Skip to content

Commit

Permalink
fix: settings bugfix error building my application issue #1414 (#1436)
Browse files Browse the repository at this point in the history
* Fix: error building my application #1414

* fix for vite

* Update vite.config.ts

* Update root.tsx

* fix the root.tsx and the debugtab

* lm studio fix and fix for the api key

* Update api.enhancer for prompt enhancement

* bugfixes

* Revert api.enhancer.ts back to original code

* Update api.enhancer.ts

* Update api.git-proxy.$.ts

* Update api.git-proxy.$.ts

* Update api.enhancer.ts
  • Loading branch information
Stijnus authored and thecodacus committed Mar 10, 2025
1 parent 7045646 commit 332edd3
Show file tree
Hide file tree
Showing 18 changed files with 371 additions and 801 deletions.
25 changes: 21 additions & 4 deletions app/components/@settings/tabs/connections/ConnectionsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { motion } from 'framer-motion';
import { GithubConnection } from './GithubConnection';
import { NetlifyConnection } from './NetlifyConnection';
import React, { Suspense } from 'react';

// Use React.lazy for dynamic imports
const GithubConnection = React.lazy(() => import('./GithubConnection'));
const NetlifyConnection = React.lazy(() => import('./NetlifyConnection'));

// Loading fallback component
const LoadingFallback = () => (
<div className="p-4 bg-white dark:bg-[#0A0A0A] rounded-lg border border-[#E5E5E5] dark:border-[#1A1A1A]">
<div className="flex items-center gap-2 text-bolt-elements-textSecondary">
<div className="i-ph:spinner-gap w-5 h-5 animate-spin" />
<span>Loading connection...</span>
</div>
</div>
);

export default function ConnectionsTab() {
return (
Expand All @@ -20,8 +33,12 @@ export default function ConnectionsTab() {
</p>

<div className="grid grid-cols-1 gap-4">
<GithubConnection />
<NetlifyConnection />
<Suspense fallback={<LoadingFallback />}>
<GithubConnection />
</Suspense>
<Suspense fallback={<LoadingFallback />}>
<NetlifyConnection />
</Suspense>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ interface GitHubConnection {
stats?: GitHubStats;
}

export function GithubConnection() {
export default function GithubConnection() {
const [connection, setConnection] = useState<GitHubConnection>({
user: null,
token: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from '~/lib/stores/netlify';
import type { NetlifyUser } from '~/types/netlify';

export function NetlifyConnection() {
export default function NetlifyConnection() {
const connection = useStore(netlifyConnection);
const connecting = useStore(isConnecting);
const fetchingStats = useStore(isFetchingStats);
Expand Down
2 changes: 1 addition & 1 deletion app/lib/hooks/useShortcuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function useShortcuts(): void {
}

// Debug logging in development only
if (process.env.NODE_ENV === 'development') {
if (import.meta.env.DEV) {
console.log('Key pressed:', {
key: event.key,
code: event.code,
Expand Down
2 changes: 1 addition & 1 deletion app/lib/modules/llm/providers/lmstudio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default class LMStudioProvider extends BaseProvider {
throw new Error('No baseUrl found for LMStudio provider');
}

const isDocker = process.env.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true';
const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true';

if (typeof window === 'undefined') {
baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl;
Expand Down
31 changes: 26 additions & 5 deletions app/lib/modules/llm/providers/ollama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ export interface OllamaApiResponse {
models: OllamaModel[];
}

export const DEFAULT_NUM_CTX = process?.env?.DEFAULT_NUM_CTX ? parseInt(process.env.DEFAULT_NUM_CTX, 10) : 32768;

export default class OllamaProvider extends BaseProvider {
name = 'Ollama';
getApiKeyLink = 'https://ollama.com/download';
Expand All @@ -41,6 +39,26 @@ export default class OllamaProvider extends BaseProvider {

staticModels: ModelInfo[] = [];

private _convertEnvToRecord(env?: Env): Record<string, string> {
if (!env) {
return {};
}

// Convert Env to a plain object with string values
return Object.entries(env).reduce(
(acc, [key, value]) => {
acc[key] = String(value);
return acc;
},
{} as Record<string, string>,
);
}

getDefaultNumCtx(serverEnv?: Env): number {
const envRecord = this._convertEnvToRecord(serverEnv);
return envRecord.DEFAULT_NUM_CTX ? parseInt(envRecord.DEFAULT_NUM_CTX, 10) : 32768;
}

async getDynamicModels(
apiKeys?: Record<string, string>,
settings?: IProviderSetting,
Expand Down Expand Up @@ -81,17 +99,20 @@ export default class OllamaProvider extends BaseProvider {
maxTokenAllowed: 8000,
}));
}

getModelInstance: (options: {
model: string;
serverEnv?: Env;
apiKeys?: Record<string, string>;
providerSettings?: Record<string, IProviderSetting>;
}) => LanguageModelV1 = (options) => {
const { apiKeys, providerSettings, serverEnv, model } = options;
const envRecord = this._convertEnvToRecord(serverEnv);

let { baseUrl } = this.getProviderBaseUrlAndKey({
apiKeys,
providerSettings: providerSettings?.[this.name],
serverEnv: serverEnv as any,
serverEnv: envRecord,
defaultBaseUrlKey: 'OLLAMA_API_BASE_URL',
defaultApiTokenKey: '',
});
Expand All @@ -101,14 +122,14 @@ export default class OllamaProvider extends BaseProvider {
throw new Error('No baseUrl found for OLLAMA provider');
}

const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || serverEnv?.RUNNING_IN_DOCKER === 'true';
const isDocker = process?.env?.RUNNING_IN_DOCKER === 'true' || envRecord.RUNNING_IN_DOCKER === 'true';
baseUrl = isDocker ? baseUrl.replace('localhost', 'host.docker.internal') : baseUrl;
baseUrl = isDocker ? baseUrl.replace('127.0.0.1', 'host.docker.internal') : baseUrl;

logger.debug('Ollama Base Url used: ', baseUrl);

const ollamaInstance = ollama(model, {
numCtx: DEFAULT_NUM_CTX,
numCtx: this.getDefaultNumCtx(serverEnv),
}) as LanguageModelV1 & { config: any };

ollamaInstance.config.baseURL = `${baseUrl}/api`;
Expand Down
7 changes: 4 additions & 3 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { createHead } from 'remix-island';
import { useEffect } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { ClientOnly } from 'remix-utils/client-only';

import reactToastifyStyles from 'react-toastify/dist/ReactToastify.css?url';
import globalStyles from './styles/index.scss?url';
Expand Down Expand Up @@ -72,11 +73,11 @@ export function Layout({ children }: { children: React.ReactNode }) {
}, [theme]);

return (
<DndProvider backend={HTML5Backend}>
{children}
<>
<ClientOnly>{() => <DndProvider backend={HTML5Backend}>{children}</DndProvider>}</ClientOnly>
<ScrollRestoration />
<Scripts />
</DndProvider>
</>
);
}

Expand Down
33 changes: 29 additions & 4 deletions app/routes/api.check-env-key.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
import type { LoaderFunction } from '@remix-run/cloudflare';
import { providerBaseUrlEnvKeys } from '~/utils/constants';
import { LLMManager } from '~/lib/modules/llm/manager';
import { getApiKeysFromCookie } from '~/lib/api/cookies';

export const loader: LoaderFunction = async ({ context, request }) => {
const url = new URL(request.url);
const provider = url.searchParams.get('provider');

if (!provider || !providerBaseUrlEnvKeys[provider].apiTokenKey) {
if (!provider) {
return Response.json({ isSet: false });
}

const envVarName = providerBaseUrlEnvKeys[provider].apiTokenKey;
const isSet = !!(process.env[envVarName] || (context?.cloudflare?.env as Record<string, any>)?.[envVarName]);
const llmManager = LLMManager.getInstance(context?.cloudflare?.env as any);
const providerInstance = llmManager.getProvider(provider);

if (!providerInstance || !providerInstance.config.apiTokenKey) {
return Response.json({ isSet: false });
}

const envVarName = providerInstance.config.apiTokenKey;

// Get API keys from cookie
const cookieHeader = request.headers.get('Cookie');
const apiKeys = getApiKeysFromCookie(cookieHeader);

/*
* Check API key in order of precedence:
* 1. Client-side API keys (from cookies)
* 2. Server environment variables (from Cloudflare env)
* 3. Process environment variables (from .env.local)
* 4. LLMManager environment variables
*/
const isSet = !!(
apiKeys?.[provider] ||
(context?.cloudflare?.env as Record<string, any>)?.[envVarName] ||
process.env[envVarName] ||
llmManager.env[envVarName]
);

return Response.json({ isSet });
};
12 changes: 10 additions & 2 deletions app/routes/api.deploy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { type ActionFunctionArgs, json } from '@remix-run/cloudflare';
import crypto from 'crypto';
import type { NetlifySiteInfo } from '~/types/netlify';

interface DeployRequestBody {
Expand All @@ -8,6 +7,15 @@ interface DeployRequestBody {
chatId: string;
}

async function sha1(message: string) {
const msgBuffer = new TextEncoder().encode(message);
const hashBuffer = await crypto.subtle.digest('SHA-1', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');

return hashHex;
}

export async function action({ request }: ActionFunctionArgs) {
try {
const { siteId, files, token, chatId } = (await request.json()) as DeployRequestBody & { token: string };
Expand Down Expand Up @@ -104,7 +112,7 @@ export async function action({ request }: ActionFunctionArgs) {
for (const [filePath, content] of Object.entries(files)) {
// Ensure file path starts with a forward slash
const normalizedPath = filePath.startsWith('/') ? filePath : '/' + filePath;
const hash = crypto.createHash('sha1').update(content).digest('hex');
const hash = await sha1(content);
fileDigests[normalizedPath] = hash;
}

Expand Down
18 changes: 11 additions & 7 deletions app/routes/api.enhancer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,28 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
},
});

// Handle streaming errors in a non-blocking way
(async () => {
for await (const part of result.fullStream) {
if (part.type === 'error') {
const error: any = part.error;
logger.error(error);

return;
try {
for await (const part of result.fullStream) {
if (part.type === 'error') {
const error: any = part.error;
logger.error('Streaming error:', error);
break;
}
}
} catch (error) {
logger.error('Error processing stream:', error);
}
})();

// Return the text stream directly since it's already text data
return new Response(result.textStream, {
status: 200,
headers: {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
'Text-Encoding': 'chunked',
},
});
} catch (error: unknown) {
Expand Down
Loading

0 comments on commit 332edd3

Please sign in to comment.