From fe324fac818bc8dc11ff710a385d5aa5b89d5ab9 Mon Sep 17 00:00:00 2001
From: Hyu
Date: Fri, 9 Oct 2026 00:29:39 +0800
Subject: [PATCH] fix(web): improve assistant setup and model login guidance
---
.../home/components/WorkspaceAssistant.tsx | 320 ++++++++++--------
.../models-dialog/components/ProviderCard.tsx | 20 +-
web/src/i18n/locales/en-US.ts | 3 +-
web/src/i18n/locales/ja-JP.ts | 2 +-
web/src/i18n/locales/zh-Hans.ts | 7 +-
5 files changed, 197 insertions(+), 155 deletions(-)
diff --git a/web/src/app/home/components/WorkspaceAssistant.tsx b/web/src/app/home/components/WorkspaceAssistant.tsx
index d7c42f3af..82d8ff235 100644
--- a/web/src/app/home/components/WorkspaceAssistant.tsx
+++ b/web/src/app/home/components/WorkspaceAssistant.tsx
@@ -1,4 +1,4 @@
-import { useEffect, useRef, useState, useId } from 'react';
+import { useEffect, useRef, useState, useId, type ReactNode } from 'react';
import { createPortal } from 'react-dom';
import { Plus, Send, ChevronDown, LoaderCircle, Square } from 'lucide-react';
import {
@@ -14,7 +14,12 @@ import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeHighlight from 'rehype-highlight';
import '@/styles/github-markdown.css';
-import { backendClient, useCurrentWorkspace, userInfo } from '@/app/infra/http';
+import {
+ backendClient,
+ systemInfo,
+ useCurrentWorkspace,
+ userInfo,
+} from '@/app/infra/http';
import { toast } from 'sonner';
import { httpClient } from '@/app/infra/http/HttpClient';
import SettingsDialog, {
@@ -31,6 +36,7 @@ import {
import DynamicFormItemComponent from './dynamic-form/DynamicFormItemComponent';
import { DynamicFormItemType } from '@/app/infra/entities/form/dynamic';
import AssistantToolResult, { AssistantTool } from './AssistantToolResult';
+import { LANGBOT_MODELS_PROVIDER_REQUESTER } from './models-dialog/types';
type Conversation = {
uuid: string;
@@ -68,6 +74,9 @@ export default function WorkspaceAssistant() {
function AssistantEntry({ storageKey }: { storageKey: string }) {
const { t } = useTranslation();
const [available, setAvailable] = useState(null);
+ const [localModel, setLocalModel] = useState<
+ { uuid: string; name: string } | undefined
+ >();
const [failed, setFailed] = useState(false);
const [settingsOpen, setSettingsOpen] = useState(false);
const [section, setSection] = useState('models');
@@ -78,9 +87,25 @@ function AssistantEntry({ storageKey }: { storageKey: string }) {
let active = true;
async function check() {
try {
- const { providers } = await backendClient.getModelProviders();
+ const { models } = await backendClient.getProviderLLMModels();
if (active) {
- setAvailable(providers.length > 0);
+ const usableModels = models.filter(
+ (model) =>
+ !!model.uuid?.trim() &&
+ model.abilities?.includes('func_call') &&
+ (model.provider?.requester !==
+ LANGBOT_MODELS_PROVIDER_REQUESTER ||
+ (userInfo?.account_type === 'space' &&
+ !systemInfo.disable_models_service)),
+ );
+ setAvailable(usableModels.length > 0);
+ const firstLocalModel =
+ userInfo?.account_type !== 'space' ? usableModels[0] : undefined;
+ setLocalModel(
+ firstLocalModel
+ ? { uuid: firstLocalModel.uuid, name: firstLocalModel.name }
+ : undefined,
+ );
setFailed(false);
}
} catch {
@@ -98,8 +123,8 @@ function AssistantEntry({ storageKey }: { storageKey: string }) {
async function login() {
setLoginBusy(true);
try {
- const response = await httpClient.getSpaceAuthorizeUrl(
- `${window.location.origin}/auth/space/callback`,
+ const response = await httpClient.getSpaceBindAuthorizeUrl(
+ `${window.location.origin}/auth/space/callback?mode=bind`,
);
window.location.href = response.authorize_url;
} catch {
@@ -110,29 +135,25 @@ function AssistantEntry({ storageKey }: { storageKey: string }) {
return (
<>
- {available ? (
-
- ) : available === false || failed ? (
- createPortal(
-
)}
- {modelError && !modelUuid && (
+ {canUseModels && modelError && !modelUuid && (
{t('assistant.recommendationFailed')}
@@ -1050,107 +1084,113 @@ function AssistantPanel({
)}
-
+ ) : (
+ setup
+ )}
)}
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 ac522f258..0d29151d4 100644
--- a/web/src/app/home/components/models-dialog/components/ProviderCard.tsx
+++ b/web/src/app/home/components/models-dialog/components/ProviderCard.tsx
@@ -195,9 +195,18 @@ export default function ProviderCard({
{t('models.modelsCount', { count: totalModels })}
-
+
{isLangBotModels ? (
- t('models.langbotModelsDescription')
+ <>
+ {t('models.langbotModelsDescription')}
+ {!ownerSpaceBound && (
+
+ {t('models.ownerMustBindSpace')}
+
+ )}
+ >
) : (
<>
{provider.base_url}
@@ -222,7 +231,7 @@ export default function ProviderCard({
}}
>
- {t('models.ownerMustBindSpace')}
+ {t('models.loginWithSpace')}
)}
{isLangBotModels && ownerSpaceBound && spaceCredits !== null && (
@@ -253,11 +262,6 @@ export default function ProviderCard({
{t('models.usesOwnerSpaceBilling')}
)}
- {isLangBotModels && !isWorkspaceOwner && !ownerSpaceBound && (
-
- {t('models.ownerMustBindSpace')}
-
- )}
{canManage && !isLangBotModels && (
<>