From c9a6f87ddbf5487140c8e04aba7e1cbc54eeba55 Mon Sep 17 00:00:00 2001 From: murashit Date: Wed, 27 May 2026 14:48:26 +0900 Subject: [PATCH] Clarify diagnostics and runtime config labels --- src/features/chat/chat-session-controller.ts | 2 +- src/features/chat/chat-state.ts | 8 +- src/features/chat/diagnostics.ts | 4 +- src/features/chat/view.ts | 16 ++-- src/runtime/state.ts | 4 +- src/runtime/view.ts | 66 +++++++------- tests/features/chat/chat-controller.test.ts | 4 +- tests/features/chat/diagnostics.test.ts | 3 +- tests/runtime/runtime-settings.test.ts | 93 +++++++++++++++----- 9 files changed, 125 insertions(+), 75 deletions(-) diff --git a/src/features/chat/chat-session-controller.ts b/src/features/chat/chat-session-controller.ts index 1aaba72a..867dc671 100644 --- a/src/features/chat/chat-session-controller.ts +++ b/src/features/chat/chat-session-controller.ts @@ -96,7 +96,7 @@ export class ChatSessionController { this.host.state.activeReasoningEffort = response.reasoningEffort; this.host.state.activeServiceTier = reportedServiceTier(response.serviceTier); this.host.state.activeApprovalsReviewer = response.approvalsReviewer; - this.host.state.activeThreadCliVersion = response.thread.cliVersion; + this.host.state.activeThreadCreationCliVersion = response.thread.cliVersion; this.host.state.tokenUsage = null; this.host.state.historyCursor = null; this.host.state.turnDiffs.clear(); diff --git a/src/features/chat/chat-state.ts b/src/features/chat/chat-state.ts index b6ea92f5..7cfef1d3 100644 --- a/src/features/chat/chat-state.ts +++ b/src/features/chat/chat-state.ts @@ -34,7 +34,7 @@ export interface ChatState { activeCollaborationMode: ModeKind; activeServiceTier: ReportedServiceTier | null; activeApprovalsReviewer: ApprovalsReviewer | null; - activeThreadCliVersion: string | null; + activeThreadCreationCliVersion: string | null; appServerDiagnostics: AppServerDiagnostics; requestedModel: RuntimeOverride; requestedReasoningEffort: RuntimeOverride; @@ -79,7 +79,7 @@ export function createChatState(): ChatState { activeCollaborationMode: "default", activeServiceTier: null, activeApprovalsReviewer: null, - activeThreadCliVersion: null, + activeThreadCreationCliVersion: null, appServerDiagnostics: createAppServerDiagnostics(), requestedModel: defaultRuntimeOverride(), requestedReasoningEffort: defaultRuntimeOverride(), @@ -129,7 +129,7 @@ export function clearActiveThreadState(state: ChatState): void { state.activeCollaborationMode = "default"; state.activeServiceTier = null; state.activeApprovalsReviewer = null; - state.activeThreadCliVersion = null; + state.activeThreadCreationCliVersion = null; state.tokenUsage = null; state.historyCursor = null; state.loadingHistory = false; @@ -146,7 +146,7 @@ export function clearConnectionScopedState(state: ChatState): void { state.activeCollaborationMode = "default"; state.activeServiceTier = null; state.activeApprovalsReviewer = null; - state.activeThreadCliVersion = null; + state.activeThreadCreationCliVersion = null; state.rateLimit = null; state.listedThreads = []; state.threadsLoaded = false; diff --git a/src/features/chat/diagnostics.ts b/src/features/chat/diagnostics.ts index 6fb33d84..72c2478c 100644 --- a/src/features/chat/diagnostics.ts +++ b/src/features/chat/diagnostics.ts @@ -20,7 +20,7 @@ export interface ConnectionDiagnosticsInput { connected: boolean; configuredCommand: string; initializeResponse: InitializeResponse | null; - activeThreadCliVersion: string | null; + activeThreadCreationCliVersion: string | null; diagnostics: AppServerDiagnostics; } @@ -36,7 +36,7 @@ export function connectionDiagnosticSections(input: ConnectionDiagnosticsInput): { label: "panel client", value: CLIENT_VERSION }, { label: "platform", value: appServerPlatform(input.initializeResponse) }, { label: "Codex home", value: input.initializeResponse?.codexHome ?? "(not connected)" }, - { label: "active thread CLI", value: input.activeThreadCliVersion ?? "(none)" }, + { label: "thread created by CLI", value: input.activeThreadCreationCliVersion ?? "(none)" }, ], }, { diff --git a/src/features/chat/view.ts b/src/features/chat/view.ts index 609a0075..102026da 100644 --- a/src/features/chat/view.ts +++ b/src/features/chat/view.ts @@ -611,7 +611,7 @@ export class CodexChatView extends ItemView { this.state.activeReasoningEffort = response.reasoningEffort; this.state.activeServiceTier = reportedServiceTier(response.serviceTier); this.state.activeApprovalsReviewer = response.approvalsReviewer; - this.state.activeThreadCliVersion = response.thread.cliVersion; + this.state.activeThreadCreationCliVersion = response.thread.cliVersion; this.state.tokenUsage = null; this.state.displayItems = [this.systemItem("Loading thread...")]; this.state.turnDiffs.clear(); @@ -1077,7 +1077,7 @@ export class CodexChatView extends ItemView { this.state.activeCollaborationMode = "default"; this.state.activeServiceTier = null; this.state.activeApprovalsReviewer = null; - this.state.activeThreadCliVersion = null; + this.state.activeThreadCreationCliVersion = null; this.state.tokenUsage = null; this.state.busy = false; this.state.displayItems = [this.systemItem("Thread restored. Send a message to resume it.")]; @@ -1280,7 +1280,7 @@ export class CodexChatView extends ItemView { autoReviewActive: autoReviewActive(snapshot, config), fastActive: currentServiceTier(snapshot, config) === "fast", runtimeSummary: runtimeSummaryLabel(model, effort), - runtimeTitle: `Model: ${model ?? "(from default)"}; Effort: ${effort ?? "(from default)"}`, + runtimeTitle: `Model: ${model ?? "(Codex default)"}; Effort: ${effort ?? "(Codex default)"}`, runtimeEmphasized: false, context: context ? { ...context, label: compactContextLabel(context.percent, context.label) } : null, rateLimit: limit, @@ -1506,10 +1506,10 @@ export class CodexChatView extends ItemView { const snapshot = this.runtimeSnapshot(); const config = readRuntimeConfig(this.state.effectiveConfig); return [ - `Model: ${currentModel(snapshot, config) ?? "(from default)"}`, + `Model: ${currentModel(snapshot, config) ?? "(Codex default)"}`, `Override: ${runtimeOverrideLabel(this.state.requestedModel)}`, - `Provider: ${statusValue(config.modelProvider, "(from default)")}`, - `Effort: ${currentReasoningEffort(snapshot, config) ?? "(from default)"}`, + `Provider: ${statusValue(config.modelProvider, "(Codex default)")}`, + `Effort: ${currentReasoningEffort(snapshot, config) ?? "(Codex default)"}`, `Mode: ${this.collaborationModeLabel()}`, `Service tier: ${serviceTierLabel(snapshot, config)}`, ]; @@ -1519,7 +1519,7 @@ export class CodexChatView extends ItemView { const snapshot = this.runtimeSnapshot(); const config = readRuntimeConfig(this.state.effectiveConfig); return [ - `Effort: ${currentReasoningEffort(snapshot, config) ?? "(from default)"}`, + `Effort: ${currentReasoningEffort(snapshot, config) ?? "(Codex default)"}`, `Override: ${runtimeOverrideLabel(this.state.requestedReasoningEffort)}`, `Supported: ${supportedReasoningEfforts(snapshot).join(", ")}`, ]; @@ -1530,7 +1530,7 @@ export class CodexChatView extends ItemView { connected: this.connection.isConnected(), configuredCommand: this.plugin.settings.codexPath, initializeResponse: this.state.initializeResponse, - activeThreadCliVersion: this.state.activeThreadCliVersion, + activeThreadCreationCliVersion: this.state.activeThreadCreationCliVersion, diagnostics: this.state.appServerDiagnostics, }); } diff --git a/src/runtime/state.ts b/src/runtime/state.ts index 5d780faa..9b17d5a8 100644 --- a/src/runtime/state.ts +++ b/src/runtime/state.ts @@ -116,7 +116,7 @@ export function serviceTierLabel( snapshot: RuntimeSnapshot, config: RuntimeConfigProjection = readRuntimeConfig(snapshot.effectiveConfig), ): string { - return currentServiceTier(snapshot, config) ?? "(not reported)"; + return currentServiceTier(snapshot, config) ?? "(Codex default)"; } export function fastModeLabel( @@ -127,7 +127,7 @@ export function fastModeLabel( if (serviceTier === "fast") return "on"; if (serviceTier === "standard") return "off"; if (serviceTier) return `unknown (${serviceTier})`; - return "not reported"; + return "Codex default"; } export function defaultRuntimeOverride(): RuntimeOverride { diff --git a/src/runtime/view.ts b/src/runtime/view.ts index 17a746bc..3acfff57 100644 --- a/src/runtime/view.ts +++ b/src/runtime/view.ts @@ -41,6 +41,9 @@ export interface EffectiveConfigSection { rows: { key: string; value: string }[]; } +const CODEX_DEFAULT_LABEL = "(Codex default)"; +const NOT_REPORTED_LABEL = "(not reported)"; + export function contextSummary(snapshot: RuntimeSnapshot): ContextSummary | null { const usage = snapshot.tokenUsage; const config = readRuntimeConfig(snapshot.effectiveConfig); @@ -109,31 +112,34 @@ export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: st rows: [ { key: "cwd", value: vaultPath }, { key: "profile", value: config.profile ?? "(default)" }, - { key: "model provider", value: stringValue(config.modelProvider, "(from default)") }, + { key: "model provider", value: stringValue(config.modelProvider, CODEX_DEFAULT_LABEL) }, ], }, { title: "Runtime", rows: [ - { key: "model", value: currentModel(snapshot, config) ?? "(from default)" }, - { key: "config model", value: configuredModel(snapshot, config) ?? "(not reported)" }, - { key: "model change", value: runtimeOverrideLabel(snapshot.requestedModel) }, - { key: "effort", value: currentReasoningEffort(snapshot, config) ?? "(from default)" }, - { key: "config effort", value: configuredReasoningEffort(snapshot, config) ?? "(not reported)" }, - { key: "effort change", value: runtimeOverrideLabel(snapshot.requestedReasoningEffort) }, - { key: "reasoning summary", value: stringValue(config.reasoningSummary, "(from default)") }, - { key: "verbosity", value: stringValue(config.verbosity, "(from default)") }, - { key: "mode", value: snapshot.activeCollaborationMode === "plan" ? "Plan" : "Default" }, + { key: "effective model", value: currentModel(snapshot, config) ?? CODEX_DEFAULT_LABEL }, + { key: "configured model", value: configuredModel(snapshot, config) ?? NOT_REPORTED_LABEL }, + { key: "thread model", value: activeRuntimeValueLabel(snapshot.activeModel) }, + { key: "requested model", value: runtimeOverrideLabel(snapshot.requestedModel) }, + { key: "effective effort", value: currentReasoningEffort(snapshot, config) ?? CODEX_DEFAULT_LABEL }, + { key: "configured effort", value: configuredReasoningEffort(snapshot, config) ?? NOT_REPORTED_LABEL }, + { key: "thread effort", value: activeRuntimeValueLabel(snapshot.activeReasoningEffort) }, + { key: "requested effort", value: runtimeOverrideLabel(snapshot.requestedReasoningEffort) }, + { key: "reasoning summary", value: stringValue(config.reasoningSummary, CODEX_DEFAULT_LABEL) }, + { key: "verbosity", value: stringValue(config.verbosity, CODEX_DEFAULT_LABEL) }, + { key: "effective mode", value: snapshot.activeCollaborationMode === "plan" ? "Plan" : "Default" }, { - key: "mode change", + key: "requested mode", value: snapshot.requestedCollaborationMode === snapshot.activeCollaborationMode ? "(none)" : modeLabel(snapshot.requestedCollaborationMode), }, - { key: "service tier", value: serviceTierLabel(snapshot, config) }, - { key: "config service tier", value: config.serviceTier ?? "(not reported)" }, - { key: "active service tier", value: activeRuntimeValueLabel(snapshot.activeServiceTier) }, + { key: "effective service tier", value: serviceTierLabel(snapshot, config) }, + { key: "configured service tier", value: config.serviceTier ?? CODEX_DEFAULT_LABEL }, + { key: "thread service tier", value: activeRuntimeValueLabel(snapshot.activeServiceTier) }, + { key: "requested service tier", value: snapshot.requestedServiceTier ?? "(none)" }, { key: "fast mode", value: fastModeLabel(snapshot, config) }, { key: "context window", value: tokenLimitLabel(config.modelContextWindow) }, { key: "auto compact limit", value: tokenLimitLabel(config.autoCompactTokenLimit) }, @@ -142,26 +148,24 @@ export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: st { title: "Policy", rows: [ - { key: "approval", value: stringValue(config.approvalPolicy, "(from default)") }, - { key: "reviewer", value: currentApprovalsReviewer(snapshot, config) ?? "(not reported)" }, + { key: "approval", value: stringValue(config.approvalPolicy, CODEX_DEFAULT_LABEL) }, + { key: "effective reviewer", value: currentApprovalsReviewer(snapshot, config) ?? NOT_REPORTED_LABEL }, { key: "auto-review", value: autoReviewActive(snapshot, config) ? "on" : "off" }, - { key: "config reviewer", value: config.approvalsReviewer ?? "(from default)" }, - { - key: "active reviewer", - value: activeRuntimeValueLabel(snapshot.activeApprovalsReviewer), - }, - { key: "sandbox", value: stringValue(config.sandboxMode, "(from default)") }, - { key: "workspace network", value: stringValue(config.workspaceNetworkAccess, "(from default)") }, + { key: "configured reviewer", value: config.approvalsReviewer ?? CODEX_DEFAULT_LABEL }, + { key: "thread reviewer", value: activeRuntimeValueLabel(snapshot.activeApprovalsReviewer) }, + { key: "requested reviewer", value: snapshot.requestedApprovalsReviewer ?? "(none)" }, + { key: "sandbox", value: stringValue(config.sandboxMode, CODEX_DEFAULT_LABEL) }, + { key: "workspace network", value: stringValue(config.workspaceNetworkAccess, CODEX_DEFAULT_LABEL) }, { key: "writable roots", value: writableRootsLabel(config.writableRoots) }, - { key: "web search", value: stringValue(config.webSearch, "(from default)") }, + { key: "web search", value: stringValue(config.webSearch, CODEX_DEFAULT_LABEL) }, ], }, { title: "Features", rows: [ - { key: "hooks", value: stringValue(config.hooksEnabled, "(from default)") }, - { key: "apply_patch freeform", value: stringValue(config.applyPatchFreeformEnabled, "(from default)") }, - { key: "tool web search", value: stringValue(config.toolWebSearch, "(from default)") }, + { key: "hooks", value: stringValue(config.hooksEnabled, CODEX_DEFAULT_LABEL) }, + { key: "apply_patch freeform", value: stringValue(config.applyPatchFreeformEnabled, CODEX_DEFAULT_LABEL) }, + { key: "tool web search", value: stringValue(config.toolWebSearch, CODEX_DEFAULT_LABEL) }, { key: "apps", value: enabledAppsLabel(config.apps) }, ], }, @@ -190,7 +194,7 @@ function modeLabel(mode: RuntimeSnapshot["requestedCollaborationMode"]): string } function activeRuntimeValueLabel(value: string | null): string { - return value ?? "(not reported)"; + return value ?? NOT_REPORTED_LABEL; } function rateLimitWindowSummary( @@ -252,11 +256,11 @@ function capitalize(value: string): string { function tokenLimitLabel(value: unknown): string { const tokens = toNumber(value); - return tokens === null ? "(from default)" : formatTokenCount(tokens); + return tokens === null ? CODEX_DEFAULT_LABEL : formatTokenCount(tokens); } function writableRootsLabel(value: unknown): string { - if (!Array.isArray(value)) return "(from default)"; + if (!Array.isArray(value)) return CODEX_DEFAULT_LABEL; if (value.length === 0) return "none"; if (value.length === 1) return String(value[0]); return `${String(value.length)} roots`; @@ -270,7 +274,7 @@ function enabledAppsLabel(apps: unknown): string { .sort(); if (enabled.length > 0) return enabled.join(", "); const defaultConfig = asRecord(appConfig["_default"]); - return stringValue(defaultConfig["enabled"], "(from default)"); + return stringValue(defaultConfig["enabled"], CODEX_DEFAULT_LABEL); } function asRecord(value: unknown): Record { diff --git a/tests/features/chat/chat-controller.test.ts b/tests/features/chat/chat-controller.test.ts index 1e5ebc3c..fd6f0dc0 100644 --- a/tests/features/chat/chat-controller.test.ts +++ b/tests/features/chat/chat-controller.test.ts @@ -845,7 +845,7 @@ describe("ChatController", () => { state.activeTurnId = "turn-active"; state.activeModel = "gpt-5.5"; state.activeServiceTier = "fast"; - state.activeThreadCliVersion = "codex-cli 1.0.0"; + state.activeThreadCreationCliVersion = "codex-cli 1.0.0"; state.tokenUsage = { last: { inputTokens: 1, cachedInputTokens: 0, outputTokens: 2, reasoningOutputTokens: 0, totalTokens: 3 }, total: { inputTokens: 1, cachedInputTokens: 0, outputTokens: 2, reasoningOutputTokens: 0, totalTokens: 3 }, @@ -892,7 +892,7 @@ describe("ChatController", () => { expect(state.activeTurnId).toBeNull(); expect(state.activeModel).toBeNull(); expect(state.activeServiceTier).toBeNull(); - expect(state.activeThreadCliVersion).toBeNull(); + expect(state.activeThreadCreationCliVersion).toBeNull(); expect(state.tokenUsage).toBeNull(); expect(state.historyCursor).toBeNull(); expect(state.loadingHistory).toBe(false); diff --git a/tests/features/chat/diagnostics.test.ts b/tests/features/chat/diagnostics.test.ts index fa513cde..27529349 100644 --- a/tests/features/chat/diagnostics.test.ts +++ b/tests/features/chat/diagnostics.test.ts @@ -37,7 +37,7 @@ describe("connection diagnostics", () => { platformFamily: "unix", platformOs: "macos", }, - activeThreadCliVersion: "0.130.0", + activeThreadCreationCliVersion: "0.130.0", diagnostics, }); @@ -46,6 +46,7 @@ describe("connection diagnostics", () => { expect(rows.map((row) => `${row.label}: ${row.value}`)).toEqual( expect.arrayContaining([ "connection: connected", + "thread created by CLI: 0.130.0", "model/list: ok (12 models)", "skills/list: failed - unknown method skills/list", "mcp docs: ready - auth notLoggedIn", diff --git a/tests/runtime/runtime-settings.test.ts b/tests/runtime/runtime-settings.test.ts index 522f5a77..61773baf 100644 --- a/tests/runtime/runtime-settings.test.ts +++ b/tests/runtime/runtime-settings.test.ts @@ -252,16 +252,19 @@ describe("runtime settings", () => { ); expect(runtimeRows).toMatchObject({ - model: "gpt-5-pending", - "config model": "gpt-5.5", - "model change": "gpt-5-pending", - effort: "low", - "config effort": "high", - "effort change": "(none)", - mode: "Plan", - "mode change": "(none)", - "config service tier": "standard", - "active service tier": "(not reported)", + "effective model": "gpt-5-pending", + "configured model": "gpt-5.5", + "thread model": "gpt-5-active", + "requested model": "gpt-5-pending", + "effective effort": "low", + "configured effort": "high", + "thread effort": "low", + "requested effort": "(none)", + "effective mode": "Plan", + "requested mode": "(none)", + "configured service tier": "standard", + "thread service tier": "(not reported)", + "requested service tier": "(none)", }); const resetSections = effectiveConfigSections( @@ -273,7 +276,43 @@ describe("runtime settings", () => { const resetRuntimeRows = Object.fromEntries( resetSections.find((section) => section.title === "Runtime")?.rows.map((row) => [row.key, row.value]) ?? [], ); - expect(resetRuntimeRows["effort change"]).toBe("(reset to config)"); + expect(resetRuntimeRows["requested effort"]).toBe("(reset to config)"); + }); + + it("labels unset config values as Codex defaults when no concrete value is reported", () => { + const sections = effectiveConfigSections( + runtimeSnapshot({ + effectiveConfig: effectiveConfigFixture({}), + }), + "/vault", + ); + const scopeRows = Object.fromEntries( + sections.find((section) => section.title === "Scope")?.rows.map((row) => [row.key, row.value]) ?? [], + ); + const runtimeRows = Object.fromEntries( + sections.find((section) => section.title === "Runtime")?.rows.map((row) => [row.key, row.value]) ?? [], + ); + const policyRows = Object.fromEntries( + sections.find((section) => section.title === "Policy")?.rows.map((row) => [row.key, row.value]) ?? [], + ); + + expect(scopeRows["model provider"]).toBe("(Codex default)"); + expect(runtimeRows).toMatchObject({ + "effective model": "(Codex default)", + "configured model": "(not reported)", + "thread model": "(not reported)", + "requested model": "(none)", + "configured service tier": "(Codex default)", + "thread service tier": "(not reported)", + "requested service tier": "(none)", + "fast mode": "Codex default", + }); + expect(policyRows).toMatchObject({ + approval: "(Codex default)", + "configured reviewer": "(Codex default)", + sandbox: "(Codex default)", + "web search": "(Codex default)", + }); }); it("shows effective profile runtime and policy values in status details", () => { @@ -307,22 +346,28 @@ describe("runtime settings", () => { expect(scopeRows["profile"]).toBe("auto"); expect(scopeRows["model provider"]).toBe("profile-provider"); expect(runtimeRows).toMatchObject({ - model: "gpt-profile", - "config model": "gpt-profile", - effort: "high", - "config effort": "high", + "effective model": "gpt-profile", + "configured model": "gpt-profile", + "thread model": "(not reported)", + "requested model": "(none)", + "effective effort": "high", + "configured effort": "high", + "thread effort": "(not reported)", + "requested effort": "(none)", "reasoning summary": "detailed", verbosity: "high", - "service tier": "fast", - "config service tier": "fast", - "active service tier": "(not reported)", + "effective service tier": "fast", + "configured service tier": "fast", + "thread service tier": "(not reported)", + "requested service tier": "(none)", "fast mode": "on", }); expect(policyRows["approval"]).toBe("never"); - expect(policyRows["reviewer"]).toBe("auto_review"); + expect(policyRows["effective reviewer"]).toBe("auto_review"); expect(policyRows["auto-review"]).toBe("on"); - expect(policyRows["config reviewer"]).toBe("auto_review"); - expect(policyRows["active reviewer"]).toBe("(not reported)"); + expect(policyRows["configured reviewer"]).toBe("auto_review"); + expect(policyRows["thread reviewer"]).toBe("(not reported)"); + expect(policyRows["requested reviewer"]).toBe("(none)"); expect(policyRows["web search"]).toBe("live"); }); @@ -339,10 +384,10 @@ describe("runtime settings", () => { ); expect(policyRows).toMatchObject({ - reviewer: "guardian_subagent", + "effective reviewer": "guardian_subagent", "auto-review": "on", - "config reviewer": "auto_review", - "active reviewer": "guardian_subagent", + "configured reviewer": "auto_review", + "thread reviewer": "guardian_subagent", }); });