This is an automated email from the ASF dual-hosted git repository.

lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git


The following commit(s) were added to refs/heads/rocketmq-studio by this push:
     new 27608f79f fix(ai): return models from connection test and refresh 
selector (#2387)
27608f79f is described below

commit 27608f79fe34bcae4893f9dde079c2352c27dec3
Author: aias00 <[email protected]>
AuthorDate: Wed Aug 19 17:34:44 2026 +0800

    fix(ai): return models from connection test and refresh selector (#2387)
    
    * feat(ai): return models from connection test
    
    * test(ai): cover models returned for Ollama connection
---
 .../rocketmq/studio/ops/ai/LlmConfigService.java   |  9 ++++++---
 .../studio/ops/ai/LlmOperationResultVO.java        | 11 +++++++++--
 .../studio/ops/ai/LlmConfigServiceTest.java        |  1 +
 web/src/api/llm.ts                                 |  1 +
 web/src/pages/settings/AiAssistantTab.tsx          |  4 ++++
 .../settings/__tests__/AiAssistantTab.test.tsx     | 23 ++++++++++++++++++++++
 6 files changed, 44 insertions(+), 5 deletions(-)

diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
index 7308a855d..900e45887 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmConfigService.java
@@ -141,11 +141,11 @@ public class LlmConfigService {
                     "Use one of: openai, deepseek, tongyi, ollama.");
         }
         try {
-            llmClient.listModels(normalized);
+            List<LlmModelItemVO> models = llmClient.listModels(normalized);
+            return LlmOperationResultVO.successWithModels("Connection 
successful", models);
         } catch (LlmGatewayException exception) {
             return LlmOperationResultVO.failure(exception.getCode(), 
exception.getMessage(), exception.getHint());
         }
-        return LlmOperationResultVO.success("Connection successful");
     }
 
     private LlmOperationResultVO testCliEngine(String engine) {
@@ -209,7 +209,10 @@ public class LlmConfigService {
     }
 
     public LlmModelsResultVO listModels() {
-        LlmConfigVO config = getConfig();
+        return listModels(getConfig());
+    }
+
+    private LlmModelsResultVO listModels(LlmConfigVO config) {
         String provider = config.getProvider();
         // The token-plan gateway model set is curated locally; do not query 
the gateway.
         if (DEFAULT_PROVIDER.equals(provider)) {
diff --git 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmOperationResultVO.java
 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmOperationResultVO.java
index 141178d96..c7a78b459 100644
--- 
a/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmOperationResultVO.java
+++ 
b/server/src/main/java/org/apache/rocketmq/studio/ops/ai/LlmOperationResultVO.java
@@ -21,6 +21,8 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.util.List;
+
 @Data
 @NoArgsConstructor
 @AllArgsConstructor
@@ -30,9 +32,14 @@ public class LlmOperationResultVO {
     private String errMsg;
     private String code;
     private String hint;
+    private List<LlmModelItemVO> models;
 
     public static LlmOperationResultVO success(String message) {
-        return new LlmOperationResultVO(0, message, null, null, null);
+        return new LlmOperationResultVO(0, message, null, null, null, null);
+    }
+
+    public static LlmOperationResultVO successWithModels(String message, 
List<LlmModelItemVO> models) {
+        return new LlmOperationResultVO(0, message, null, null, null, models);
     }
 
     public static LlmOperationResultVO failure(String message) {
@@ -40,6 +47,6 @@ public class LlmOperationResultVO {
     }
 
     public static LlmOperationResultVO failure(String code, String message, 
String hint) {
-        return new LlmOperationResultVO(1, null, message, code, hint);
+        return new LlmOperationResultVO(1, null, message, code, hint, null);
     }
 }
diff --git 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
index db8a5872e..07f67b62d 100644
--- 
a/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
+++ 
b/server/src/test/java/org/apache/rocketmq/studio/ops/ai/LlmConfigServiceTest.java
@@ -338,6 +338,7 @@ class LlmConfigServiceTest {
 
         assertThat(result.getStatus()).isZero();
         assertThat(result.getMsg()).isEqualTo("Connection successful");
+        assertThat(result.getModels()).isEmpty();
     }
 
     @Test
diff --git a/web/src/api/llm.ts b/web/src/api/llm.ts
index 3f5a24147..2c29e65aa 100644
--- a/web/src/api/llm.ts
+++ b/web/src/api/llm.ts
@@ -39,6 +39,7 @@ export interface LlmTestResult {
   errMsg?: string;
   code?: string;
   hint?: string;
+  models?: LlmModelItem[];
 }
 
 export interface LlmModelItem {
diff --git a/web/src/pages/settings/AiAssistantTab.tsx 
b/web/src/pages/settings/AiAssistantTab.tsx
index f6888c979..0d404cf3c 100644
--- a/web/src/pages/settings/AiAssistantTab.tsx
+++ b/web/src/pages/settings/AiAssistantTab.tsx
@@ -234,6 +234,10 @@ export const AiAssistantTab = () => {
       const result = await testLlmConnection(payload);
       if (testRequestIdRef.current === requestId) {
         applyTestResult(result);
+        if (result.status === 0) {
+          const remoteModels = result.models?.map((model) => model.id || 
'').filter(Boolean) ?? [];
+          setModelOptions(buildModelOptions(payload.provider, remoteModels, 
payload.model));
+        }
       }
     } catch {
       if (testRequestIdRef.current === requestId) {
diff --git a/web/src/pages/settings/__tests__/AiAssistantTab.test.tsx 
b/web/src/pages/settings/__tests__/AiAssistantTab.test.tsx
index 005f094e1..84c0d1686 100644
--- a/web/src/pages/settings/__tests__/AiAssistantTab.test.tsx
+++ b/web/src/pages/settings/__tests__/AiAssistantTab.test.tsx
@@ -145,6 +145,29 @@ describe('AiAssistantTab', () => {
     ).toBeInTheDocument();
   });
 
+  it('refreshes the model list from a successful connection test', async () => 
{
+    const user = userEvent.setup();
+    llmApiMocks.testLlmConnection.mockResolvedValue({
+      status: 0,
+      msg: 'ok',
+      models: [{ id: 'qwen3.8-max' }, { id: 'qwen-plus-latest' }],
+    });
+    renderPage();
+
+    await screen.findByText('密钥已配置');
+    await user.type(screen.getByLabelText('API Key'), 'sk-preview');
+    await user.click(screen.getByRole('button', { name: /测试连接/ }));
+
+    await waitFor(() => 
expect(llmApiMocks.testLlmConnection).toHaveBeenCalledTimes(1));
+    expect(llmApiMocks.testLlmConnection).toHaveBeenCalledWith(
+      expect.objectContaining({ apiKey: 'sk-preview', provider: 'tongyi' }),
+    );
+    await user.click(screen.getAllByRole('combobox')[2]);
+    expect(
+      await screen.findByText('qwen-plus-latest', { selector: 
'.ant-select-item-option-content' }),
+    ).toBeInTheDocument();
+  });
+
   it('ignores a connection result after the tested configuration changes', 
async () => {
     let resolveTest!: (result: { status: number; msg: string }) => void;
     llmApiMocks.testLlmConnection.mockImplementationOnce(

Reply via email to