From 9842ce38c4b5b0bb0ef17a99cb54c0b40c9ad79a Mon Sep 17 00:00:00 2001 From: murashit Date: Wed, 1 Jul 2026 07:43:35 +0900 Subject: [PATCH] Use panel-owned diagnostic probe ids --- src/app-server/query/cache.ts | 14 +++--- src/app-server/query/metadata-probes.ts | 16 +++---- src/app-server/services/tool-inventory.ts | 14 +++--- src/domain/server/diagnostics.ts | 47 ++++++++++--------- .../chat/app-server/actions/diagnostics.ts | 16 +++---- .../runtime/diagnostic-sections.ts | 10 ++-- .../app-server/app-server-diagnostics.test.ts | 29 +++++------- tests/app-server/query-cache.test.ts | 24 +++++----- tests/app-server/shared-queries.test.ts | 2 +- tests/app-server/tool-inventory.test.ts | 2 +- .../chat/app-server/actions/actions.test.ts | 36 +++++++------- .../runtime/diagnostic-sections.test.ts | 21 +++------ 12 files changed, 111 insertions(+), 120 deletions(-) diff --git a/src/app-server/query/cache.ts b/src/app-server/query/cache.ts index 82d553e8..f60906f5 100644 --- a/src/app-server/query/cache.ts +++ b/src/app-server/query/cache.ts @@ -192,12 +192,12 @@ export class AppServerQueryCache { const probes = metadata.serverDiagnostics.probes; const next = cloneSharedServerMetadata({ ...metadata, - availableModels: probes["model/list"].status === "ok" ? metadata.availableModels : (this.modelsSnapshot(context) ?? []), - availableSkills: probes["skills/list"].status === "ok" ? metadata.availableSkills : (previous?.availableSkills ?? []), - rateLimit: probes["account/rateLimits/read"].status === "ok" ? metadata.rateLimit : (previous?.rateLimit ?? null), + availableModels: probes.models.status === "ok" ? metadata.availableModels : (this.modelsSnapshot(context) ?? []), + availableSkills: probes.skills.status === "ok" ? metadata.availableSkills : (previous?.availableSkills ?? []), + rateLimit: probes.rateLimits.status === "ok" ? metadata.rateLimit : (previous?.rateLimit ?? null), }); this.client.setQueryData(appServerMetadataQueryKey(context), cloneSharedServerMetadata(next)); - if (probes["model/list"].status === "ok") { + if (probes.models.status === "ok") { this.client.setQueryData(appServerModelsQueryKey(context), cloneModelMetadata(next.availableModels)); } return cloneSharedServerMetadata(next); @@ -315,15 +315,15 @@ export class AppServerQueryCache { client: AppServerClient, ): Promise<{ value: readonly ModelMetadata[]; - probe: SharedServerMetadata["serverDiagnostics"]["probes"]["model/list"]; + probe: SharedServerMetadata["serverDiagnostics"]["probes"]["models"]; }> { try { const models = cloneModelMetadata(await this.client.fetchQuery(this.modelsQueryOptionsWithClient(context, client))); - return { value: models, probe: diagnosticProbeOk("model/list", `${String(models.length)} models`, Date.now()) }; + return { value: models, probe: diagnosticProbeOk("models", `${String(models.length)} models`, Date.now()) }; } catch (error) { return { value: this.modelsSnapshot(context) ?? [], - probe: diagnosticProbeError("model/list", error, Date.now()), + probe: diagnosticProbeError("models", error, Date.now()), }; } } diff --git a/src/app-server/query/metadata-probes.ts b/src/app-server/query/metadata-probes.ts index 5ff3b67b..e9cb8b0c 100644 --- a/src/app-server/query/metadata-probes.ts +++ b/src/app-server/query/metadata-probes.ts @@ -11,8 +11,8 @@ interface MetadataProbeResult { probe: Diagnostics["probes"][K]; } -export type SkillMetadataProbeResult = MetadataProbeResult; -export type RateLimitMetadataProbeResult = MetadataProbeResult; +export type SkillMetadataProbeResult = MetadataProbeResult; +export type RateLimitMetadataProbeResult = MetadataProbeResult; export async function readSkillMetadataProbe( client: AppServerRequestClient | null, @@ -20,13 +20,13 @@ export async function readSkillMetadataProbe( forceReload = false, ): Promise { if (!client) { - return { value: [], probe: diagnosticProbeError("skills/list", new Error("Codex app-server is not connected."), Date.now()) }; + return { value: [], probe: diagnosticProbeError("skills", new Error("Codex app-server is not connected."), Date.now()) }; } try { const catalog = await listSkillCatalog(client, vaultPath, { forceReload }); - return { value: catalog.skills, probe: diagnosticProbeOk("skills/list", `${String(catalog.totalCount)} skills`, Date.now()) }; + return { value: catalog.skills, probe: diagnosticProbeOk("skills", `${String(catalog.totalCount)} skills`, Date.now()) }; } catch (error) { - return { value: [], probe: diagnosticProbeError("skills/list", error, Date.now()) }; + return { value: [], probe: diagnosticProbeError("skills", error, Date.now()) }; } } @@ -34,16 +34,16 @@ export async function readRateLimitMetadataProbe(client: AppServerRequestClient if (!client) { return { value: null, - probe: diagnosticProbeError("account/rateLimits/read", new Error("Codex app-server is not connected."), Date.now()), + probe: diagnosticProbeError("rateLimits", new Error("Codex app-server is not connected."), Date.now()), }; } try { const response = await readAccountRateLimits(client); return { value: rateLimitSnapshotFromAccountRateLimitsResponse(response), - probe: diagnosticProbeOk("account/rateLimits/read", accountRateLimitsSummaryFromResponse(response), Date.now()), + probe: diagnosticProbeOk("rateLimits", accountRateLimitsSummaryFromResponse(response), Date.now()), }; } catch (error) { - return { value: null, probe: diagnosticProbeError("account/rateLimits/read", error, Date.now()) }; + return { value: null, probe: diagnosticProbeError("rateLimits", error, Date.now()) }; } } diff --git a/src/app-server/services/tool-inventory.ts b/src/app-server/services/tool-inventory.ts index cd31df3e..5c514d0b 100644 --- a/src/app-server/services/tool-inventory.ts +++ b/src/app-server/services/tool-inventory.ts @@ -65,7 +65,7 @@ function readCachedSkills( return { items: [...skills], error: null, - probe: probe ?? diagnosticProbeOk("skills/list", `${String(skills.length)} skills`, checkedAt), + probe: probe ?? diagnosticProbeOk("skills", `${String(skills.length)} skills`, checkedAt), }; } @@ -86,14 +86,14 @@ async function readPlugins( items: plugins, marketplaceErrors, error: null, - probe: diagnosticProbeOk("plugin/installed", `${String(plugins.length)} plugins`, checkedAt), + probe: diagnosticProbeOk("plugins", `${String(plugins.length)} plugins`, checkedAt), }; } catch (error) { return { items: null, marketplaceErrors: [], error: shortErrorMessage(error), - probe: diagnosticProbeError("plugin/installed", error, checkedAt), + probe: diagnosticProbeError("plugins", error, checkedAt), }; } } @@ -113,13 +113,13 @@ async function readMcpServers( return { items: servers, error: null, - probe: diagnosticProbeOk("mcpServerStatus/list", mcpSummary(servers), checkedAt), + probe: diagnosticProbeOk("mcpServers", mcpSummary(servers), checkedAt), }; } catch (error) { return { items: null, error: shortErrorMessage(error), - probe: diagnosticProbeError("mcpServerStatus/list", error, checkedAt), + probe: diagnosticProbeError("mcpServers", error, checkedAt), }; } } @@ -139,10 +139,10 @@ async function readSkills( return { items: catalog.skills, error: null, - probe: diagnosticProbeOk("skills/list", `${String(catalog.totalCount)} skills`, checkedAt), + probe: diagnosticProbeOk("skills", `${String(catalog.totalCount)} skills`, checkedAt), }; } catch (error) { - return { items: null, error: shortErrorMessage(error), probe: diagnosticProbeError("skills/list", error, checkedAt) }; + return { items: null, error: shortErrorMessage(error), probe: diagnosticProbeError("skills", error, checkedAt) }; } } diff --git a/src/domain/server/diagnostics.ts b/src/domain/server/diagnostics.ts index 541c5882..3fba7838 100644 --- a/src/domain/server/diagnostics.ts +++ b/src/domain/server/diagnostics.ts @@ -2,20 +2,20 @@ import type { ServerInitialization } from "./initialization"; import { type McpServerDiagnostic, type McpServerStatusSummary, mcpServerDiagnosticFromStatus } from "./mcp-status"; import { cloneToolInventorySnapshot, type ToolInventorySnapshot } from "./tool-inventory"; -const DIAGNOSTIC_PROBE_METHODS = [ - "model/list", - "skills/list", - "app/list", - "plugin/installed", - "account/rateLimits/read", - "mcpServerStatus/list", -] as const; +const DIAGNOSTIC_PROBE_DEFINITIONS = { + models: { label: "Models" }, + skills: { label: "Skills" }, + apps: { label: "Apps" }, + plugins: { label: "Plugins" }, + rateLimits: { label: "Rate limits" }, + mcpServers: { label: "MCP servers" }, +} as const; -export type DiagnosticProbeMethod = (typeof DIAGNOSTIC_PROBE_METHODS)[number]; +export type DiagnosticProbeId = keyof typeof DIAGNOSTIC_PROBE_DEFINITIONS; type DiagnosticProbeStatus = "unknown" | "ok" | "failed"; export interface DiagnosticProbeResult { - readonly method: DiagnosticProbeMethod; + readonly id: DiagnosticProbeId; readonly status: DiagnosticProbeStatus; readonly message: string | null; readonly summary: string | null; @@ -23,17 +23,16 @@ export interface DiagnosticProbeResult { } export interface Diagnostics { - readonly probes: Readonly>; + readonly probes: Readonly>; readonly mcpServers: readonly McpServerDiagnostic[]; readonly toolInventory: ToolInventorySnapshot | null; } export function createServerDiagnostics(): Diagnostics { return { - probes: Object.fromEntries(DIAGNOSTIC_PROBE_METHODS.map((method) => [method, createDiagnosticProbeResult(method)])) as Record< - DiagnosticProbeMethod, - DiagnosticProbeResult - >, + probes: Object.fromEntries( + Object.keys(DIAGNOSTIC_PROBE_DEFINITIONS).map((id) => [id, createDiagnosticProbeResult(id as DiagnosticProbeId)]), + ) as Record, mcpServers: [], toolInventory: null, }; @@ -52,7 +51,7 @@ export function diagnosticsWithProbe(diagnostics: Diagnostics, probe: Diagnostic ...diagnostics, probes: { ...diagnostics.probes, - [probe.method]: probe, + [probe.id]: probe, }, }; } @@ -64,9 +63,9 @@ export function diagnosticsWithToolInventory(diagnostics: Diagnostics, toolInven }; } -function createDiagnosticProbeResult(method: DiagnosticProbeMethod): DiagnosticProbeResult { +function createDiagnosticProbeResult(id: DiagnosticProbeId): DiagnosticProbeResult { return { - method, + id, status: "unknown", message: null, summary: null, @@ -74,9 +73,9 @@ function createDiagnosticProbeResult(method: DiagnosticProbeMethod): DiagnosticP }; } -export function diagnosticProbeOk(method: DiagnosticProbeMethod, summary: string | null, checkedAt: number): DiagnosticProbeResult { +export function diagnosticProbeOk(id: DiagnosticProbeId, summary: string | null, checkedAt: number): DiagnosticProbeResult { return { - method, + id, status: "ok", message: null, summary, @@ -84,9 +83,9 @@ export function diagnosticProbeOk(method: DiagnosticProbeMethod, summary: string }; } -export function diagnosticProbeError(method: DiagnosticProbeMethod, error: unknown, checkedAt: number): DiagnosticProbeResult { +export function diagnosticProbeError(id: DiagnosticProbeId, error: unknown, checkedAt: number): DiagnosticProbeResult { return { - method, + id, status: "failed", message: shortErrorMessage(error), summary: null, @@ -94,6 +93,10 @@ export function diagnosticProbeError(method: DiagnosticProbeMethod, error: unkno }; } +export function diagnosticProbeLabel(id: DiagnosticProbeId): string { + return DIAGNOSTIC_PROBE_DEFINITIONS[id].label; +} + export function serverIdentity(initializeResponse: ServerInitialization | null): string { return initializeResponse?.userAgent ?? "(not connected)"; } diff --git a/src/features/chat/app-server/actions/diagnostics.ts b/src/features/chat/app-server/actions/diagnostics.ts index 8801e9a6..84e601f9 100644 --- a/src/features/chat/app-server/actions/diagnostics.ts +++ b/src/features/chat/app-server/actions/diagnostics.ts @@ -4,8 +4,8 @@ import { listModelMetadata } from "../../../../app-server/services/catalog"; import { readToolInventory } from "../../../../app-server/services/tool-inventory"; import { cloneServerDiagnostics, - type DiagnosticProbeMethod, - type Diagnostics, + type DiagnosticProbeId, + type DiagnosticProbeResult, diagnosticProbeError, diagnosticProbeOk, diagnosticsWithProbe, @@ -21,7 +21,7 @@ interface RefreshServerDiagnosticsOptions { } interface DiagnosticProbeSnapshot { - probe: Diagnostics["probes"][DiagnosticProbeMethod]; + probe: DiagnosticProbeResult; } export interface ChatServerDiagnosticsActionsHost extends ChatServerActionsHost { @@ -58,7 +58,7 @@ async function refreshServerDiagnostics( const cachedSkillsProbe = options.forceResourceProbes === true ? undefined - : (metadataSnapshot?.serverDiagnostics.probes["skills/list"] ?? state.connection.serverDiagnostics.probes["skills/list"]); + : (metadataSnapshot?.serverDiagnostics.probes.skills ?? state.connection.serverDiagnostics.probes.skills); const toolInventory = readToolInventory(client, host.vaultPath, { threadId: activeThreadId, mcpDiagnostics: initialDiagnostics.mcpServers, @@ -69,7 +69,7 @@ async function refreshServerDiagnostics( if (options.forceResourceProbes === true && options.appServerMetadataSnapshot !== true) { probes.push( probeDiagnostic( - "model/list", + "models", () => listModelMetadata(client), (models) => `${String(models.length)} models`, ), @@ -108,16 +108,16 @@ function currentMetadataDiagnostics(host: ChatServerDiagnosticsActionsHost): Sha } async function probeDiagnostic( - method: DiagnosticProbeMethod, + id: DiagnosticProbeId, request: () => Promise, summarize: (response: T) => string | null, ): Promise { try { const response = await request(); return { - probe: diagnosticProbeOk(method, summarize(response), Date.now()), + probe: diagnosticProbeOk(id, summarize(response), Date.now()), }; } catch (error) { - return { probe: diagnosticProbeError(method, error, Date.now()) }; + return { probe: diagnosticProbeError(id, error, Date.now()) }; } } diff --git a/src/features/chat/presentation/runtime/diagnostic-sections.ts b/src/features/chat/presentation/runtime/diagnostic-sections.ts index 84a9d19d..3a055610 100644 --- a/src/features/chat/presentation/runtime/diagnostic-sections.ts +++ b/src/features/chat/presentation/runtime/diagnostic-sections.ts @@ -1,9 +1,9 @@ import { CLIENT_VERSION } from "../../../../constants"; -import type { DiagnosticProbeResult, Diagnostics } from "../../../../domain/server/diagnostics"; -import { type DiagnosticProbeMethod, serverIdentity, serverPlatform } from "../../../../domain/server/diagnostics"; +import type { DiagnosticProbeId, DiagnosticProbeResult, Diagnostics } from "../../../../domain/server/diagnostics"; +import { diagnosticProbeLabel, serverIdentity, serverPlatform } from "../../../../domain/server/diagnostics"; import type { ServerInitialization } from "../../../../domain/server/initialization"; -const RUNTIME_CHECK_PROBE_METHODS: readonly DiagnosticProbeMethod[] = ["model/list", "account/rateLimits/read"]; +const RUNTIME_CHECK_PROBE_IDS: readonly DiagnosticProbeId[] = ["models", "rateLimits"]; export interface DiagnosticRow { label: string; @@ -38,7 +38,7 @@ export function appServerDiagnosticSections(input: AppServerDiagnosticSectionsIn }, { title: "Runtime Checks", - rows: RUNTIME_CHECK_PROBE_METHODS.map((method) => diagnosticProbeRow(input.diagnostics.probes[method])), + rows: RUNTIME_CHECK_PROBE_IDS.map((id) => diagnosticProbeRow(input.diagnostics.probes[id])), }, ]; } @@ -46,7 +46,7 @@ export function appServerDiagnosticSections(input: AppServerDiagnosticSectionsIn function diagnosticProbeRow(probe: DiagnosticProbeResult): DiagnosticRow { const detail = probe.message ? ` - ${probe.message}` : probe.summary ? ` (${probe.summary})` : ""; return { - label: probe.method, + label: diagnosticProbeLabel(probe.id), value: `${probe.status}${detail}`, level: probe.status === "failed" ? "error" : probe.status === "unknown" ? "warning" : "normal", }; diff --git a/tests/app-server/app-server-diagnostics.test.ts b/tests/app-server/app-server-diagnostics.test.ts index 40a46fec..751eb7c7 100644 --- a/tests/app-server/app-server-diagnostics.test.ts +++ b/tests/app-server/app-server-diagnostics.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { createServerDiagnostics, diagnosticProbeError, + diagnosticProbeLabel, diagnosticProbeOk, serverIdentity, serverPlatform, @@ -27,43 +28,37 @@ describe("app-server diagnostics", () => { it("creates generic capability probe defaults", () => { const diagnostics = createServerDiagnostics(); - expect(Object.keys(diagnostics.probes)).toEqual([ - "model/list", - "skills/list", - "app/list", - "plugin/installed", - "account/rateLimits/read", - "mcpServerStatus/list", - ]); - expect(diagnostics.probes["model/list"]).toMatchObject({ - method: "model/list", + expect(Object.keys(diagnostics.probes)).toEqual(["models", "skills", "apps", "plugins", "rateLimits", "mcpServers"]); + expect(diagnostics.probes.models).toMatchObject({ + id: "models", status: "unknown", message: null, summary: null, checkedAt: null, }); + expect(diagnosticProbeLabel("models")).toBe("Models"); }); it("classifies ok and failed capability probes", () => { - expect(diagnosticProbeOk("skills/list", "3 skills", 123)).toEqual({ - method: "skills/list", + expect(diagnosticProbeOk("skills", "3 skills", 123)).toEqual({ + id: "skills", status: "ok", message: null, summary: "3 skills", checkedAt: 123, }); - expect(diagnosticProbeError("plugin/installed", new Error("boom"), 456)).toMatchObject({ - method: "plugin/installed", + expect(diagnosticProbeError("plugins", new Error("boom"), 456)).toMatchObject({ + id: "plugins", status: "failed", message: "boom", checkedAt: 456, }); - expect(diagnosticProbeError("model/list", new Error("unknown provider failure"), 792).status).toBe("failed"); + expect(diagnosticProbeError("models", new Error("unknown provider failure"), 792).status).toBe("failed"); }); it("shortens error messages and tracks MCP server diagnostics", () => { - expect(diagnosticProbeError("model/list", "a\n b\t c", 1).message).toBe("a b c"); - expect(diagnosticProbeError("model/list", "x".repeat(200), 1).message).toHaveLength(160); + expect(diagnosticProbeError("models", "a\n b\t c", 1).message).toBe("a b c"); + expect(diagnosticProbeError("models", "x".repeat(200), 1).message).toHaveLength(160); let diagnostics = upsertMcpServerDiagnostic(createServerDiagnostics(), { name: "github", diff --git a/tests/app-server/query-cache.test.ts b/tests/app-server/query-cache.test.ts index 5844b779..c900ad28 100644 --- a/tests/app-server/query-cache.test.ts +++ b/tests/app-server/query-cache.test.ts @@ -39,12 +39,12 @@ describe("AppServerQueryCache", () => { expect(cache.appServerMetadataSnapshot(context)?.availableModels.map((model) => model.model)).toEqual(["gpt-5.6"]); expect(cache.appServerMetadataSnapshot(context)?.availableSkills.map((skill) => skill.name)).toEqual(["writer"]); expect(cache.appServerMetadataSnapshot(context)?.rateLimit?.primary?.usedPercent).toBe(42); - expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes["skills/list"].status).toBe("failed"); - expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes["account/rateLimits/read"].status).toBe("failed"); + expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes.skills.status).toBe("failed"); + expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes.rateLimits.status).toBe("failed"); cache.writeAppServerMetadata(context, metadata({ availableModels: [], modelProbeStatus: "failed" })); expect(cache.appServerMetadataSnapshot(context)?.availableModels.map((model) => model.model)).toEqual(["gpt-5.6"]); - expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes["model/list"].status).toBe("failed"); + expect(cache.appServerMetadataSnapshot(context)?.serverDiagnostics.probes.models.status).toBe("failed"); }); it("does not accept failed metadata resource payloads as cache truth", () => { @@ -65,7 +65,7 @@ describe("AppServerQueryCache", () => { const cached = cache.appServerMetadataSnapshot(context); expect(cached?.runtimeConfig).not.toBeNull(); - expect(cached?.serverDiagnostics.probes["model/list"].status).toBe("failed"); + expect(cached?.serverDiagnostics.probes.models.status).toBe("failed"); expect(cached?.availableModels).toEqual([]); expect(cached?.availableSkills).toEqual([]); expect(cached?.rateLimit).toBeNull(); @@ -192,7 +192,7 @@ describe("AppServerQueryCache", () => { expect(metadata?.availableModels.map((model) => model.model)).toEqual(["gpt-meta"]); expect(metadata?.availableSkills.map((skill) => skill.name)).toEqual(["writer"]); expect(metadata?.rateLimit?.primary?.usedPercent).toBe(64); - expect(metadata?.serverDiagnostics.probes["model/list"].status).toBe("ok"); + expect(metadata?.serverDiagnostics.probes.models.status).toBe("ok"); expect(cache.modelsSnapshot(context)?.map((model) => model.model)).toEqual(["gpt-meta"]); }); @@ -237,7 +237,7 @@ describe("AppServerQueryCache", () => { const metadataSnapshot = await cache.refreshAppServerMetadata(context); expect(metadataSnapshot?.availableModels.map((model) => model.model)).toEqual(["gpt-cached"]); - expect(metadataSnapshot?.serverDiagnostics.probes["model/list"].status).toBe("failed"); + expect(metadataSnapshot?.serverDiagnostics.probes.models.status).toBe("failed"); expect(cache.modelsSnapshot(context)?.map((model) => model.model)).toEqual(["gpt-cached"]); }); @@ -329,20 +329,20 @@ function metadata( diagnostics = diagnosticsWithProbe( diagnostics, overrides.modelProbeStatus === "failed" - ? diagnosticProbeError("model/list", new Error("offline"), 1) - : diagnosticProbeOk("model/list", "1 models", 1), + ? diagnosticProbeError("models", new Error("offline"), 1) + : diagnosticProbeOk("models", "1 models", 1), ); diagnostics = diagnosticsWithProbe( diagnostics, overrides.skillsProbeStatus === "failed" - ? diagnosticProbeError("skills/list", new Error("offline"), 1) - : diagnosticProbeOk("skills/list", "0 skills", 1), + ? diagnosticProbeError("skills", new Error("offline"), 1) + : diagnosticProbeOk("skills", "0 skills", 1), ); diagnostics = diagnosticsWithProbe( diagnostics, overrides.rateLimitProbeStatus === "failed" - ? diagnosticProbeError("account/rateLimits/read", new Error("offline"), 1) - : diagnosticProbeOk("account/rateLimits/read", "available", 1), + ? diagnosticProbeError("rateLimits", new Error("offline"), 1) + : diagnosticProbeOk("rateLimits", "available", 1), ); return { runtimeConfig: overrides.runtimeConfig ?? emptyRuntimeConfigSnapshot(), diff --git a/tests/app-server/shared-queries.test.ts b/tests/app-server/shared-queries.test.ts index 6445f990..71ad29eb 100644 --- a/tests/app-server/shared-queries.test.ts +++ b/tests/app-server/shared-queries.test.ts @@ -194,7 +194,7 @@ function model(modelId: string): ModelMetadata { } function serverMetadata(overrides: Partial = {}): SharedServerMetadata { - const diagnostics = diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("model/list", "0 models", 1)); + const diagnostics = diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("models", "0 models", 1)); return { runtimeConfig: null, availableModels: [], diff --git a/tests/app-server/tool-inventory.test.ts b/tests/app-server/tool-inventory.test.ts index 74ce3ff9..de4d9a7d 100644 --- a/tests/app-server/tool-inventory.test.ts +++ b/tests/app-server/tool-inventory.test.ts @@ -59,7 +59,7 @@ describe("tool inventory", () => { const result = await readToolInventory(client, "/vault"); expect(client.request).not.toHaveBeenCalledWith("app/list", expect.anything()); - expect(result.probes.some((probe) => probe.method === "app/list")).toBe(false); + expect(result.probes.some((probe) => probe.id === "apps")).toBe(false); }); it("preserves plugin order from installed plugin summaries", async () => { diff --git a/tests/features/chat/app-server/actions/actions.test.ts b/tests/features/chat/app-server/actions/actions.test.ts index 7b99a765..c5c6f260 100644 --- a/tests/features/chat/app-server/actions/actions.test.ts +++ b/tests/features/chat/app-server/actions/actions.test.ts @@ -253,10 +253,10 @@ describe("chat app-server actions", () => { rateLimit: rateLimitFixture(), serverDiagnostics: diagnosticsWithProbe( diagnosticsWithProbe( - diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("model/list", "1 models", 1)), - diagnosticProbeOk("skills/list", "1 skills", 1), + diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("models", "1 models", 1)), + diagnosticProbeOk("skills", "1 skills", 1), ), - diagnosticProbeOk("account/rateLimits/read", "available", 1), + diagnosticProbeOk("rateLimits", "available", 1), ), }); const refreshAppServerMetadata = vi.fn<() => Promise>().mockResolvedValue(refreshedMetadata); @@ -289,15 +289,15 @@ describe("chat app-server actions", () => { expect(refreshAppServerMetadata).toHaveBeenCalledOnce(); expect(listMcpServerStatus).toHaveBeenCalledWith({ detail: "toolsAndAuthOnly", limit: 100 }); - expect(stateStore.getState().connection.serverDiagnostics.probes["model/list"]).toMatchObject({ + expect(stateStore.getState().connection.serverDiagnostics.probes.models).toMatchObject({ status: "ok", summary: "1 models", }); - expect(stateStore.getState().connection.serverDiagnostics.probes["skills/list"]).toMatchObject({ + expect(stateStore.getState().connection.serverDiagnostics.probes.skills).toMatchObject({ status: "ok", summary: "1 skills", }); - expect(stateStore.getState().connection.serverDiagnostics.probes["account/rateLimits/read"]).toMatchObject({ + expect(stateStore.getState().connection.serverDiagnostics.probes.rateLimits).toMatchObject({ status: "ok", summary: "available", }); @@ -325,7 +325,7 @@ describe("chat app-server actions", () => { const stateStore = createChatStateStore(chatStateFixture()); const metadataCache = metadataCacheHost({ current: serverMetadataFixture({ - serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("model/list", "cached models", 1)), + serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeOk("models", "cached models", 1)), }), }); const listModels = vi.fn().mockResolvedValue({ data: [modelFixture("gpt-direct")] }); @@ -350,7 +350,7 @@ describe("chat app-server actions", () => { expect(listModels).not.toHaveBeenCalled(); expect(listSkills).not.toHaveBeenCalled(); expect(readAccountRateLimits).not.toHaveBeenCalled(); - expect(stateStore.getState().connection.serverDiagnostics.probes["model/list"]).toMatchObject({ + expect(stateStore.getState().connection.serverDiagnostics.probes.models).toMatchObject({ status: "ok", summary: "cached models", }); @@ -380,7 +380,7 @@ describe("chat app-server actions", () => { expect(listModels).toHaveBeenCalledWith({ includeHidden: false, limit: 100 }); expect(listSkills).toHaveBeenCalledWith({ cwds: ["/vault"], forceReload: false }); expect(readAccountRateLimits).toHaveBeenCalledWith(undefined); - expect(stateStore.getState().connection.serverDiagnostics.probes["model/list"]).toMatchObject({ + expect(stateStore.getState().connection.serverDiagnostics.probes.models).toMatchObject({ status: "ok", summary: "1 models", }); @@ -410,7 +410,7 @@ describe("chat app-server actions", () => { await refreshing; expect(listMcpServerStatus).toHaveBeenCalledWith({ detail: "toolsAndAuthOnly", limit: 100 }); - expect(stateStore.getState().connection.serverDiagnostics.probes["mcpServerStatus/list"].status).toBe("unknown"); + expect(stateStore.getState().connection.serverDiagnostics.probes.mcpServers.status).toBe("unknown"); expect(stateStore.getState().connection.serverDiagnostics.mcpServers).toEqual([]); expect(updateAppServerMetadata).not.toHaveBeenCalled(); }); @@ -438,7 +438,7 @@ describe("chat app-server actions", () => { const stateStore = createChatStateStore(state); const metadata = serverMetadataFixture({ availableModels: modelMetadataFromCatalogModels([modelFixture("gpt-cached")]), - serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeError("model/list", new Error("offline"), 1)), + serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeError("models", new Error("offline"), 1)), }); const controller = createChatServerMetadataActions({ stateStore, @@ -451,7 +451,7 @@ describe("chat app-server actions", () => { await controller.refreshAppServerMetadata(); expect(stateStore.getState().connection.availableModels.map((model) => model.model)).toEqual(["gpt-cached"]); - expect(stateStore.getState().connection.serverDiagnostics.probes["model/list"].status).toBe("failed"); + expect(stateStore.getState().connection.serverDiagnostics.probes.models.status).toBe("failed"); }); it("does not use chat state as a second model source when metadata model refresh fails", async () => { @@ -460,7 +460,7 @@ describe("chat app-server actions", () => { const stateStore = createChatStateStore(state); const metadata = serverMetadataFixture({ availableModels: [], - serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeError("model/list", new Error("offline"), 1)), + serverDiagnostics: diagnosticsWithProbe(createServerDiagnostics(), diagnosticProbeError("models", new Error("offline"), 1)), }); const controller = createChatServerMetadataActions({ stateStore, @@ -473,7 +473,7 @@ describe("chat app-server actions", () => { await controller.refreshAppServerMetadata(); expect(stateStore.getState().connection.availableModels).toEqual([]); - expect(stateStore.getState().connection.serverDiagnostics.probes["model/list"].status).toBe("failed"); + expect(stateStore.getState().connection.serverDiagnostics.probes.models.status).toBe("failed"); }); it("does not apply or publish refreshed skills after the client changes", async () => { @@ -500,7 +500,7 @@ describe("chat app-server actions", () => { await refreshing; expect(listSkills).toHaveBeenCalledWith({ cwds: ["/vault"], forceReload: true }); expect(stateStore.getState().connection.availableSkills).toEqual([]); - expect(stateStore.getState().connection.serverDiagnostics.probes["skills/list"].status).toBe("unknown"); + expect(stateStore.getState().connection.serverDiagnostics.probes.skills.status).toBe("unknown"); expect(updateAppServerMetadata).not.toHaveBeenCalled(); }); @@ -523,7 +523,7 @@ describe("chat app-server actions", () => { expect(listSkills).toHaveBeenCalledWith({ cwds: ["/vault"], forceReload: true }); expect(stateStore.getState().connection.availableSkills).toEqual(previousSkills); - expect(stateStore.getState().connection.serverDiagnostics.probes["skills/list"]).toMatchObject({ status: "failed" }); + expect(stateStore.getState().connection.serverDiagnostics.probes.skills).toMatchObject({ status: "failed" }); }); it("publishes refreshed rate limits from sparse update notifications", async () => { @@ -570,7 +570,7 @@ describe("chat app-server actions", () => { await controller.applyAppServerResourceEvent({ type: "rate-limits-updated", preserveExistingOnFailure: true }); expect(stateStore.getState().connection.rateLimit).toBe(previousRateLimit); - expect(stateStore.getState().connection.serverDiagnostics.probes["account/rateLimits/read"]).toMatchObject({ status: "failed" }); + expect(stateStore.getState().connection.serverDiagnostics.probes.rateLimits).toMatchObject({ status: "failed" }); }); it("does not apply or publish sparse rate limit refreshes after the client changes", async () => { @@ -600,7 +600,7 @@ describe("chat app-server actions", () => { await refreshing; expect(stateStore.getState().connection.rateLimit).toBeNull(); - expect(stateStore.getState().connection.serverDiagnostics.probes["account/rateLimits/read"].status).toBe("unknown"); + expect(stateStore.getState().connection.serverDiagnostics.probes.rateLimits.status).toBe("unknown"); expect(updateAppServerMetadata).not.toHaveBeenCalled(); }); diff --git a/tests/features/chat/presentation/runtime/diagnostic-sections.test.ts b/tests/features/chat/presentation/runtime/diagnostic-sections.test.ts index 80471510..d1824a34 100644 --- a/tests/features/chat/presentation/runtime/diagnostic-sections.test.ts +++ b/tests/features/chat/presentation/runtime/diagnostic-sections.test.ts @@ -23,12 +23,9 @@ function diagnosticsWithToolInventory(inventory: ToolInventorySnapshot) { describe("connection diagnostics", () => { it("formats connection rows and runtime checks for /doctor", () => { let diagnostics = createServerDiagnostics(); - diagnostics = diagnosticsWithProbe(diagnostics, diagnosticProbeOk("model/list", "12 models", 1)); - diagnostics = diagnosticsWithProbe( - diagnostics, - diagnosticProbeError("account/rateLimits/read", new Error("rate limit request failed"), 2), - ); - diagnostics = diagnosticsWithProbe(diagnostics, diagnosticProbeError("skills/list", new Error("unknown method skills/list"), 3)); + diagnostics = diagnosticsWithProbe(diagnostics, diagnosticProbeOk("models", "12 models", 1)); + diagnostics = diagnosticsWithProbe(diagnostics, diagnosticProbeError("rateLimits", new Error("rate limit request failed"), 2)); + diagnostics = diagnosticsWithProbe(diagnostics, diagnosticProbeError("skills", new Error("unknown method skills/list"), 3)); diagnostics = upsertMcpServerDiagnostic(diagnostics, { name: "github", startupStatus: "failed", @@ -59,15 +56,11 @@ describe("connection diagnostics", () => { const rows = sections.flatMap((section) => section.rows); expect(sections.map((section) => section.title)).toEqual(["Process", "Runtime Checks"]); expect(rows.map((row) => `${row.label}: ${row.value}`)).toEqual( - expect.arrayContaining([ - "connection: connected", - "model/list: ok (12 models)", - "account/rateLimits/read: failed - rate limit request failed", - ]), + expect.arrayContaining(["connection: connected", "Models: ok (12 models)", "Rate limits: failed - rate limit request failed"]), ); - expect(rows.find((row) => row.label === "account/rateLimits/read")?.level).toBe("error"); - expect(rows.find((row) => row.label === "skills/list")).toBeUndefined(); - expect(rows.find((row) => row.label === "mcpServerStatus/list")).toBeUndefined(); + expect(rows.find((row) => row.label === "Rate limits")?.level).toBe("error"); + expect(rows.find((row) => row.label === "Skills")).toBeUndefined(); + expect(rows.find((row) => row.label === "MCP servers")).toBeUndefined(); expect(rows.find((row) => row.label === "mcp github")).toBeUndefined(); });