diff --git a/web/src/app/home/components/WorkspaceAssistant.tsx b/web/src/app/home/components/WorkspaceAssistant.tsx
index 82d8ff235..dd2dbad38 100644
--- a/web/src/app/home/components/WorkspaceAssistant.tsx
+++ b/web/src/app/home/components/WorkspaceAssistant.tsx
@@ -22,6 +22,7 @@ import {
} from '@/app/infra/http';
import { toast } from 'sonner';
import { httpClient } from '@/app/infra/http/HttpClient';
+import { MODEL_CONFIGURATION_CHANGED } from '@/app/infra/http/modelConfigEvents';
import SettingsDialog, {
SettingsSection,
} from './settings-dialog/SettingsDialog';
@@ -85,10 +86,12 @@ function AssistantEntry({ storageKey }: { storageKey: string }) {
useEffect(() => {
let active = true;
+ let latestCheck = 0;
async function check() {
+ const currentCheck = ++latestCheck;
try {
const { models } = await backendClient.getProviderLLMModels();
- if (active) {
+ if (active && currentCheck === latestCheck) {
const usableModels = models.filter(
(model) =>
!!model.uuid?.trim() &&
@@ -109,14 +112,16 @@ function AssistantEntry({ storageKey }: { storageKey: string }) {
setFailed(false);
}
} catch {
- if (active) setFailed(true);
+ if (active && currentCheck === latestCheck) setFailed(true);
}
}
if (!settingsOpen) void check();
window.addEventListener('focus', check);
+ window.addEventListener(MODEL_CONFIGURATION_CHANGED, check);
return () => {
active = false;
window.removeEventListener('focus', check);
+ window.removeEventListener(MODEL_CONFIGURATION_CHANGED, check);
};
}, [settingsOpen, retry]);
diff --git a/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx b/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx
index 054120395..3f14128c8 100644
--- a/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx
+++ b/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx
@@ -22,6 +22,7 @@ import { ControllerRenderProps } from 'react-hook-form';
import { Button } from '@/components/ui/button';
import { useEffect, useState } from 'react';
import { httpClient, systemInfo, userInfo } from '@/app/infra/http';
+import { MODEL_CONFIGURATION_CHANGED } from '@/app/infra/http/modelConfigEvents';
import { useInstalledPluginIcon } from '@/app/infra/hooks/useInstalledPluginIcon';
import {
LLMModel,
@@ -306,6 +307,10 @@ export default function DynamicFormItemComponent({
useEffect(() => {
if (config.type === DynamicFormItemType.LLM_MODEL_SELECTOR) {
fetchLlmModels();
+ window.addEventListener(MODEL_CONFIGURATION_CHANGED, fetchLlmModels);
+ return () => {
+ window.removeEventListener(MODEL_CONFIGURATION_CHANGED, fetchLlmModels);
+ };
}
}, [config.type]);
diff --git a/web/src/app/home/components/models-dialog/components/ProviderCard.tsx b/web/src/app/home/components/models-dialog/components/ProviderCard.tsx
index 0d29151d4..a0b49612e 100644
--- a/web/src/app/home/components/models-dialog/components/ProviderCard.tsx
+++ b/web/src/app/home/components/models-dialog/components/ProviderCard.tsx
@@ -367,7 +367,7 @@ export default function ProviderCard({
}}
>
- {t('models.addModel')}
+ {t('common.add')}
}
onOpen={() => {
@@ -394,14 +394,15 @@ export default function ProviderCard({
trigger={
}
onOpen={() => {
diff --git a/web/src/app/infra/http/BackendClient.ts b/web/src/app/infra/http/BackendClient.ts
index 27eb93657..b8591c4c4 100644
--- a/web/src/app/infra/http/BackendClient.ts
+++ b/web/src/app/infra/http/BackendClient.ts
@@ -1,4 +1,5 @@
import { BaseHttpClient, type RequestConfig } from './BaseHttpClient';
+import { notifyAfterModelConfigurationChange } from './modelConfigEvents';
import type {
PipelineMigrationPreview,
PipelineMigrationRequest,
@@ -148,19 +149,25 @@ export class BackendClient extends BaseHttpClient {
public createModelProvider(
provider: Omit,
): Promise<{ uuid: string }> {
- return this.post('/api/v1/provider/providers', provider);
+ return notifyAfterModelConfigurationChange(
+ this.post<{ uuid: string }>('/api/v1/provider/providers', provider),
+ );
}
public updateModelProvider(
uuid: string,
provider: Partial,
): Promise