From d945323526d311a5b46bc02cba48094d223337e5 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:17:24 +0530 Subject: [PATCH 1/5] test: stop treating test support as a suite --- src/bin-launcher.test.ts | 2 +- src/cli-show-changes.test.ts | 2 +- src/cli-worktrees.test.ts | 2 +- src/cli.test.ts | 2 +- src/local-agent-profiles.test.ts | 2 +- src/server-oauth.test.ts | 2 +- src/server.test.ts | 2 +- src/skills.test.ts | 2 +- src/test-support/{config.test.ts => config.ts} | 0 src/workspace-conversation.test.ts | 2 +- src/workspaces.test.ts | 2 +- test/package-install-smoke.test.ts | 2 +- 12 files changed, 11 insertions(+), 11 deletions(-) rename src/test-support/{config.test.ts => config.ts} (100%) diff --git a/src/bin-launcher.test.ts b/src/bin-launcher.test.ts index 00b43a99f..f1f5fba37 100644 --- a/src/bin-launcher.test.ts +++ b/src/bin-launcher.test.ts @@ -4,7 +4,7 @@ import { cpSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } fr import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const projectRoot = fileURLToPath(new URL("..", import.meta.url)); const tsxRoot = join(projectRoot, "node_modules", "tsx"); diff --git a/src/cli-show-changes.test.ts b/src/cli-show-changes.test.ts index 40763b86e..b147b7605 100644 --- a/src/cli-show-changes.test.ts +++ b/src/cli-show-changes.test.ts @@ -9,7 +9,7 @@ import test from "node:test"; import { fileURLToPath } from "node:url"; import { promisify } from "node:util"; import { createReviewCheckpointManager } from "./review-checkpoints.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const execFileAsync = promisify(execFile); const require = createRequire(import.meta.url); diff --git a/src/cli-worktrees.test.ts b/src/cli-worktrees.test.ts index f749e2afa..2d6a40a3d 100644 --- a/src/cli-worktrees.test.ts +++ b/src/cli-worktrees.test.ts @@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url"; import test from "node:test"; import { promisify } from "node:util"; import { openDatabase } from "./db/client.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; import { SqliteWorkspaceStore } from "./workspace-store.js"; const execFileAsync = promisify(execFile); diff --git a/src/cli.test.ts b/src/cli.test.ts index 3a622eb19..a70f4d5d2 100644 --- a/src/cli.test.ts +++ b/src/cli.test.ts @@ -14,7 +14,7 @@ import { } from "./local-agent-daemon-lifecycle.js"; import { encodeLocalAgentDaemonResponse } from "./local-agent-daemon-protocol.js"; import { LocalAgentStore } from "./local-agent-store.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const execFileAsync = promisify(execFile); const require = createRequire(import.meta.url); diff --git a/src/local-agent-profiles.test.ts b/src/local-agent-profiles.test.ts index 8a7d57db1..7751e2fc5 100644 --- a/src/local-agent-profiles.test.ts +++ b/src/local-agent-profiles.test.ts @@ -4,7 +4,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { loadConfig } from "./config.js"; import { loadLocalAgentProfiles } from "./local-agent-profiles.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const root = await mkdtemp(join(tmpdir(), "devspace-agent-profiles-test-")); diff --git a/src/server-oauth.test.ts b/src/server-oauth.test.ts index 1ab4fcfb7..f9cdf5720 100644 --- a/src/server-oauth.test.ts +++ b/src/server-oauth.test.ts @@ -8,7 +8,7 @@ import test from "node:test"; import { loadConfig } from "./config.js"; import { SqliteOAuthStore } from "./oauth-store.js"; import { createServer } from "./server.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; test("HTTP MCP enforces canonical and exact alias bearer resources", async (t) => { const root = await mkdtemp(join(tmpdir(), "devspace-http-oauth-")); diff --git a/src/server.test.ts b/src/server.test.ts index 59bcc5d37..d436fb76f 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -17,7 +17,7 @@ import { ProcessSessionManager } from "./process-sessions.js"; import { createMcpServer, createServer } from "./server.js"; import { SqliteWorkspaceStore } from "./workspace-store.js"; import { WorkspaceRegistry } from "./workspaces.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const execFileAsync = promisify(execFile); diff --git a/src/skills.test.ts b/src/skills.test.ts index 357c417db..e3e57371e 100644 --- a/src/skills.test.ts +++ b/src/skills.test.ts @@ -9,7 +9,7 @@ import { loadWorkspaceSkills, resolveSkillReadPath, } from "./skills.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const root = await mkdtemp(join(tmpdir(), "devspace-skills-test-")); const originalHome = process.env.HOME; diff --git a/src/test-support/config.test.ts b/src/test-support/config.ts similarity index 100% rename from src/test-support/config.test.ts rename to src/test-support/config.ts diff --git a/src/workspace-conversation.test.ts b/src/workspace-conversation.test.ts index 67ebbe2ac..d7d3e2979 100644 --- a/src/workspace-conversation.test.ts +++ b/src/workspace-conversation.test.ts @@ -9,7 +9,7 @@ import { loadConfig, type ServerConfig } from "./config.js"; import { openDatabase } from "./db/client.js"; import { SqliteWorkspaceStore } from "./workspace-store.js"; import { WorkspaceRegistry } from "./workspaces.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const execFileAsync = promisify(execFile); diff --git a/src/workspaces.test.ts b/src/workspaces.test.ts index 914837502..c79dd4584 100644 --- a/src/workspaces.test.ts +++ b/src/workspaces.test.ts @@ -13,7 +13,7 @@ import { type WorkspaceStoreError, } from "./workspace-store.js"; import { WorkspaceRegistry } from "./workspaces.js"; -import { writeTestDevspaceConfig } from "./test-support/config.test.js"; +import { writeTestDevspaceConfig } from "./test-support/config.js"; const execFileAsync = promisify(execFile); diff --git a/test/package-install-smoke.test.ts b/test/package-install-smoke.test.ts index c53477fd8..4400628ed 100644 --- a/test/package-install-smoke.test.ts +++ b/test/package-install-smoke.test.ts @@ -4,7 +4,7 @@ import { mkdirSync, mkdtempSync, readdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; -import { writeTestDevspaceConfig } from "../src/test-support/config.test.js"; +import { writeTestDevspaceConfig } from "../src/test-support/config.js"; const projectRoot = fileURLToPath(new URL("..", import.meta.url)); From 908ede3230f82945e9ac7c286a99fccc26c5f55d Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:17:24 +0530 Subject: [PATCH 2/5] test: trim redundant unit coverage --- src/local-agent-catalog.test.ts | 60 ---------------------------- src/local-agent-presentation.test.ts | 57 +++++--------------------- src/request-meta.test.ts | 24 ----------- src/server.test.ts | 27 ++++++++++--- 4 files changed, 31 insertions(+), 137 deletions(-) delete mode 100644 src/local-agent-catalog.test.ts delete mode 100644 src/request-meta.test.ts diff --git a/src/local-agent-catalog.test.ts b/src/local-agent-catalog.test.ts deleted file mode 100644 index cc156251d..000000000 --- a/src/local-agent-catalog.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import assert from "node:assert/strict"; -import { - buildLocalAgentCatalog, - buildLocalAgentProviderStatuses, -} from "./local-agent-catalog.js"; -import type { LocalAgentProfile } from "./local-agent-profiles.js"; -import type { SubagentsConfig } from "./local-agent-config.js"; - -const config: SubagentsConfig = { - enabled: true, - instructions: "on-demand", - providers: [ - { id: "codex", enabled: true, model: "gpt-default", effort: "medium" }, - { id: "claude", enabled: true, model: "sonnet" }, - { id: "pi", enabled: false }, - ], -}; -const statuses = buildLocalAgentProviderStatuses(config, [ - { name: "codex", available: true }, - { name: "claude", available: false, reason: "credentials missing" }, - { name: "pi", available: true }, -]); -assert.equal(statuses.find((provider) => provider.id === "codex")?.usable, true); -assert.equal(statuses.find((provider) => provider.id === "claude")?.usable, false); -assert.equal(statuses.find((provider) => provider.id === "pi")?.usable, false); -assert.equal(statuses.find((provider) => provider.id === "opencode")?.enabled, false); - -const profiles: LocalAgentProfile[] = [ - { - name: "reviewer", - description: "Review changes.", - provider: "codex", - filePath: "/project/reviewer.md", - body: "Review only.", - disabled: false, - }, - { - name: "custom", - description: "Use a custom model.", - provider: "codex", - model: "gpt-custom", - filePath: "/project/custom.md", - body: "Inspect.", - disabled: false, - }, - { - name: "claude-reviewer", - description: "Unavailable profile.", - provider: "claude", - filePath: "/project/claude.md", - body: "Review.", - disabled: false, - }, -]; -const catalog = buildLocalAgentCatalog(config, profiles, statuses); -assert.deepEqual(catalog.providers.map((provider) => provider.id), ["codex", "claude"]); -assert.deepEqual(catalog.profiles.map((profile) => profile.name), ["reviewer", "custom"]); -assert.equal(catalog.profiles[0]?.model, "gpt-default"); -assert.equal(catalog.profiles[0]?.effort, "medium"); -assert.equal(catalog.profiles[1]?.model, "gpt-custom"); diff --git a/src/local-agent-presentation.test.ts b/src/local-agent-presentation.test.ts index ea1a4d6e6..c85418656 100644 --- a/src/local-agent-presentation.test.ts +++ b/src/local-agent-presentation.test.ts @@ -2,57 +2,24 @@ import assert from "node:assert/strict"; import type { LocalAgentCatalog } from "./local-agent-catalog.js"; import { presentAgentObservation, - presentAgentReceipt, - presentAgentSummary, presentAgentTargetCatalog, } from "./local-agent-presentation.js"; import type { LocalAgentRecord } from "./local-agent-store.js"; -const record: LocalAgentRecord = { +const failed: LocalAgentRecord = { id: "agt_test", - workspaceId: "ws_private", workspaceRoot: "/private/project", profileName: "reviewer", provider: "codex", - model: "gpt-5.4", - effort: "high", - providerSessionId: "provider_private", - status: "running", - latestResponse: "previous response", - createdAt: "2026-08-21T10:00:00.000Z", - updatedAt: "2026-08-21T10:01:00.000Z", -}; - -assert.deepEqual(presentAgentReceipt({ ...record, status: "starting" }), { - id: "agt_test", - status: "running", -}); -assert.deepEqual(presentAgentSummary({ ...record, status: "idle" }), { - id: "agt_test", - status: "completed", - target: "reviewer", -}); - -const completed = presentAgentObservation({ - ...record, - status: "idle", - latestResponse: "Found one issue.", -}); -assert.deepEqual(completed, { - id: "agt_test", - status: "completed", - response: "Found one issue.", -}); - -const failed = presentAgentObservation({ - ...record, status: "error", - latestResponse: undefined, error: "Provider disconnected.", errorCode: "PROVIDER_EXECUTION_ERROR", errorRetryable: true, -}); -assert.deepEqual(failed, { + createdAt: "2026-08-21T10:00:00.000Z", + updatedAt: "2026-08-21T10:01:00.000Z", +}; + +assert.deepEqual(presentAgentObservation(failed), { id: "agt_test", status: "failed", error: { @@ -66,13 +33,7 @@ const catalog: LocalAgentCatalog = { enabled: true, providers: [ { id: "codex", enabled: true, available: true, usable: true, model: "gpt-5.4", effort: "high" }, - { - id: "claude", - enabled: true, - available: false, - usable: false, - reason: "credentials missing", - }, + { id: "claude", enabled: true, available: false, usable: false }, ], profiles: [{ name: "reviewer", @@ -82,8 +43,8 @@ const catalog: LocalAgentCatalog = { effort: "high", }], }; -const targetCatalog = presentAgentTargetCatalog(catalog); -assert.deepEqual(targetCatalog, { + +assert.deepEqual(presentAgentTargetCatalog(catalog), { targets: [ { name: "codex", kind: "provider", model: "gpt-5.4", effort: "high" }, { diff --git a/src/request-meta.test.ts b/src/request-meta.test.ts deleted file mode 100644 index f00ed5f95..000000000 --- a/src/request-meta.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; -import { conversationScopeIdFromRequestMeta } from "./request-meta.js"; - -test("conversation scope resolves valid OpenAI session metadata", () => { - for (const meta of [ - undefined, - {}, - { "openai/session": "" }, - { "openai/session": 42 }, - { "openai/session": {} }, - ]) { - assert.equal(conversationScopeIdFromRequestMeta(meta), undefined); - } - - assert.equal( - conversationScopeIdFromRequestMeta({ - "openai/session": "chat-session-opaque-value", - "openai/subject": "user-1", - "openai/organization": "org-1", - }), - "chat-session-opaque-value", - ); -}); diff --git a/src/server.test.ts b/src/server.test.ts index d436fb76f..8415eaf90 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -387,6 +387,11 @@ test("open_workspace refreshes provider availability for each catalog", async (t let available = false; const context = await fixture(t, { localAgentProviders: () => [{ name: "codex", available }], + subagents: { + enabled: true, + instructions: "on-demand", + providers: [{ id: "codex", enabled: true, model: "gpt-default", effort: "medium" }], + }, }); const unavailable = structuredContent(await callOpen(context.client, context.project, "chat-1")); @@ -399,10 +404,18 @@ test("open_workspace refreshes provider availability for each catalog", async (t (usable.agent_providers as Array>)[0]?.id, "codex", ); - assert.equal( - (usable.agents as Array>)[0]?.name, - "reviewer", + const provider = (usable.agent_providers as Array>)[0]; + assert.deepEqual( + { id: provider?.id, model: provider?.model, effort: provider?.effort }, + { id: "codex", model: "gpt-default", effort: "medium" }, ); + assert.deepEqual((usable.agents as Array>)[0], { + name: "reviewer", + description: "Reviews project changes.", + provider: "codex", + model: "gpt-default", + effort: "medium", + }); }); test("open_workspace omits providers disabled by configuration", async (t) => { @@ -461,11 +474,15 @@ test("open_workspace scopes checkout reuse to OpenAI session metadata", async (t const repeated = await callOpen(context.client, context.project, "chat-1"); const otherSession = await callOpen(context.client, context.project, "chat-2"); const unscoped = await callOpen(context.client, context.project); + const emptySession = await callOpen(context.client, context.project, ""); + const malformedSession = await callOpen(context.client, context.project, 42); assert.equal(structuredContent(repeated).workspace_id, structuredContent(first).workspace_id); assert.equal(structuredContent(repeated).agents_files, undefined); assert.notEqual(structuredContent(otherSession).workspace_id, structuredContent(first).workspace_id); assert.notEqual(structuredContent(unscoped).workspace_id, structuredContent(first).workspace_id); + assert.notEqual(structuredContent(emptySession).workspace_id, structuredContent(first).workspace_id); + assert.notEqual(structuredContent(malformedSession).workspace_id, structuredContent(first).workspace_id); assert.ok(Array.isArray(structuredContent(otherSession).agents_files)); assert.ok(Array.isArray(structuredContent(unscoped).agents_files)); }); @@ -953,12 +970,12 @@ function recordValue(value: unknown): Record { async function callOpen( client: Client, path: string, - conversationScopeId?: string, + conversationScopeId?: unknown, ): Promise>> { const params = { name: "open_workspace", arguments: { path }, - ...(conversationScopeId + ...(conversationScopeId !== undefined ? { _meta: { "openai/session": conversationScopeId } } : {}), } as Parameters[0]; From 67ec8982413004078050cc9481d7b4dc92e2f2b5 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:26:33 +0530 Subject: [PATCH 3/5] test: preserve profile override coverage --- src/server.test.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/server.test.ts b/src/server.test.ts index 8415eaf90..5e01dcbf1 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -393,6 +393,15 @@ test("open_workspace refreshes provider availability for each catalog", async (t providers: [{ id: "codex", enabled: true, model: "gpt-default", effort: "medium" }], }, }); + await writeFile(join(context.project, ".devspace", "agents", "custom.md"), [ + "---", + "name: custom", + "description: Uses a custom model.", + "provider: codex", + "model: gpt-custom", + "---", + "Inspect.", + ].join("\n")); const unavailable = structuredContent(await callOpen(context.client, context.project, "chat-1")); assert.deepEqual(unavailable.agent_providers, []); @@ -409,13 +418,21 @@ test("open_workspace refreshes provider availability for each catalog", async (t { id: provider?.id, model: provider?.model, effort: provider?.effort }, { id: "codex", model: "gpt-default", effort: "medium" }, ); - assert.deepEqual((usable.agents as Array>)[0], { + const agents = usable.agents as Array>; + assert.deepEqual(agents.find((agent) => agent.name === "reviewer"), { name: "reviewer", description: "Reviews project changes.", provider: "codex", model: "gpt-default", effort: "medium", }); + assert.deepEqual(agents.find((agent) => agent.name === "custom"), { + name: "custom", + description: "Uses a custom model.", + provider: "codex", + model: "gpt-custom", + effort: "medium", + }); }); test("open_workspace omits providers disabled by configuration", async (t) => { From 50f012616d2ac47fa5a6ca3d489169d9c310259f Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:36:12 +0530 Subject: [PATCH 4/5] test: keep high-signal regression coverage --- src/local-agent-presentation.test.ts | 17 ++++++++++++++--- src/server.test.ts | 15 +++++++++++---- tsconfig.build.json | 2 +- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/local-agent-presentation.test.ts b/src/local-agent-presentation.test.ts index c85418656..afaeaedcc 100644 --- a/src/local-agent-presentation.test.ts +++ b/src/local-agent-presentation.test.ts @@ -2,21 +2,32 @@ import assert from "node:assert/strict"; import type { LocalAgentCatalog } from "./local-agent-catalog.js"; import { presentAgentObservation, + presentAgentReceipt, presentAgentTargetCatalog, } from "./local-agent-presentation.js"; import type { LocalAgentRecord } from "./local-agent-store.js"; -const failed: LocalAgentRecord = { +const starting: LocalAgentRecord = { id: "agt_test", workspaceRoot: "/private/project", profileName: "reviewer", provider: "codex", + status: "starting", + createdAt: "2026-08-21T10:00:00.000Z", + updatedAt: "2026-08-21T10:01:00.000Z", +}; + +assert.deepEqual(presentAgentReceipt(starting), { + id: "agt_test", + status: "running", +}); + +const failed: LocalAgentRecord = { + ...starting, status: "error", error: "Provider disconnected.", errorCode: "PROVIDER_EXECUTION_ERROR", errorRetryable: true, - createdAt: "2026-08-21T10:00:00.000Z", - updatedAt: "2026-08-21T10:01:00.000Z", }; assert.deepEqual(presentAgentObservation(failed), { diff --git a/src/server.test.ts b/src/server.test.ts index 5e01dcbf1..0751fb453 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -491,17 +491,24 @@ test("open_workspace scopes checkout reuse to OpenAI session metadata", async (t const repeated = await callOpen(context.client, context.project, "chat-1"); const otherSession = await callOpen(context.client, context.project, "chat-2"); const unscoped = await callOpen(context.client, context.project); - const emptySession = await callOpen(context.client, context.project, ""); - const malformedSession = await callOpen(context.client, context.project, 42); assert.equal(structuredContent(repeated).workspace_id, structuredContent(first).workspace_id); assert.equal(structuredContent(repeated).agents_files, undefined); assert.notEqual(structuredContent(otherSession).workspace_id, structuredContent(first).workspace_id); assert.notEqual(structuredContent(unscoped).workspace_id, structuredContent(first).workspace_id); - assert.notEqual(structuredContent(emptySession).workspace_id, structuredContent(first).workspace_id); - assert.notEqual(structuredContent(malformedSession).workspace_id, structuredContent(first).workspace_id); assert.ok(Array.isArray(structuredContent(otherSession).agents_files)); assert.ok(Array.isArray(structuredContent(unscoped).agents_files)); + + for (const malformedSession of ["", 42, {}]) { + const firstMalformed = await callOpen(context.client, context.project, malformedSession); + const repeatedMalformed = await callOpen(context.client, context.project, malformedSession); + assert.notEqual( + structuredContent(repeatedMalformed).workspace_id, + structuredContent(firstMalformed).workspace_id, + ); + assert.ok(Array.isArray(structuredContent(firstMalformed).agents_files)); + assert.ok(Array.isArray(structuredContent(repeatedMalformed).agents_files)); + } }); test("HTTP endpoint serves modern MCP and stateless legacy clients", async (t) => { diff --git a/tsconfig.build.json b/tsconfig.build.json index a48941b6a..94435e351 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,4 +1,4 @@ { "extends": "./tsconfig.json", - "exclude": ["src/ui/**/*", "src/**/*.test.ts"] + "exclude": ["src/ui/**/*", "src/test-support/**/*", "src/**/*.test.ts"] } From bd743dbf1d1a60df1fa6d2a15371d23166d52b74 Mon Sep 17 00:00:00 2001 From: Waishnav <86405648+Waishnav@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:46:35 +0530 Subject: [PATCH 5/5] test: cover unavailable provider filtering --- src/server.test.ts | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/server.test.ts b/src/server.test.ts index 0751fb453..888ebc30d 100644 --- a/src/server.test.ts +++ b/src/server.test.ts @@ -386,11 +386,17 @@ test("open_workspace keeps lifecycle flags out of model output and preserves com test("open_workspace refreshes provider availability for each catalog", async (t) => { let available = false; const context = await fixture(t, { - localAgentProviders: () => [{ name: "codex", available }], + localAgentProviders: () => [ + { name: "codex", available }, + { name: "claude", available: false }, + ], subagents: { enabled: true, instructions: "on-demand", - providers: [{ id: "codex", enabled: true, model: "gpt-default", effort: "medium" }], + providers: [ + { id: "codex", enabled: true, model: "gpt-default", effort: "medium" }, + { id: "claude", enabled: true }, + ], }, }); await writeFile(join(context.project, ".devspace", "agents", "custom.md"), [ @@ -402,6 +408,14 @@ test("open_workspace refreshes provider availability for each catalog", async (t "---", "Inspect.", ].join("\n")); + await writeFile(join(context.project, ".devspace", "agents", "claude-reviewer.md"), [ + "---", + "name: claude-reviewer", + "description: Uses an unavailable provider.", + "provider: claude", + "---", + "Review with Claude.", + ].join("\n")); const unavailable = structuredContent(await callOpen(context.client, context.project, "chat-1")); assert.deepEqual(unavailable.agent_providers, []); @@ -409,9 +423,9 @@ test("open_workspace refreshes provider availability for each catalog", async (t available = true; const usable = structuredContent(await callOpen(context.client, context.project, "chat-2")); - assert.equal( - (usable.agent_providers as Array>)[0]?.id, - "codex", + assert.deepEqual( + (usable.agent_providers as Array>).map((provider) => provider.id), + ["codex"], ); const provider = (usable.agent_providers as Array>)[0]; assert.deepEqual( @@ -433,6 +447,7 @@ test("open_workspace refreshes provider availability for each catalog", async (t model: "gpt-custom", effort: "medium", }); + assert.deepEqual(agents.map((agent) => agent.name).sort(), ["custom", "reviewer"]); }); test("open_workspace omits providers disabled by configuration", async (t) => {