Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions ui/desktop/src/agent/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getApiUrl, getSecretKey } from '../config';
import { getApiUrl } from '../config';

interface initializeAgentProps {
model: string;
Expand All @@ -10,7 +10,7 @@ export async function initializeAgent({ model, provider }: initializeAgentProps)
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
body: JSON.stringify({
provider: provider.toLowerCase().replace(/ /g, '_'),
Expand Down
14 changes: 3 additions & 11 deletions ui/desktop/src/components/ConfigContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
removeExtension as apiRemoveExtension,
providers,
} from '../api';
import { client } from '../api/client.gen';
import type {
ConfigResponse,
UpsertConfigQuery,
Expand All @@ -18,8 +17,9 @@ import type {
ProviderDetails,
ExtensionQuery,
ExtensionConfig,
} from '../api/types.gen';
} from '../api';
import { removeShims } from './settings/extensions/utils';
import { ensureClientInitialized } from '../utils';

export type { ExtensionConfig } from '../api/types.gen';

Expand All @@ -28,15 +28,6 @@ export type FixedExtensionEntry = ExtensionConfig & {
enabled: boolean;
};

// Initialize client configuration
client.setConfig({
baseUrl: window.appConfig.get('GOOSE_API_HOST') + ':' + window.appConfig.get('GOOSE_PORT'),
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': window.appConfig.get('secretKey'),
},
});

interface ConfigContextType {
config: ConfigResponse['config'];
providersList: ProviderDetails[];
Expand Down Expand Up @@ -184,6 +175,7 @@ export const ConfigProvider: React.FC<ConfigProviderProps> = ({ children }) => {
useEffect(() => {
// Load all configuration data and providers on mount
(async () => {
await ensureClientInitialized();
// Load config
const configResponse = await readAllConfig();
setConfig(configResponse.data?.config || {});
Expand Down
3 changes: 3 additions & 0 deletions ui/desktop/src/components/ProviderGuard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { startOpenRouterSetup } from '../utils/openRouterSetup';
import WelcomeGooseLogo from './WelcomeGooseLogo';
import { initializeSystem } from '../utils/providerUtils';
import { toastService } from '../toasts';
import { ensureClientInitialized } from '../utils';

interface ProviderGuardProps {
children: React.ReactNode;
Expand Down Expand Up @@ -95,6 +96,8 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
useEffect(() => {
const checkProvider = async () => {
try {
await ensureClientInitialized();

const config = window.electron.getConfig();
console.log('ProviderGuard - Full config:', config);

Expand Down
4 changes: 2 additions & 2 deletions ui/desktop/src/components/common/ActivityHeatmap.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/Tooltip';
import { getApiUrl, getSecretKey } from '../../config';
import { getApiUrl } from '../../config';

interface ActivityHeatmapCell {
week: number;
Expand Down Expand Up @@ -40,7 +40,7 @@ export function ActivityHeatmap() {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
});

Expand Down
4 changes: 2 additions & 2 deletions ui/desktop/src/components/sessions/SessionsInsights.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { Card, CardContent, CardDescription } from '../ui/card';
// import { Folder } from 'lucide-react';
import { getApiUrl, getSecretKey } from '../../config';
import { getApiUrl } from '../../config';
import { Greeting } from '../common/Greeting';
import { fetchSessions, fetchSessionDetails, type Session } from '../../sessions';
// import { fetchProjects, type ProjectMetadata } from '../../projects';
Expand Down Expand Up @@ -36,7 +36,7 @@ export function SessionInsights() {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
});

Expand Down
6 changes: 3 additions & 3 deletions ui/desktop/src/components/settings/app/AppSettingsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Settings, RefreshCw, ExternalLink } from 'lucide-react';
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '../../ui/dialog';
import UpdateSection from './UpdateSection';
import { COST_TRACKING_ENABLED, UPDATES_ENABLED } from '../../../updates';
import { getApiUrl, getSecretKey } from '../../../config';
import { getApiUrl } from '../../../config';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../ui/card';
import ThemeSelector from '../../GooseSidebar/ThemeSelector';
import BlockLogoBlack from './icons/block-lockup_black.png';
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
const checkPricingStatus = async () => {
try {
const apiUrl = getApiUrl('/config/pricing');
const secretKey = getSecretKey();
const secretKey = await window.electron.getSecretKey();

const headers: HeadersInit = { 'Content-Type': 'application/json' };
if (secretKey) {
Expand Down Expand Up @@ -100,7 +100,7 @@ export default function AppSettingsSection({ scrollToSection }: AppSettingsSecti
setIsRefreshing(true);
try {
const apiUrl = getApiUrl('/config/pricing');
const secretKey = getSecretKey();
const secretKey = await window.electron.getSecretKey();

const headers: HeadersInit = { 'Content-Type': 'application/json' };
if (secretKey) {
Expand Down
4 changes: 2 additions & 2 deletions ui/desktop/src/components/settings/extensions/agent-api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ExtensionConfig } from '../../../api/types.gen';
import { getApiUrl, getSecretKey } from '../../../config';
import { getApiUrl } from '../../../config';
import { toastService, ToastServiceOptions } from '../../../toasts';
import { replaceWithShims } from './utils';

Expand Down Expand Up @@ -46,7 +46,7 @@ export async function extensionApiCall(
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
body: JSON.stringify(payload),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState, useCallback } from 'react';
import { useConfig } from '../../ConfigContext';
import { getApiUrl, getSecretKey } from '../../../config';
import { getApiUrl } from '../../../config';

interface ToolSelectionStrategy {
key: string;
Expand Down Expand Up @@ -56,7 +56,7 @@ export const ToolSelectionStrategySection = () => {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
});

Expand Down
4 changes: 0 additions & 4 deletions ui/desktop/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,3 @@ export const getApiUrl = (endpoint: string): string => {
const cleanEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
return `${baseUrl}${cleanEndpoint}`;
};

export const getSecretKey = (): string => {
return String(window.appConfig.get('secretKey') || '');
};
6 changes: 3 additions & 3 deletions ui/desktop/src/extensions.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getApiUrl, getSecretKey } from './config';
import { getApiUrl } from './config';
import { toast } from 'react-toastify';
import { safeJsonParse } from './utils/jsonUtils';

Expand Down Expand Up @@ -100,7 +100,7 @@ export async function addExtension(
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
body: JSON.stringify(config),
});
Expand Down Expand Up @@ -177,7 +177,7 @@ export async function removeExtension(name: string, silent: boolean = false): Pr
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
},
body: JSON.stringify(sanitizeName(name)),
});
Expand Down
48 changes: 10 additions & 38 deletions ui/desktop/src/goosed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ interface GooseProcessEnv {

export const startGoosed = async (
app: App,
serverSecret: string,
dir: string | null = null,
env: Partial<GooseProcessEnv> = {}
): Promise<[number, string, ChildProcess]> => {
Expand Down Expand Up @@ -182,7 +183,7 @@ export const startGoosed = async (
PATH: `${path.dirname(resolvedGoosedPath)}${path.delimiter}${process.env.PATH || ''}`,
// start with the port specified
GOOSE_PORT: String(port),
GOOSE_SERVER__SECRET_KEY: process.env.GOOSE_SERVER__SECRET_KEY,
GOOSE_SERVER__SECRET_KEY: serverSecret,
// Add any additional environment variables passed in
...env,
} as GooseProcessEnv;
Expand All @@ -208,20 +209,6 @@ export const startGoosed = async (
}
log.info(`Binary path resolved to: ${goosedPath}`);

// Verify binary exists and is a regular file
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
const stats = fs.statSync(goosedPath);
if (!stats.isFile()) {
throw new Error(`Path is not a regular file: ${goosedPath}`);
}
log.info(`Binary exists and is a regular file: ${stats.isFile()}`);
} catch (error) {
log.error(`Binary not found or invalid at ${goosedPath}:`, error);
throw new Error(`Binary not found or invalid at ${goosedPath}`);
}

const spawnOptions = {
cwd: dir,
env: processEnv,
Expand Down Expand Up @@ -282,46 +269,31 @@ export const startGoosed = async (
// Wait for the server to be ready
const isReady = await checkServerStatus(port);
log.info(`Goosed isReady ${isReady}`);
if (!isReady) {
log.error(`Goosed server failed to start on port ${port}`);

const try_kill_goose = () => {
try {
if (isWindows) {
// On Windows, use taskkill to forcefully terminate the process tree
// Security: Validate PID is numeric and use safe arguments
const pid = goosedProcess.pid?.toString() || '0';
if (!/^\d+$/.test(pid)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this be needed on windows?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah - centralising it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, it strikes me that either we can kill the thing or we can't. why would we try to guess what a pid looks like if we got it from the os and pass it to the os?

throw new Error(`Invalid PID: ${pid}`);
}
spawn('taskkill', ['/pid', pid, '/T', '/F'], { shell: false });
} else {
goosedProcess.kill?.();
}
} catch (error) {
log.error('Error while terminating goosed process:', error);
}
};

if (!isReady) {
log.error(`Goosed server failed to start on port ${port}`);
try_kill_goose();
throw new Error(`Goosed server failed to start on port ${port}`);
}

// Ensure goosed is terminated when the app quits
// TODO will need to do it at tab level next
app.on('will-quit', () => {
log.info('App quitting, terminating goosed server');
try {
if (isWindows) {
// On Windows, use taskkill to forcefully terminate the process tree
// Security: Validate PID is numeric and use safe arguments
const pid = goosedProcess.pid?.toString() || '0';
if (!/^\d+$/.test(pid)) {
log.error(`Invalid PID for termination: ${pid}`);
return;
}
spawn('taskkill', ['/pid', pid, '/T', '/F'], { shell: false });
} else {
goosedProcess.kill?.();
}
} catch (error) {
log.error('Error while terminating goosed process:', error);
}
try_kill_goose();
});

log.info(`Goosed server successfully started on port ${port}`);
Expand Down
11 changes: 4 additions & 7 deletions ui/desktop/src/hooks/useMessageStream.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useCallback, useEffect, useRef, useId, useReducer } from 'react';
import { useCallback, useEffect, useId, useReducer, useRef, useState } from 'react';
import useSWR from 'swr';
import { getSecretKey } from '../config';
import { Message, createUserMessage, hasCompletedToolCalls } from '../types/message';
import { createUserMessage, hasCompletedToolCalls, Message } from '../types/message';
import { getSessionHistory } from '../api';
import { ChatState } from '../types/chatState';

Expand Down Expand Up @@ -382,9 +381,7 @@ export function useMessageStream({
break; // Don't throw error, just add the message
}

// For non-token-limit errors, still throw the error
const error = new Error(parsedEvent.error);
throw error;
throw new Error(parsedEvent.error);
}

case 'Finish': {
Expand Down Expand Up @@ -478,7 +475,7 @@ export function useMessageStream({
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
...extraMetadataRef.current.headers,
},
body: JSON.stringify({
Expand Down
4 changes: 2 additions & 2 deletions ui/desktop/src/hooks/useWhisper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useRef, useCallback, useEffect } from 'react';
import { useConfig } from '../components/ConfigContext';
import { getApiUrl, getSecretKey } from '../config';
import { getApiUrl } from '../config';
import { useDictationSettings } from './useDictationSettings';
import { safeJsonParse } from '../utils/jsonUtils';

Expand Down Expand Up @@ -117,7 +117,7 @@ export const useWhisper = ({ onTranscription, onError, onSizeWarning }: UseWhisp
let endpoint = '';
let headers: Record<string, string> = {
'Content-Type': 'application/json',
'X-Secret-Key': getSecretKey(),
'X-Secret-Key': await window.electron.getSecretKey(),
};
let body: Record<string, string> = {
audio: base64Audio,
Expand Down
Loading
Loading