From 8a614aac580088681f8f5f9a4bb6bcad7bc0337e Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 25 Dec 2025 18:20:37 +0700 Subject: [PATCH] Add listProviderModels() to DaemonClient + E2E tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add method to query available models for Claude and Codex providers without requiring an active agent. E2E tests verify both providers return model lists with expected structure (id, label, provider). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- packages/server/src/server/daemon.e2e.test.ts | 50 +++++++++++++++++++ .../src/server/test-utils/daemon-client.ts | 42 ++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/packages/server/src/server/daemon.e2e.test.ts b/packages/server/src/server/daemon.e2e.test.ts index 490daea34..19615b06b 100644 --- a/packages/server/src/server/daemon.e2e.test.ts +++ b/packages/server/src/server/daemon.e2e.test.ts @@ -1454,4 +1454,54 @@ describe("daemon E2E", () => { 60000 // 1 minute timeout ); }); + + describe("listProviderModels", () => { + test( + "returns model list for Codex provider", + async () => { + // List models for Codex provider - no agent needed + const result = await ctx.client.listProviderModels("codex"); + + // Verify response structure + expect(result.provider).toBe("codex"); + expect(result.error).toBeNull(); + expect(result.fetchedAt).toBeTruthy(); + + // Should return at least one model + expect(result.models).toBeTruthy(); + expect(result.models.length).toBeGreaterThan(0); + + // Verify model structure + const model = result.models[0]; + expect(model.provider).toBe("codex"); + expect(model.id).toBeTruthy(); + expect(model.label).toBeTruthy(); + }, + 60000 // 1 minute timeout + ); + + test( + "returns model list for Claude provider", + async () => { + // List models for Claude provider - no agent needed + const result = await ctx.client.listProviderModels("claude"); + + // Verify response structure + expect(result.provider).toBe("claude"); + expect(result.error).toBeNull(); + expect(result.fetchedAt).toBeTruthy(); + + // Should return at least one model + expect(result.models).toBeTruthy(); + expect(result.models.length).toBeGreaterThan(0); + + // Verify model structure + const model = result.models[0]; + expect(model.provider).toBe("claude"); + expect(model.id).toBeTruthy(); + expect(model.label).toBeTruthy(); + }, + 60000 // 1 minute timeout + ); + }); }); diff --git a/packages/server/src/server/test-utils/daemon-client.ts b/packages/server/src/server/test-utils/daemon-client.ts index b624babe4..b90f61545 100644 --- a/packages/server/src/server/test-utils/daemon-client.ts +++ b/packages/server/src/server/test-utils/daemon-client.ts @@ -8,6 +8,7 @@ import type { PersistedAgentDescriptorPayload, } from "../messages.js"; import type { + AgentModelDefinition, AgentPermissionRequest, AgentPermissionResponse, AgentPersistenceHandle, @@ -489,6 +490,47 @@ export class DaemonClient { ); } + // ============================================================================ + // Provider Models + // ============================================================================ + + async listProviderModels( + provider: AgentProvider, + options?: { cwd?: string } + ): Promise<{ + provider: AgentProvider; + models: AgentModelDefinition[]; + fetchedAt: string; + error: string | null; + }> { + const startPosition = this.messageQueue.length; + + this.send({ + type: "list_provider_models_request", + provider, + cwd: options?.cwd, + }); + + return this.waitFor( + (msg) => { + if ( + msg.type === "list_provider_models_response" && + msg.payload.provider === provider + ) { + return { + provider: msg.payload.provider, + models: msg.payload.models ?? [], + fetchedAt: msg.payload.fetchedAt, + error: msg.payload.error ?? null, + }; + } + return null; + }, + 30000, + { skipQueueBefore: startPosition } + ); + } + // ============================================================================ // Permissions // ============================================================================