Better search paths and handling of CLI providers (#5554)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Jack Amadeo
2025-11-07 19:35:26 -08:00
committed by GitHub
parent 65b4b2bb18
commit 25dfd768e5
27 changed files with 721 additions and 538 deletions
+64
View File
@@ -382,6 +382,25 @@
}
}
},
"/config/check_provider": {
"post": {
"tags": [
"super::routes::config_management"
],
"operationId": "check_provider",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CheckProviderRequest"
}
}
},
"required": true
},
"responses": {}
}
},
"/config/custom-providers": {
"post": {
"tags": [
@@ -840,6 +859,25 @@
}
}
},
"/config/set_provider": {
"post": {
"tags": [
"super::routes::config_management"
],
"operationId": "set_config_provider",
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SetProviderRequest"
}
}
},
"required": true
},
"responses": {}
}
},
"/config/upsert": {
"post": {
"tags": [
@@ -2152,6 +2190,17 @@
}
}
},
"CheckProviderRequest": {
"type": "object",
"required": [
"provider"
],
"properties": {
"provider": {
"type": "string"
}
}
},
"ConfigKey": {
"type": "object",
"description": "Configuration key metadata for provider setup",
@@ -4359,6 +4408,21 @@
}
}
},
"SetProviderRequest": {
"type": "object",
"required": [
"provider",
"model"
],
"properties": {
"model": {
"type": "string"
},
"provider": {
"type": "string"
}
}
},
"Settings": {
"type": "object",
"properties": {
+23 -1
View File
@@ -2,7 +2,7 @@
import type { Client, Options as Options2, TDataShape } from './client';
import { client } from './client.gen';
import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, ConfirmPermissionData, ConfirmPermissionErrors, ConfirmPermissionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetToolsData, GetToolsErrors, GetToolsResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StatusData, StatusResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateRouterToolSelectorData, UpdateRouterToolSelectorErrors, UpdateRouterToolSelectorResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen';
import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, CheckProviderData, ConfirmPermissionData, ConfirmPermissionErrors, ConfirmPermissionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetToolsData, GetToolsErrors, GetToolsResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, SetConfigProviderData, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StatusData, StatusResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateRouterToolSelectorData, UpdateRouterToolSelectorErrors, UpdateRouterToolSelectorResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen';
export type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = Options2<TData, ThrowOnError> & {
/**
@@ -116,6 +116,17 @@ export const backupConfig = <ThrowOnError extends boolean = false>(options?: Opt
});
};
export const checkProvider = <ThrowOnError extends boolean = false>(options: Options<CheckProviderData, ThrowOnError>) => {
return (options.client ?? client).post<unknown, unknown, ThrowOnError>({
url: '/config/check_provider',
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
};
export const createCustomProvider = <ThrowOnError extends boolean = false>(options: Options<CreateCustomProviderData, ThrowOnError>) => {
return (options.client ?? client).post<CreateCustomProviderResponses, CreateCustomProviderErrors, ThrowOnError>({
url: '/config/custom-providers',
@@ -238,6 +249,17 @@ export const removeConfig = <ThrowOnError extends boolean = false>(options: Opti
});
};
export const setConfigProvider = <ThrowOnError extends boolean = false>(options: Options<SetConfigProviderData, ThrowOnError>) => {
return (options.client ?? client).post<unknown, unknown, ThrowOnError>({
url: '/config/set_provider',
...options,
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
};
export const upsertConfig = <ThrowOnError extends boolean = false>(options: Options<UpsertConfigData, ThrowOnError>) => {
return (options.client ?? client).post<UpsertConfigResponses, UpsertConfigErrors, ThrowOnError>({
url: '/config/upsert',
+23
View File
@@ -32,6 +32,10 @@ export type ChatRequest = {
session_id: string;
};
export type CheckProviderRequest = {
provider: string;
};
/**
* Configuration key metadata for provider setup
*/
@@ -731,6 +735,11 @@ export type SessionsQuery = {
limit?: number;
};
export type SetProviderRequest = {
model: string;
provider: string;
};
export type Settings = {
goose_model?: string | null;
goose_provider?: string | null;
@@ -1212,6 +1221,13 @@ export type BackupConfigResponses = {
export type BackupConfigResponse = BackupConfigResponses[keyof BackupConfigResponses];
export type CheckProviderData = {
body: CheckProviderRequest;
path?: never;
query?: never;
url: '/config/check_provider';
};
export type CreateCustomProviderData = {
body: UpdateCustomProviderRequest;
path?: never;
@@ -1578,6 +1594,13 @@ export type RemoveConfigResponses = {
export type RemoveConfigResponse = RemoveConfigResponses[keyof RemoveConfigResponses];
export type SetConfigProviderData = {
body: SetProviderRequest;
path?: never;
query?: never;
url: '/config/set_provider';
};
export type UpsertConfigData = {
body: UpsertConfigQuery;
path?: never;
+1 -1
View File
@@ -34,7 +34,7 @@ export function ErrorUI({ error }: { error: Error }) {
</p>
)}
<pre className="text-destructive text-sm dark:text-white p-4 bg-muted rounded-lg w-full overflow-auto border border-border">
<pre className="text-destructive text-sm dark:text-white p-4 bg-muted rounded-lg w-full overflow-auto border border-border whitespace-pre-wrap">
{error.message}
</pre>
@@ -1,7 +1,7 @@
import React, { createContext, useContext, useState, useEffect, useMemo, useCallback } from 'react';
import { toastError, toastSuccess } from '../toasts';
import Model, { getProviderMetadata } from './settings/models/modelInterface';
import { ProviderMetadata, updateAgentProvider } from '../api';
import { ProviderMetadata, setConfigProvider, updateAgentProvider } from '../api';
import { useConfig } from './ConfigContext';
import {
getModelDisplayName,
@@ -12,10 +12,6 @@ import {
export const UNKNOWN_PROVIDER_TITLE = 'Provider name lookup';
// errors
const CHANGE_MODEL_ERROR_TITLE = 'Change failed';
const SWITCH_MODEL_AGENT_ERROR_MSG =
'Failed to start agent with selected model -- please try again';
const CONFIG_UPDATE_ERROR_MSG = 'Failed to update configuration settings -- please try again';
export const UNKNOWN_PROVIDER_MSG = 'Unknown provider in config -- please inspect your config.yaml';
// success
@@ -43,61 +39,68 @@ const ModelAndProviderContext = createContext<ModelAndProviderContextType | unde
export const ModelAndProviderProvider: React.FC<ModelAndProviderProviderProps> = ({ children }) => {
const [currentModel, setCurrentModel] = useState<string | null>(null);
const [currentProvider, setCurrentProvider] = useState<string | null>(null);
const { read, upsert, getProviders } = useConfig();
const { read, getProviders } = useConfig();
const changeModel = useCallback(
async (sessionId: string | null, model: Model) => {
const modelName = model.name;
const providerName = model.provider;
let phase = 'agent';
const changeModel = useCallback(async (sessionId: string | null, model: Model) => {
const modelName = model.name;
const providerName = model.provider;
let phase = 'agent';
try {
if (sessionId) {
await updateAgentProvider({
body: {
session_id: sessionId,
provider: providerName,
model: modelName,
},
});
}
phase = 'config';
await upsert('GOOSE_PROVIDER', providerName, false);
await upsert('GOOSE_MODEL', modelName, false);
setCurrentProvider(providerName);
setCurrentModel(modelName);
toastSuccess({
title: CHANGE_MODEL_TOAST_TITLE,
msg: `${SWITCH_MODEL_SUCCESS_MSG} -- using ${model.alias ?? modelName} from ${model.subtext ?? providerName}`,
});
} catch (error) {
console.error(`Failed to change model at ${phase} step -- ${modelName} ${providerName}`);
toastError({
title: CHANGE_MODEL_ERROR_TITLE,
msg: phase === 'agent' ? SWITCH_MODEL_AGENT_ERROR_MSG : CONFIG_UPDATE_ERROR_MSG,
traceback: error instanceof Error ? error.message : String(error),
try {
if (sessionId) {
await updateAgentProvider({
body: {
session_id: sessionId,
provider: providerName,
model: modelName,
},
});
}
},
[upsert]
);
phase = 'config';
await setConfigProvider({
body: {
provider: providerName,
model: modelName,
},
throwOnError: true,
});
setCurrentProvider(providerName);
setCurrentModel(modelName);
toastSuccess({
title: CHANGE_MODEL_TOAST_TITLE,
msg: `${SWITCH_MODEL_SUCCESS_MSG} -- using ${model.alias ?? modelName} from ${model.subtext ?? providerName}`,
});
} catch (error) {
console.error(`Failed to change model at ${phase} step -- ${modelName} ${providerName}`);
toastError({
title: `${providerName}/${modelName} failed`,
msg: `${error}`,
traceback: error instanceof Error ? error.message : String(error),
});
}
}, []);
const getFallbackModelAndProvider = useCallback(async () => {
const provider = window.appConfig.get('GOOSE_DEFAULT_PROVIDER') as string;
const model = window.appConfig.get('GOOSE_DEFAULT_MODEL') as string;
if (provider && model) {
try {
await upsert('GOOSE_MODEL', model, false);
await upsert('GOOSE_PROVIDER', provider, false);
await setConfigProvider({
body: {
provider: provider,
model: model,
},
throwOnError: true,
});
} catch (error) {
console.error('[getFallbackModelAndProvider] Failed to write to config', error);
}
}
return { model: model, provider: provider };
}, [upsert]);
}, []);
const getCurrentModelAndProvider = useCallback(async () => {
let model: string;
@@ -3,7 +3,7 @@ import { ScrollArea } from '../../ui/scroll-area';
import BackButton from '../../ui/BackButton';
import ProviderGrid from './ProviderGrid';
import { useConfig } from '../../ConfigContext';
import { ProviderDetails } from '../../../api';
import { ProviderDetails, setConfigProvider } from '../../../api';
import { toastService } from '../../../toasts';
interface ProviderSettingsProps {
@@ -12,7 +12,7 @@ interface ProviderSettingsProps {
}
export default function ProviderSettings({ onClose, isOnboarding }: ProviderSettingsProps) {
const { getProviders, upsert } = useConfig();
const { getProviders } = useConfig();
const [loading, setLoading] = useState(true);
const [providers, setProviders] = useState<ProviderDetails[]>([]);
const initialLoadDone = useRef(false);
@@ -56,15 +56,13 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett
const model = provider.metadata.default_model;
try {
// update the config
// set GOOSE_PROVIDER in the config file
upsert('GOOSE_PROVIDER', provider_name, false).then((_) =>
console.log('Setting GOOSE_PROVIDER to', provider_name)
);
// set GOOSE_MODEL in the config file
upsert('GOOSE_MODEL', model, false).then((_) =>
console.log('Setting GOOSE_MODEL to', model)
);
await setConfigProvider({
body: {
provider: provider_name,
model,
},
throwOnError: true,
});
toastService.configure({ silent: false });
toastService.success({
@@ -85,7 +83,7 @@ export default function ProviderSettings({ onClose, isOnboarding }: ProviderSett
});
}
},
[onClose, upsert]
[onClose]
);
return (
@@ -18,6 +18,7 @@ import { useConfig } from '../../../ConfigContext';
import { useModelAndProvider } from '../../../ModelAndProviderContext';
import { AlertTriangle } from 'lucide-react';
import { ProviderDetails, removeCustomProvider } from '../../../../api';
import { Button } from '../../../../components/ui/button';
interface ProviderConfigurationModalProps {
provider: ProviderDetails;
@@ -34,6 +35,7 @@ export default function ProviderConfigurationModal({
const [configValues, setConfigValues] = useState<Record<string, ConfigInput>>({});
const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);
const [isActiveProvider, setIsActiveProvider] = useState(false);
const [error, setError] = useState<string | null>(null);
const requiredParameters = provider.metadata.config_keys.filter(
(param) => param.required === true
@@ -79,8 +81,12 @@ export default function ProviderConfigurationModal({
.map(([k, entry]) => [k, entry.value || ''])
);
await providerConfigSubmitHandler(upsert, provider, toSubmit);
onClose();
try {
await providerConfigSubmitHandler(upsert, provider, toSubmit);
onClose();
} catch (error) {
setError(`${error}`);
}
};
const handleCancel = () => {
@@ -137,54 +143,71 @@ export default function ProviderConfigurationModal({
};
return (
<Dialog open onOpenChange={(open) => !open && onClose()}>
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
{getModalIcon()}
{headerText}
</DialogTitle>
<DialogDescription>{descriptionText}</DialogDescription>
</DialogHeader>
<>
<Dialog open={!!error} onOpenChange={(open) => !open && setError(null)}>
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
<DialogTitle className="flex items-center gap-2">Error</DialogTitle>
<DialogDescription className="text-inherit text-base">
There was an error checking this provider configuration.
</DialogDescription>
<pre className="ml-2">{error}</pre>
<div>Check your configuration again to use this provider.</div>
<DialogFooter>
<Button variant="outline" onClick={() => setError(null)}>
Go Back
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog open={!error} onOpenChange={(open) => !open && onClose()}>
<DialogContent className="sm:max-w-[600px] max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
{getModalIcon()}
{headerText}
</DialogTitle>
<DialogDescription>{descriptionText}</DialogDescription>
</DialogHeader>
<div className="py-4">
{/* Contains information used to set up each provider */}
{/* Only show the form when NOT in delete confirmation mode */}
{!showDeleteConfirmation ? (
<>
{/* Contains information used to set up each provider */}
<DefaultProviderSetupForm
configValues={configValues}
setConfigValues={setConfigValues}
provider={provider}
validationErrors={validationErrors}
/>
<div className="py-4">
{/* Contains information used to set up each provider */}
{/* Only show the form when NOT in delete confirmation mode */}
{!showDeleteConfirmation ? (
<>
{/* Contains information used to set up each provider */}
<DefaultProviderSetupForm
configValues={configValues}
setConfigValues={setConfigValues}
provider={provider}
validationErrors={validationErrors}
/>
{requiredParameters.length > 0 &&
provider.metadata.config_keys &&
provider.metadata.config_keys.length > 0 && <SecureStorageNotice />}
</>
) : null}
</div>
{requiredParameters.length > 0 &&
provider.metadata.config_keys &&
provider.metadata.config_keys.length > 0 && <SecureStorageNotice />}
</>
) : null}
</div>
<DialogFooter>
<ProviderSetupActions
requiredParameters={requiredParameters}
onCancel={handleCancel}
onSubmit={handleSubmitForm}
onDelete={handleDelete}
showDeleteConfirmation={showDeleteConfirmation}
onConfirmDelete={handleConfirmDelete}
onCancelDelete={() => {
setIsActiveProvider(false);
setShowDeleteConfirmation(false);
}}
canDelete={isConfigured && !isActiveProvider}
providerName={provider.metadata.display_name}
isActiveProvider={isActiveProvider}
/>
</DialogFooter>
</DialogContent>
</Dialog>
<DialogFooter>
<ProviderSetupActions
requiredParameters={requiredParameters}
onCancel={handleCancel}
onSubmit={handleSubmitForm}
onDelete={handleDelete}
showDeleteConfirmation={showDeleteConfirmation}
onConfirmDelete={handleConfirmDelete}
onCancelDelete={() => {
setIsActiveProvider(false);
setShowDeleteConfirmation(false);
}}
canDelete={isConfigured && !isActiveProvider}
providerName={provider.metadata.display_name}
isActiveProvider={isActiveProvider}
/>
</DialogFooter>
</DialogContent>
</Dialog>
</>
);
}
@@ -1,3 +1,5 @@
import { checkProvider } from '../../../../../../api';
/**
* Standalone function to submit provider configuration
* Useful for components that don't want to use the hook
@@ -19,15 +21,6 @@ export const providerConfigSubmitHandler = async (
) => {
const parameters = provider.metadata.config_keys || [];
if (parameters.length === 0) {
// For zero-config providers, mark them as configured
const configKey = `${provider.name}_configured`;
await upsertFn(configKey, true, false);
await upsertFn('GOOSE_PROVIDER', provider.name, false);
return;
}
const requiredParams = parameters.filter((param) => param.required);
if (requiredParams.length === 0 && parameters.length > 0) {
const allOptionalWithDefaults = parameters.every(
@@ -35,8 +28,6 @@ export const providerConfigSubmitHandler = async (
);
if (allOptionalWithDefaults) {
const promises: Promise<void>[] = [];
const configKey = `${provider.name}_configured`;
promises.push(upsertFn(configKey, true, false));
for (const param of parameters) {
if (param.default !== undefined) {
@@ -46,39 +37,41 @@ export const providerConfigSubmitHandler = async (
}
}
return Promise.all(promises);
await Promise.all(promises);
return;
}
}
const upsertPromises = parameters.map(
(parameter: { name: string; required?: boolean; default?: unknown; secret?: boolean }) => {
// Skip parameters that don't have a value and aren't required
async (parameter: {
name: string;
required?: boolean;
default?: unknown;
secret?: boolean;
}) => {
if (!configValues[parameter.name] && !parameter.required) {
return Promise.resolve();
return;
}
// For required parameters with no value, use the default if available
const value =
configValues[parameter.name] !== undefined
? configValues[parameter.name]
: parameter.default;
// Skip if there's still no value
if (value === undefined || value === null) {
return Promise.resolve();
return;
}
// Create the provider-specific config key
const configKey = `${parameter.name}`;
// Explicitly define is_secret as a boolean (true/false)
const isSecret = parameter.secret === true;
// Pass the is_secret flag from the parameter definition
return upsertFn(configKey, value, isSecret);
await upsertFn(configKey, value, isSecret);
}
);
// Wait for all upsert operations to complete
return Promise.all(upsertPromises);
await Promise.all(upsertPromises);
await checkProvider({
body: { provider: provider.name },
throwOnError: true,
});
};