mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Organize status, doctor, and runtime diagnostics
This commit is contained in:
parent
f5f9c5951a
commit
9b1770ee3f
11 changed files with 124 additions and 83 deletions
|
|
@ -9,6 +9,11 @@ export interface DiagnosticRow {
|
|||
level?: "normal" | "warning" | "error";
|
||||
}
|
||||
|
||||
export interface DiagnosticSection {
|
||||
title: string;
|
||||
rows: DiagnosticRow[];
|
||||
}
|
||||
|
||||
export type DiagnosticAlertLevel = "normal" | "warning" | "error";
|
||||
|
||||
export interface ConnectionDiagnosticsInput {
|
||||
|
|
@ -19,24 +24,32 @@ export interface ConnectionDiagnosticsInput {
|
|||
diagnostics: AppServerDiagnostics;
|
||||
}
|
||||
|
||||
export function connectionDiagnosticRows(input: ConnectionDiagnosticsInput): DiagnosticRow[] {
|
||||
export function connectionDiagnosticSections(input: ConnectionDiagnosticsInput): DiagnosticSection[] {
|
||||
const mcpRows = mcpServerDiagnosticRows(input.diagnostics.mcpServers);
|
||||
return [
|
||||
{ label: "connection", value: input.connected ? "connected" : "offline" },
|
||||
{ label: "configured command", value: input.configuredCommand },
|
||||
{ label: "running app-server", value: appServerIdentity(input.initializeResponse) },
|
||||
{ label: "panel client", value: CLIENT_VERSION },
|
||||
{ label: "platform", value: appServerPlatform(input.initializeResponse) },
|
||||
{ label: "codexHome", value: input.initializeResponse?.codexHome ?? "(not connected)" },
|
||||
{ label: "active thread CLI", value: input.activeThreadCliVersion ?? "(none)" },
|
||||
...CAPABILITY_PROBE_METHODS.map((method) => capabilityDiagnosticRow(input.diagnostics.probes[method])),
|
||||
...mcpServerDiagnosticRows(input.diagnostics.mcpServers),
|
||||
{
|
||||
title: "Process",
|
||||
rows: [
|
||||
{ label: "connection", value: input.connected ? "connected" : "offline" },
|
||||
{ label: "configured command", value: input.configuredCommand },
|
||||
{ label: "running app-server", value: appServerIdentity(input.initializeResponse) },
|
||||
{ label: "panel client", value: CLIENT_VERSION },
|
||||
{ label: "platform", value: appServerPlatform(input.initializeResponse) },
|
||||
{ label: "codexHome", value: input.initializeResponse?.codexHome ?? "(not connected)" },
|
||||
{ label: "active thread CLI", value: input.activeThreadCliVersion ?? "(none)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Capabilities",
|
||||
rows: CAPABILITY_PROBE_METHODS.map((method) => capabilityDiagnosticRow(input.diagnostics.probes[method])),
|
||||
},
|
||||
{
|
||||
title: "MCP issues",
|
||||
rows: mcpRows.length > 0 ? mcpRows : [{ label: "issues", value: "(none)" }],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function connectionDiagnosticLines(rows: DiagnosticRow[]): string[] {
|
||||
return ["Connection diagnostics", ...rows.map((row) => `${row.label}: ${row.value}`)];
|
||||
}
|
||||
|
||||
export function diagnosticAlertLevel(diagnostics: AppServerDiagnostics): DiagnosticAlertLevel {
|
||||
let hasWarning = false;
|
||||
for (const probe of Object.values(diagnostics.probes)) {
|
||||
|
|
@ -52,7 +65,7 @@ export function diagnosticAlertLevel(diagnostics: AppServerDiagnostics): Diagnos
|
|||
function capabilityDiagnosticRow(probe: CapabilityProbeResult): DiagnosticRow {
|
||||
const detail = probe.message ? ` - ${probe.message}` : probe.summary ? ` (${probe.summary})` : "";
|
||||
return {
|
||||
label: `capability ${probe.method}`,
|
||||
label: probe.method,
|
||||
value: `${probe.status}${detail}`,
|
||||
level: capabilityLevel(probe.status),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export interface SlashCommandExecutionContext {
|
|||
setRequestedModel: (model: string | null) => void | Promise<void>;
|
||||
setRequestedReasoningEffort: (effort: ReasoningEffort | null) => void | Promise<void>;
|
||||
statusSummaryLines: () => string[];
|
||||
connectionDiagnosticLines: () => string[];
|
||||
connectionDiagnosticDetails: () => DisplayDetailSection[];
|
||||
mcpStatusLines: () => Promise<string[]>;
|
||||
modelStatusLines: () => string[];
|
||||
effortStatusLines: () => string[];
|
||||
|
|
@ -181,7 +181,7 @@ export async function executeSlashCommand(
|
|||
}
|
||||
|
||||
if (command === "doctor") {
|
||||
context.addStructuredSystemMessage("Connection diagnostics", detailsFromLines(context.connectionDiagnosticLines()));
|
||||
context.addStructuredSystemMessage("Connection diagnostics", context.connectionDiagnosticDetails());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import {
|
|||
nextCollaborationMode,
|
||||
} from "../runtime/collaboration-mode";
|
||||
import { PanelController } from "./controller";
|
||||
import { connectionDiagnosticLines, connectionDiagnosticRows, diagnosticAlertLevel } from "./diagnostics";
|
||||
import { connectionDiagnosticSections, diagnosticAlertLevel } from "./diagnostics";
|
||||
import { rollbackCandidateFromItems } from "./rollback";
|
||||
import { contextSummary, effectiveConfigSections, rateLimitSummary } from "../runtime/view";
|
||||
import {
|
||||
|
|
@ -547,7 +547,7 @@ export class CodexPanelView extends ItemView {
|
|||
setRequestedModel: (model) => this.setRequestedModel(model),
|
||||
setRequestedReasoningEffort: (effort) => this.setRequestedReasoningEffort(effort),
|
||||
statusSummaryLines: () => this.statusSummaryLines(),
|
||||
connectionDiagnosticLines: () => this.connectionDiagnosticLines(),
|
||||
connectionDiagnosticDetails: () => this.connectionDiagnosticDetails(),
|
||||
mcpStatusLines: () => this.mcpStatusLines(),
|
||||
modelStatusLines: () => this.modelStatusLines(),
|
||||
effortStatusLines: () => this.effortStatusLines(),
|
||||
|
|
@ -864,7 +864,7 @@ export class CodexPanelView extends ItemView {
|
|||
modelChoices: this.modelToolbarChoices(),
|
||||
effortChoices: this.effortToolbarChoices(),
|
||||
connectLabel: this.connection.isConnected() ? "Reconnect" : "Connect",
|
||||
diagnostics: this.connectionDiagnosticRows(),
|
||||
diagnostics: this.connectionDiagnosticSections(),
|
||||
diagnosticAlertLevel: diagnosticAlertLevel(this.state.appServerDiagnostics),
|
||||
};
|
||||
}
|
||||
|
|
@ -1026,8 +1026,8 @@ export class CodexPanelView extends ItemView {
|
|||
];
|
||||
}
|
||||
|
||||
private connectionDiagnosticRows() {
|
||||
return connectionDiagnosticRows({
|
||||
private connectionDiagnosticSections() {
|
||||
return connectionDiagnosticSections({
|
||||
connected: this.connection.isConnected(),
|
||||
configuredCommand: this.plugin.settings.codexPath,
|
||||
initializeResponse: this.state.initializeResponse,
|
||||
|
|
@ -1036,8 +1036,11 @@ export class CodexPanelView extends ItemView {
|
|||
});
|
||||
}
|
||||
|
||||
private connectionDiagnosticLines(): string[] {
|
||||
return connectionDiagnosticLines(this.connectionDiagnosticRows());
|
||||
private connectionDiagnosticDetails(): DisplayDetailSection[] {
|
||||
return this.connectionDiagnosticSections().map((section) => ({
|
||||
title: section.title,
|
||||
rows: section.rows.map((row) => ({ key: row.label, value: row.value })),
|
||||
}));
|
||||
}
|
||||
|
||||
private async mcpStatusLines(): Promise<string[]> {
|
||||
|
|
|
|||
|
|
@ -35,9 +35,6 @@ export interface RuntimeSnapshot {
|
|||
|
||||
export interface TurnRuntimeSettings {
|
||||
collaborationMode: CollaborationMode | null;
|
||||
model: string | null | undefined;
|
||||
effort: ReasoningEffort | null | undefined;
|
||||
approvalsReviewer: ApprovalsReviewer | undefined;
|
||||
warning: string | null;
|
||||
}
|
||||
|
||||
|
|
@ -98,9 +95,6 @@ export function requestedTurnRuntimeSettings(snapshot: RuntimeSnapshot): TurnRun
|
|||
: null;
|
||||
return {
|
||||
collaborationMode,
|
||||
model: runtimeOverridePayload(snapshot.requestedModel),
|
||||
effort: runtimeOverridePayload(snapshot.requestedReasoningEffort),
|
||||
approvalsReviewer: snapshot.requestedApprovalsReviewer ?? undefined,
|
||||
warning: model ? null : "No effective model is available. Sending without a mode override.",
|
||||
};
|
||||
}
|
||||
|
|
@ -140,10 +134,6 @@ export function resetRuntimeOverride<T>(): RuntimeOverride<T> {
|
|||
return { kind: "resetPending" };
|
||||
}
|
||||
|
||||
export function commitRuntimeOverride<T>(override: RuntimeOverride<T>): RuntimeOverride<T> {
|
||||
return override.kind === "resetPending" ? defaultRuntimeOverride<T>() : override;
|
||||
}
|
||||
|
||||
export function runtimeOverridePayload<T>(override: RuntimeOverride<T>): T | null | undefined {
|
||||
if (override.kind === "set") return override.value;
|
||||
if (override.kind === "resetPending") return null;
|
||||
|
|
@ -152,8 +142,8 @@ export function runtimeOverridePayload<T>(override: RuntimeOverride<T>): T | nul
|
|||
|
||||
export function runtimeOverrideLabel<T>(override: RuntimeOverride<T>): string {
|
||||
if (override.kind === "set") return String(override.value);
|
||||
if (override.kind === "resetPending") return "(reset pending)";
|
||||
return "(default)";
|
||||
if (override.kind === "resetPending") return "(reset to config)";
|
||||
return "(none)";
|
||||
}
|
||||
|
||||
function configuredServiceTier(config: Record<string, unknown>): ServiceTier | null {
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import {
|
|||
currentModel,
|
||||
currentReasoningEffort,
|
||||
fastModeLabel,
|
||||
runtimeOverrideLabel,
|
||||
serviceTierLabel,
|
||||
type RuntimeOverride,
|
||||
type RuntimeSnapshot,
|
||||
} from "./state";
|
||||
|
||||
|
|
@ -118,10 +118,10 @@ export function effectiveConfigSections(snapshot: RuntimeSnapshot, vaultPath: st
|
|||
rows: [
|
||||
{ key: "model", value: currentModel(snapshot, config) ?? "(from default)" },
|
||||
{ key: "config model", value: configuredModel(snapshot, config) ?? "(not reported)" },
|
||||
{ key: "model change", value: pendingRuntimeChangeLabel(snapshot.requestedModel) },
|
||||
{ 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: pendingRuntimeChangeLabel(snapshot.requestedReasoningEffort) },
|
||||
{ key: "effort change", value: runtimeOverrideLabel(snapshot.requestedReasoningEffort) },
|
||||
{ key: "reasoning summary", value: stringValue(config.model_reasoning_summary, "(from default)") },
|
||||
{ key: "verbosity", value: stringValue(config.model_verbosity, "(from default)") },
|
||||
{ key: "mode", value: snapshot.activeCollaborationMode === "plan" ? "Plan" : "Default" },
|
||||
|
|
@ -184,12 +184,6 @@ function modeLabel(mode: RuntimeSnapshot["requestedCollaborationMode"]): string
|
|||
return mode === "plan" ? "Plan" : "Default";
|
||||
}
|
||||
|
||||
function pendingRuntimeChangeLabel<T>(override: RuntimeOverride<T>): string {
|
||||
if (override.kind === "set") return String(override.value);
|
||||
if (override.kind === "resetPending") return "(reset to config)";
|
||||
return "(none)";
|
||||
}
|
||||
|
||||
function rateLimitWindowSummary(
|
||||
fallbackLabel: string,
|
||||
window: RateLimitWindow | null,
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ export interface ToolbarDiagnosticRow {
|
|||
level?: "normal" | "warning" | "error";
|
||||
}
|
||||
|
||||
export interface ToolbarDiagnosticSection {
|
||||
title: string;
|
||||
rows: ToolbarDiagnosticRow[];
|
||||
}
|
||||
|
||||
export interface ToolbarViewModel {
|
||||
connected: boolean;
|
||||
status: string;
|
||||
|
|
@ -57,7 +62,7 @@ export interface ToolbarViewModel {
|
|||
modelChoices: ToolbarChoice[];
|
||||
effortChoices: ToolbarChoice[];
|
||||
connectLabel: string;
|
||||
diagnostics: ToolbarDiagnosticRow[];
|
||||
diagnostics: ToolbarDiagnosticSection[];
|
||||
diagnosticAlertLevel: ToolbarDiagnosticAlertLevel;
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +114,10 @@ export function toolbarSignature(model: ToolbarViewModel): string {
|
|||
modelChoices: model.modelChoices.map((choice) => `${choice.label}:${choice.selected}:${choice.disabled}:${choice.meta ?? ""}`),
|
||||
effortChoices: model.effortChoices.map((choice) => `${choice.label}:${choice.selected}:${choice.disabled}:${choice.meta ?? ""}`),
|
||||
connectLabel: model.connectLabel,
|
||||
diagnostics: model.diagnostics.map((row) => `${row.label}:${row.value}:${row.level ?? "normal"}`),
|
||||
diagnostics: model.diagnostics.map((section) => ({
|
||||
title: section.title,
|
||||
rows: section.rows.map((row) => `${row.label}:${row.value}:${row.level ?? "normal"}`),
|
||||
})),
|
||||
diagnosticAlertLevel: model.diagnosticAlertLevel,
|
||||
});
|
||||
}
|
||||
|
|
@ -282,16 +290,19 @@ function renderRateLimitPanel(parent: HTMLElement, rateLimit: RateLimitSummary |
|
|||
}
|
||||
}
|
||||
|
||||
function renderConnectionDiagnostics(parent: HTMLElement, rows: ToolbarDiagnosticRow[]): void {
|
||||
function renderConnectionDiagnostics(parent: HTMLElement, sections: ToolbarDiagnosticSection[]): void {
|
||||
const diagnostics = parent.createDiv({ cls: "codex-panel__connection-diagnostics" });
|
||||
diagnostics.createDiv({ cls: "codex-panel__connection-diagnostics-title", text: "Connection diagnostics" });
|
||||
const list = diagnostics.createEl("dl", { cls: "codex-panel__connection-diagnostics-list" });
|
||||
for (const row of rows) {
|
||||
const item = list.createDiv({
|
||||
cls: `codex-panel__connection-diagnostics-row codex-panel__connection-diagnostics-row--${row.level ?? "normal"}`,
|
||||
});
|
||||
item.createEl("dt", { text: row.label });
|
||||
item.createEl("dd", { text: row.value });
|
||||
diagnostics.createDiv({ cls: "codex-panel__connection-diagnostics-title", text: "Connection" });
|
||||
for (const section of sections) {
|
||||
diagnostics.createDiv({ cls: "codex-panel__connection-diagnostics-section", text: section.title });
|
||||
const list = diagnostics.createEl("dl", { cls: "codex-panel__connection-diagnostics-list" });
|
||||
for (const row of section.rows) {
|
||||
const item = list.createDiv({
|
||||
cls: `codex-panel__connection-diagnostics-row codex-panel__connection-diagnostics-row--${row.level ?? "normal"}`,
|
||||
});
|
||||
item.createEl("dt", { text: row.label });
|
||||
item.createEl("dd", { text: row.value });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
15
styles.css
15
styles.css
|
|
@ -560,6 +560,18 @@
|
|||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-section {
|
||||
padding: 6px 8px 2px;
|
||||
color: var(--text-faint);
|
||||
font-size: var(--font-ui-smaller);
|
||||
font-weight: var(--font-semibold);
|
||||
line-height: var(--line-height-tight);
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-title + .codex-panel__connection-diagnostics-section {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-list {
|
||||
margin: 0;
|
||||
cursor: text;
|
||||
|
|
@ -568,7 +580,7 @@
|
|||
|
||||
.codex-panel__connection-diagnostics-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(96px, 36%) minmax(0, 1fr);
|
||||
grid-template-columns: minmax(0, 36%) minmax(0, 1fr);
|
||||
gap: var(--codex-panel-section-gap);
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
|
@ -583,6 +595,7 @@
|
|||
|
||||
.codex-panel__connection-diagnostics-row dt {
|
||||
color: var(--text-faint);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.codex-panel__connection-diagnostics-row dd {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ function context(overrides: Partial<SlashCommandExecutionContext> = {}): SlashCo
|
|||
setRequestedModel: vi.fn(),
|
||||
setRequestedReasoningEffort: vi.fn(),
|
||||
statusSummaryLines: () => ["status"],
|
||||
connectionDiagnosticLines: () => ["doctor"],
|
||||
connectionDiagnosticDetails: () => [{ title: "Process", rows: [{ key: "connection", value: "connected" }] }],
|
||||
mcpStatusLines: vi.fn().mockResolvedValue(["mcp"]),
|
||||
modelStatusLines: () => ["model"],
|
||||
effortStatusLines: () => ["effort"],
|
||||
|
|
@ -322,6 +322,16 @@ describe("slash commands", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it("shows doctor diagnostics as shared structured sections", async () => {
|
||||
const details = [{ title: "Process", rows: [{ key: "connection", value: "connected" }] }];
|
||||
const ctx = context({ connectionDiagnosticDetails: () => details });
|
||||
|
||||
await executeSlashCommand("doctor", "", ctx);
|
||||
|
||||
expect(ctx.addSystemMessage).not.toHaveBeenCalled();
|
||||
expect(ctx.addStructuredSystemMessage).toHaveBeenCalledWith("Connection diagnostics", details);
|
||||
});
|
||||
|
||||
it("documents that /plan can take a message", () => {
|
||||
expect(slashCommandHelpLines().find((line) => line.startsWith("/plan"))).toBe(
|
||||
"/plan - Toggle Plan mode, optionally sending a message.",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
createAppServerDiagnostics,
|
||||
upsertMcpServerDiagnostic,
|
||||
} from "../../src/app-server/compatibility";
|
||||
import { connectionDiagnosticLines, connectionDiagnosticRows, diagnosticAlertLevel } from "../../src/panel/diagnostics";
|
||||
import { connectionDiagnosticSections, diagnosticAlertLevel } from "../../src/panel/diagnostics";
|
||||
|
||||
describe("connection diagnostics", () => {
|
||||
it("formats base rows, capability probes, and MCP issues for /doctor", () => {
|
||||
|
|
@ -28,7 +28,7 @@ describe("connection diagnostics", () => {
|
|||
message: null,
|
||||
});
|
||||
|
||||
const rows = connectionDiagnosticRows({
|
||||
const sections = connectionDiagnosticSections({
|
||||
connected: true,
|
||||
configuredCommand: "/opt/homebrew/bin/codex",
|
||||
initializeResponse: {
|
||||
|
|
@ -41,18 +41,22 @@ describe("connection diagnostics", () => {
|
|||
diagnostics,
|
||||
});
|
||||
|
||||
const rows = sections.flatMap((section) => section.rows);
|
||||
expect(sections.map((section) => section.title)).toEqual(["Process", "Capabilities", "MCP issues"]);
|
||||
expect(rows.map((row) => `${row.label}: ${row.value}`)).toEqual(
|
||||
expect.arrayContaining([
|
||||
"connection: connected",
|
||||
"capability model/list: ok (12 models)",
|
||||
"capability skills/list: unsupported - unknown method skills/list",
|
||||
"model/list: ok (12 models)",
|
||||
"skills/list: unsupported - unknown method skills/list",
|
||||
"mcp docs: ready - auth notLoggedIn",
|
||||
"mcp github: failed - missing token",
|
||||
]),
|
||||
);
|
||||
expect(rows.find((row) => row.label === "capability skills/list")?.level).toBe("warning");
|
||||
expect(rows.find((row) => row.label === "skills/list")?.level).toBe("warning");
|
||||
expect(rows.find((row) => row.label === "mcp github")?.level).toBe("error");
|
||||
expect(connectionDiagnosticLines(rows)[0]).toBe("Connection diagnostics");
|
||||
expect(sections.find((section) => section.title === "MCP issues")?.rows).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ label: "mcp github", value: "failed - missing token" })]),
|
||||
);
|
||||
});
|
||||
|
||||
it("derives a top-level diagnostic alert without treating unknown or unsupported probes as warnings", () => {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
requestedOrConfiguredServiceTier,
|
||||
requestedTurnRuntimeSettings,
|
||||
resetRuntimeOverride,
|
||||
runtimeOverridePayload,
|
||||
setRuntimeOverride,
|
||||
serviceTierLabel,
|
||||
type RuntimeSnapshot,
|
||||
|
|
@ -61,7 +62,7 @@ describe("runtime settings", () => {
|
|||
expect(compactContextLabel(null, "1.2K tokens")).toBe("1.2K tokens");
|
||||
});
|
||||
|
||||
it("keeps runtime defaults, resets, and turn payload semantics distinct", () => {
|
||||
it("keeps runtime defaults, resets, and collaboration mode semantics distinct", () => {
|
||||
const snapshot = runtimeSnapshot({
|
||||
requestedModel: resetRuntimeOverride(),
|
||||
requestedReasoningEffort: resetRuntimeOverride(),
|
||||
|
|
@ -70,16 +71,16 @@ describe("runtime settings", () => {
|
|||
expect(currentModel(snapshot)).toBe("gpt-5.5");
|
||||
expect(currentReasoningEffort(snapshot)).toBe("high");
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).toMatchObject({
|
||||
model: null,
|
||||
effort: null,
|
||||
collaborationMode: {
|
||||
mode: "default",
|
||||
settings: { model: "gpt-5.5", reasoning_effort: "high" },
|
||||
},
|
||||
});
|
||||
expect(runtimeOverridePayload(snapshot.requestedModel)).toBeNull();
|
||||
expect(runtimeOverridePayload(snapshot.requestedReasoningEffort)).toBeNull();
|
||||
});
|
||||
|
||||
it("serializes explicit runtime overrides as turn payload values", () => {
|
||||
it("uses explicit runtime overrides as current values and settings payload values", () => {
|
||||
const snapshot = runtimeSnapshot({
|
||||
requestedModel: setRuntimeOverride("gpt-5.4"),
|
||||
requestedReasoningEffort: setRuntimeOverride("low"),
|
||||
|
|
@ -87,10 +88,8 @@ describe("runtime settings", () => {
|
|||
|
||||
expect(currentModel(snapshot)).toBe("gpt-5.4");
|
||||
expect(currentReasoningEffort(snapshot)).toBe("low");
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).toMatchObject({
|
||||
model: "gpt-5.4",
|
||||
effort: "low",
|
||||
});
|
||||
expect(runtimeOverridePayload(snapshot.requestedModel)).toBe("gpt-5.4");
|
||||
expect(runtimeOverridePayload(snapshot.requestedReasoningEffort)).toBe("low");
|
||||
});
|
||||
|
||||
it("resolves approval reviewer from requested, active, then effective config", () => {
|
||||
|
|
@ -120,13 +119,12 @@ describe("runtime settings", () => {
|
|||
).toBe("guardian_subagent");
|
||||
});
|
||||
|
||||
it("serializes requested approval reviewer as a turn override", () => {
|
||||
it("resolves requested approval reviewer without adding it to turn runtime settings", () => {
|
||||
const snapshot = runtimeSnapshot({ requestedApprovalsReviewer: "auto_review" });
|
||||
|
||||
expect(autoReviewActive(snapshot)).toBe(true);
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).toMatchObject({
|
||||
approvalsReviewer: "auto_review",
|
||||
});
|
||||
expect(currentApprovalsReviewer(snapshot)).toBe("auto_review");
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).not.toHaveProperty("approvalsReviewer");
|
||||
});
|
||||
|
||||
it("treats active thread runtime as display state without persisting it into turn overrides", () => {
|
||||
|
|
@ -139,13 +137,13 @@ describe("runtime settings", () => {
|
|||
expect(currentModel(snapshot)).toBe("gpt-5-active");
|
||||
expect(currentServiceTier(snapshot)).toBe("fast");
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).toMatchObject({
|
||||
model: undefined,
|
||||
effort: undefined,
|
||||
collaborationMode: {
|
||||
mode: "default",
|
||||
settings: { model: "gpt-5-active" },
|
||||
},
|
||||
});
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).not.toHaveProperty("model");
|
||||
expect(requestedTurnRuntimeSettings(snapshot)).not.toHaveProperty("effort");
|
||||
});
|
||||
|
||||
it("separates effective runtime, config defaults, and pending changes in status details", () => {
|
||||
|
|
|
|||
|
|
@ -1558,7 +1558,10 @@ describe("toolbar renderer decisions", () => {
|
|||
toolbarSignature({ ...baseModel, effortChoices: [...baseModel.effortChoices, { label: "xhigh", onClick: vi.fn() }] }),
|
||||
);
|
||||
expect(toolbarSignature(baseModel)).not.toBe(
|
||||
toolbarSignature({ ...baseModel, diagnostics: [{ label: "compatibility", value: "model/list failed", level: "error" }] }),
|
||||
toolbarSignature({
|
||||
...baseModel,
|
||||
diagnostics: [{ title: "Capabilities", rows: [{ label: "compatibility", value: "model/list failed", level: "error" }] }],
|
||||
}),
|
||||
);
|
||||
expect(toolbarSignature(baseModel)).not.toBe(toolbarSignature({ ...baseModel, autoReviewActive: true }));
|
||||
expect(toolbarSignature(baseModel)).not.toBe(
|
||||
|
|
@ -1628,14 +1631,16 @@ describe("toolbar renderer decisions", () => {
|
|||
statusPanelOpen: true,
|
||||
openPanel: "status",
|
||||
diagnostics: [
|
||||
{ label: "running app-server", value: "codex-cli/1.2.3" },
|
||||
{ label: "compatibility", value: "model/list failed", level: "error" },
|
||||
{ title: "Process", rows: [{ label: "running app-server", value: "codex-cli/1.2.3" }] },
|
||||
{ title: "Capabilities", rows: [{ label: "compatibility", value: "model/list failed", level: "error" }] },
|
||||
],
|
||||
}),
|
||||
toolbarActions({ refreshDiagnostics }),
|
||||
);
|
||||
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-title")?.textContent).toBe("Connection diagnostics");
|
||||
expect(parent.querySelector(".codex-panel__connection-diagnostics-title")?.textContent).toBe("Connection");
|
||||
expect(parent.textContent).toContain("Process");
|
||||
expect(parent.textContent).toContain("Capabilities");
|
||||
expect(parent.textContent).toContain("Effective Codex config");
|
||||
expect(parent.textContent).toContain("Refresh diagnostics");
|
||||
expect(parent.textContent).toContain("codex-cli/1.2.3");
|
||||
|
|
@ -2153,7 +2158,7 @@ function toolbarModel(overrides: Partial<ToolbarViewModel> = {}): ToolbarViewMod
|
|||
modelChoices: [{ label: "Default", selected: true, onClick: vi.fn() }],
|
||||
effortChoices: [{ label: "Default", selected: true, onClick: vi.fn() }],
|
||||
connectLabel: "Reconnect",
|
||||
diagnostics: [{ label: "running app-server", value: "codex-cli/test" }],
|
||||
diagnostics: [{ title: "Process", rows: [{ label: "running app-server", value: "codex-cli/test" }] }],
|
||||
diagnosticAlertLevel: "normal",
|
||||
...overrides,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue