mirror of
https://github.com/aljazceru/goose.git
synced 2026-01-02 14:04:27 +01:00
chore: Initial pass at cleanup of initializeAgent (#1888)
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
"license": {
|
||||
"name": "Apache-2.0"
|
||||
},
|
||||
"version": "1.0.15"
|
||||
"version": "1.0.16"
|
||||
},
|
||||
"paths": {
|
||||
"/config": {
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
import { useConfig, FixedExtensionEntry } from '../components/ConfigContext';
|
||||
import { getApiUrl, getSecretKey } from '../config';
|
||||
import { ExtensionConfig } from '../api';
|
||||
import { toast } from 'react-toastify';
|
||||
import React, { useState } from 'react';
|
||||
import { initializeAgent as startAgent, replaceWithShims } from './utils';
|
||||
import { toastError, toastInfo, toastLoading, toastSuccess } from '../toasts';
|
||||
|
||||
// extensionUpdate = an extension was newly added or updated so we should attempt to add it
|
||||
|
||||
export const useAgent = () => {
|
||||
const { getExtensions, read } = useConfig();
|
||||
const [isUpdating, setIsUpdating] = useState(false);
|
||||
|
||||
// whenever we change the model, we must call this
|
||||
const initializeAgent = async (provider: string, model: string) => {
|
||||
try {
|
||||
console.log('Initializing agent with provider', provider, 'model', model);
|
||||
|
||||
const response = await startAgent(model, provider);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to initialize agent: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize agent:', error);
|
||||
toastError({
|
||||
title: 'Failed to initialize agent',
|
||||
traceback: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const updateAgent = async (extensionUpdate?: ExtensionConfig) => {
|
||||
setIsUpdating(true);
|
||||
|
||||
try {
|
||||
// need to initialize agent first (i dont get why but if we dont do this, we get a 428)
|
||||
// note: we must write the value for GOOSE_MODEL and GOOSE_PROVIDER in the config before updating agent
|
||||
const goose_model = (await read('GOOSE_MODEL', false)) as string;
|
||||
const goose_provider = (await read('GOOSE_PROVIDER', false)) as string;
|
||||
|
||||
console.log(
|
||||
`Starting agent with GOOSE_MODEL=${goose_model} and GOOSE_PROVIDER=${goose_provider}`
|
||||
);
|
||||
|
||||
// Initialize the agent if it's a model change
|
||||
if (goose_model && goose_provider) {
|
||||
const success = await initializeAgent(goose_provider, goose_model);
|
||||
if (!success) {
|
||||
console.error('Failed to initialize agent during model change');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (extensionUpdate) {
|
||||
await addExtensionToAgent(extensionUpdate);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error updating agent:', error);
|
||||
return false;
|
||||
} finally {
|
||||
setIsUpdating(false);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: set 'enabled' to false if we fail to start / add the extension
|
||||
// only for non-builtins
|
||||
|
||||
// TODO: try to add some descriptive error messages for common failure modes
|
||||
const addExtensionToAgent = async (
|
||||
extension: ExtensionConfig,
|
||||
silent: boolean = false
|
||||
): Promise<Response> => {
|
||||
if (extension.type == 'stdio') {
|
||||
console.log('extension command', extension.cmd);
|
||||
extension.cmd = await replaceWithShims(extension.cmd);
|
||||
console.log('next ext command', extension.cmd);
|
||||
}
|
||||
|
||||
try {
|
||||
let toastId;
|
||||
if (!silent) {
|
||||
toastId = toastLoading({
|
||||
title: extension.name,
|
||||
msg: 'Adding extension...',
|
||||
toastOptions: { position: 'top-center' },
|
||||
});
|
||||
toastInfo({
|
||||
msg: 'Press the escape key to continue using goose while extension loads',
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch(getApiUrl('/extensions/add'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': getSecretKey(),
|
||||
},
|
||||
body: JSON.stringify(extension),
|
||||
});
|
||||
|
||||
// Handle non-OK responses
|
||||
if (!response.ok) {
|
||||
const errorMsg = `Server returned ${response.status}: ${response.statusText}`;
|
||||
console.error(errorMsg);
|
||||
|
||||
// Special handling for 428 Precondition Required (agent not initialized)
|
||||
if (response.status === 428) {
|
||||
if (!silent) {
|
||||
if (toastId) toast.dismiss(toastId);
|
||||
toastError({
|
||||
msg: 'Agent is not initialized. Please initialize the agent first.',
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
if (!silent) {
|
||||
if (toastId) toast.dismiss(toastId);
|
||||
toastError({
|
||||
title: extension.name,
|
||||
msg: 'Failed to add extension',
|
||||
traceback: errorMsg,
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// Parse response JSON safely
|
||||
let data;
|
||||
try {
|
||||
const text = await response.text();
|
||||
data = text ? JSON.parse(text) : { error: false };
|
||||
} catch (error) {
|
||||
console.warn('Could not parse response as JSON, assuming success', error);
|
||||
data = { error: false };
|
||||
}
|
||||
|
||||
console.log('Response data:', data);
|
||||
|
||||
if (!data.error) {
|
||||
if (!silent) {
|
||||
if (toastId) toast.dismiss(toastId);
|
||||
toastSuccess({
|
||||
title: extension.name,
|
||||
msg: 'Successfully added extension',
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
console.log('Error trying to send a request to the extensions endpoint');
|
||||
const errorMessage = `Error adding ${extension.name} extension${data.message ? `. ${data.message}` : ''}`;
|
||||
console.error(errorMessage);
|
||||
if (toastId) toast.dismiss(toastId);
|
||||
toastError({
|
||||
title: extension.name,
|
||||
msg: 'Failed to add extension',
|
||||
traceback: data.message,
|
||||
});
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.log('Got some other error');
|
||||
const errorMessage = `Failed to add ${extension.name} extension: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
||||
console.error(errorMessage);
|
||||
toastError({
|
||||
title: extension.name,
|
||||
msg: 'Failed to add extension',
|
||||
traceback: error.message,
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
updateAgent,
|
||||
addExtensionToAgent,
|
||||
initializeAgent,
|
||||
isUpdating,
|
||||
};
|
||||
};
|
||||
@@ -15,19 +15,3 @@ export async function initializeAgent(model: string, provider: string) {
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
export async function replaceWithShims(cmd: string) {
|
||||
const binaryPathMap: Record<string, string> = {
|
||||
goosed: await window.electron.getBinaryPath('goosed'),
|
||||
jbang: await window.electron.getBinaryPath('jbang'),
|
||||
npx: await window.electron.getBinaryPath('npx'),
|
||||
uvx: await window.electron.getBinaryPath('uvx'),
|
||||
};
|
||||
|
||||
if (binaryPathMap[cmd]) {
|
||||
console.log('--------> Replacing command with shim ------>', cmd, binaryPathMap[cmd]);
|
||||
cmd = binaryPathMap[cmd];
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ExtensionConfig } from '../../../api/types.gen';
|
||||
import { getApiUrl, getSecretKey } from '../../../config';
|
||||
import { toastService, ToastServiceOptions } from '../../../toasts';
|
||||
import { replaceWithShims } from './utils';
|
||||
|
||||
/**
|
||||
* Makes an API call to the extension endpoints
|
||||
@@ -166,19 +167,3 @@ export async function removeFromAgent(
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the path to the binary based on the command
|
||||
async function replaceWithShims(cmd: string): Promise<string> {
|
||||
const binaryPathMap: Record<string, string> = {
|
||||
goosed: await window.electron.getBinaryPath('goosed'),
|
||||
npx: await window.electron.getBinaryPath('npx'),
|
||||
uvx: await window.electron.getBinaryPath('uvx'),
|
||||
};
|
||||
|
||||
if (binaryPathMap[cmd]) {
|
||||
console.log('--------> Replacing command with shim ------>', cmd, binaryPathMap[cmd]);
|
||||
return binaryPathMap[cmd];
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -127,3 +127,19 @@ export function extractExtensionConfig(fixedEntry: FixedExtensionEntry): Extensi
|
||||
const { enabled, ...extensionConfig } = fixedEntry;
|
||||
return extensionConfig;
|
||||
}
|
||||
|
||||
export async function replaceWithShims(cmd: string) {
|
||||
const binaryPathMap: Record<string, string> = {
|
||||
goosed: await window.electron.getBinaryPath('goosed'),
|
||||
jbang: await window.electron.getBinaryPath('jbang'),
|
||||
npx: await window.electron.getBinaryPath('npx'),
|
||||
uvx: await window.electron.getBinaryPath('uvx'),
|
||||
};
|
||||
|
||||
if (binaryPathMap[cmd]) {
|
||||
console.log('--------> Replacing command with shim ------>', cmd, binaryPathMap[cmd]);
|
||||
cmd = binaryPathMap[cmd];
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import BackButton from '../../ui/BackButton';
|
||||
import ProviderGrid from './ProviderGrid';
|
||||
import { useConfig } from '../../ConfigContext';
|
||||
import { ProviderDetails } from '../../../api/types.gen';
|
||||
import { useAgent } from '../../../agent/UpdateAgent';
|
||||
import { initializeAgent } from '../../../agent/';
|
||||
import WelcomeGooseLogo from '../../WelcomeGooseLogo';
|
||||
|
||||
interface ProviderSettingsProps {
|
||||
@@ -14,7 +14,6 @@ interface ProviderSettingsProps {
|
||||
|
||||
export default function ProviderSettings({ onClose, isOnboarding }: ProviderSettingsProps) {
|
||||
const { getProviders, upsert } = useConfig();
|
||||
const { initializeAgent } = useAgent();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [providers, setProviders] = useState<ProviderDetails[]>([]);
|
||||
const initialLoadDone = useRef(false);
|
||||
@@ -70,7 +69,7 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett
|
||||
);
|
||||
|
||||
// initialize agent
|
||||
await initializeAgent(provider_name, model);
|
||||
await initializeAgent({ provider: provider.name, model });
|
||||
} catch (error) {
|
||||
console.error(`Failed to initialize with provider ${provider_name}:`, error);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { loadAndAddStoredExtensions } from '../extensions';
|
||||
import { GOOSE_PROVIDER, GOOSE_MODEL } from '../env_vars';
|
||||
import { Model } from '../components/settings/models/ModelContext';
|
||||
import { gooseModels } from '../components/settings/models/GooseModels';
|
||||
import { initializeAgent } from '../agent';
|
||||
|
||||
export function getStoredProvider(config: any): string | null {
|
||||
return config.GOOSE_PROVIDER || localStorage.getItem(GOOSE_PROVIDER);
|
||||
@@ -32,23 +33,6 @@ export interface Provider {
|
||||
requiredKeys: string[]; // List of required keys
|
||||
}
|
||||
|
||||
const addAgent = async (provider: string, model: string) => {
|
||||
const response = await fetch(getApiUrl('/agent'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Secret-Key': getSecretKey(),
|
||||
},
|
||||
body: JSON.stringify({ provider: provider, model: model }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to add agent: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
// Desktop-specific system prompt extension
|
||||
const desktopPrompt = `You are being accessed through the Goose Desktop application.
|
||||
|
||||
@@ -84,7 +68,7 @@ There may be (but not always) some tools mentioned in the instructions which you
|
||||
export const initializeSystem = async (provider: string, model: string) => {
|
||||
try {
|
||||
console.log('initializing agent with provider', provider, 'model', model);
|
||||
await addAgent(provider.toLowerCase().replace(/ /g, '_'), model);
|
||||
await initializeAgent({ provider, model });
|
||||
|
||||
// Sync the model state with React
|
||||
const syncedModel = syncModelWithAgent(provider, model);
|
||||
@@ -119,7 +103,7 @@ export const initializeSystem = async (provider: string, model: string) => {
|
||||
|
||||
// This will go away after the release of settings v2 as we now handle this via
|
||||
//
|
||||
// initializeBuildInExtensions
|
||||
// initializeBuiltInExtensions
|
||||
// syncBuiltInExtensions
|
||||
if (!process.env.ALPHA) {
|
||||
loadAndAddStoredExtensions().catch((error) => {
|
||||
|
||||
Reference in New Issue
Block a user