mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Flatten runtime slash command details
This commit is contained in:
parent
b3a770d1b1
commit
37051838a8
5 changed files with 63 additions and 59 deletions
|
|
@ -5,7 +5,7 @@ import { collaborationModeLabel as formatCollaborationModeLabel } from "../domai
|
|||
import { resolveRuntimeControls } from "../domain/runtime/resolution";
|
||||
import type { RuntimeSnapshot } from "../domain/runtime/snapshot";
|
||||
import type { ThreadStreamNoticeSection } from "../domain/thread-stream/items";
|
||||
import { appServerDiagnosticSections } from "../presentation/runtime/diagnostic-sections";
|
||||
import { appServerDiagnosticSections, type DiagnosticRow } from "../presentation/runtime/diagnostic-sections";
|
||||
import { runtimePermissionSections } from "../presentation/runtime/permission-sections";
|
||||
import {
|
||||
effortStatusDetails as buildEffortStatusDetails,
|
||||
|
|
@ -44,7 +44,7 @@ export function createChatPanelRuntimeProjection(input: ChatPanelRuntimeProjecti
|
|||
|
||||
function statusDetails(input: ChatPanelRuntimeProjectionInput): ThreadStreamNoticeSection[] {
|
||||
const state = input.state();
|
||||
return noticeSectionsFromDiagnostics(
|
||||
return noticeSectionsFromRows(
|
||||
buildStatusDetails({
|
||||
activeThreadId: state.activeThread.id,
|
||||
snapshot: runtimeSnapshot(state),
|
||||
|
|
@ -55,7 +55,7 @@ function statusDetails(input: ChatPanelRuntimeProjectionInput): ThreadStreamNoti
|
|||
|
||||
function modelStatusDetails(input: ChatPanelRuntimeProjectionInput): ThreadStreamNoticeSection[] {
|
||||
const state = input.state();
|
||||
return noticeSectionsFromDiagnostics(
|
||||
return noticeSectionsFromRows(
|
||||
buildModelStatusDetails({
|
||||
runtimeConfig: state.connection.runtimeConfig,
|
||||
pendingModel: state.runtime.pending.model,
|
||||
|
|
@ -67,7 +67,7 @@ function modelStatusDetails(input: ChatPanelRuntimeProjectionInput): ThreadStrea
|
|||
|
||||
function effortStatusDetails(input: ChatPanelRuntimeProjectionInput): ThreadStreamNoticeSection[] {
|
||||
const state = input.state();
|
||||
return noticeSectionsFromDiagnostics(
|
||||
return noticeSectionsFromRows(
|
||||
buildEffortStatusDetails({
|
||||
runtimeConfig: state.connection.runtimeConfig,
|
||||
pendingReasoningEffort: state.runtime.pending.reasoningEffort,
|
||||
|
|
@ -110,6 +110,10 @@ function noticeSectionsFromDiagnostics(
|
|||
}));
|
||||
}
|
||||
|
||||
function noticeSectionsFromRows(rows: readonly DiagnosticRow[]): ThreadStreamNoticeSection[] {
|
||||
return [{ auditFacts: rows.map((row) => ({ key: row.label, value: row.value })) }];
|
||||
}
|
||||
|
||||
function collaborationModeLabel(state: ChatState): string {
|
||||
const snapshot = runtimeSnapshot(state);
|
||||
return formatCollaborationModeLabel(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import type { RateLimitWindow, SpendControlLimitSnapshot, ThreadTokenUsage } fro
|
|||
import { serviceTierLabel as formatServiceTierLabel, pendingRuntimeSettingLabel } from "../../domain/runtime/labels";
|
||||
import { resolveRuntimeControls } from "../../domain/runtime/resolution";
|
||||
import type { RuntimeSnapshot } from "../../domain/runtime/snapshot";
|
||||
import type { DiagnosticSection } from "./diagnostic-sections";
|
||||
import type { DiagnosticRow } from "./diagnostic-sections";
|
||||
|
||||
export interface ContextSummary {
|
||||
label: string;
|
||||
|
|
@ -121,54 +121,36 @@ export function rateLimitSummary(snapshot: RuntimeSnapshot, nowMs: number): Rate
|
|||
};
|
||||
}
|
||||
|
||||
export function statusDetails(input: StatusDetailsInput): DiagnosticSection[] {
|
||||
export function statusDetails(input: StatusDetailsInput): DiagnosticRow[] {
|
||||
const context = contextSummary(input.snapshot);
|
||||
const limit = rateLimitSummary(input.snapshot, input.nowMs);
|
||||
return [
|
||||
{
|
||||
title: "Thread",
|
||||
rows: [
|
||||
{ label: "Thread", value: input.activeThreadId ?? "(none)" },
|
||||
{ label: "Context", value: context ? context.detail : "not available" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Usage Limits",
|
||||
rows: limit ? usageLimitRows(limit) : [{ label: "Status", value: "not available" }],
|
||||
},
|
||||
{ label: "Thread", value: input.activeThreadId ?? "(none)" },
|
||||
{ label: "Context", value: context ? context.detail : "not available" },
|
||||
{ label: "Usage Limits", value: limit ? usageLimitValue(limit) : "not available" },
|
||||
];
|
||||
}
|
||||
|
||||
export function modelStatusDetails(input: ModelStatusDetailsInput): DiagnosticSection[] {
|
||||
export function modelStatusDetails(input: ModelStatusDetailsInput): DiagnosticRow[] {
|
||||
const config = runtimeConfigOrDefault(input.runtimeConfig);
|
||||
const resolution = resolveRuntimeControls(input.snapshot, config);
|
||||
return [
|
||||
{
|
||||
title: "Model",
|
||||
rows: [
|
||||
{ label: "Model", value: resolution.model.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Override", value: pendingRuntimeSettingLabel(input.pendingModel) },
|
||||
{ label: "Provider", value: stringValue(config.modelProvider, CODEX_DEFAULT_LABEL) },
|
||||
{ label: "Effort", value: resolution.reasoningEffort.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Mode", value: input.collaborationModeLabel },
|
||||
{ label: "Service tier", value: serviceTierLabel(input.snapshot, config) },
|
||||
],
|
||||
},
|
||||
{ label: "Model", value: resolution.model.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Override", value: pendingRuntimeSettingLabel(input.pendingModel) },
|
||||
{ label: "Provider", value: stringValue(config.modelProvider, CODEX_DEFAULT_LABEL) },
|
||||
{ label: "Effort", value: resolution.reasoningEffort.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Mode", value: input.collaborationModeLabel },
|
||||
{ label: "Service tier", value: serviceTierLabel(input.snapshot, config) },
|
||||
];
|
||||
}
|
||||
|
||||
export function effortStatusDetails(input: EffortStatusDetailsInput): DiagnosticSection[] {
|
||||
export function effortStatusDetails(input: EffortStatusDetailsInput): DiagnosticRow[] {
|
||||
const config = runtimeConfigOrDefault(input.runtimeConfig);
|
||||
const resolution = resolveRuntimeControls(input.snapshot, config);
|
||||
return [
|
||||
{
|
||||
title: "Reasoning",
|
||||
rows: [
|
||||
{ label: "Effort", value: resolution.reasoningEffort.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Override", value: pendingRuntimeSettingLabel(input.pendingReasoningEffort) },
|
||||
{ label: "Supported", value: resolution.supportedReasoningEfforts.join(", ") },
|
||||
],
|
||||
},
|
||||
{ label: "Effort", value: resolution.reasoningEffort.effective ?? CODEX_DEFAULT_LABEL },
|
||||
{ label: "Override", value: pendingRuntimeSettingLabel(input.pendingReasoningEffort) },
|
||||
{ label: "Supported", value: resolution.supportedReasoningEfforts.join(", ") },
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -176,12 +158,8 @@ function contextUsageTokens(usage: ThreadTokenUsage): number {
|
|||
return usage.last.inputTokens > 0 ? usage.last.inputTokens : usage.last.totalTokens;
|
||||
}
|
||||
|
||||
function usageLimitRows(limit: RateLimitSummary): DiagnosticSection["rows"] {
|
||||
return limit.rows.map((row) => ({
|
||||
label: row.label,
|
||||
value: `${row.value}${row.resetLabel ? ` (${row.resetLabel})` : ""}`,
|
||||
level: row.level === "ok" ? "normal" : row.level === "warn" ? "warning" : "error",
|
||||
}));
|
||||
function usageLimitValue(limit: RateLimitSummary): string {
|
||||
return limit.rows.map((row) => `${row.label} ${row.value}${row.resetLabel ? ` (${row.resetLabel})` : ""}`).join(", ");
|
||||
}
|
||||
|
||||
function rateLimitWindowSummary(
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ function context(overrides: Partial<SlashCommandExecutionContext> = {}): SlashCo
|
|||
setStatus: vi.fn().mockResolvedValue(true),
|
||||
clear: vi.fn().mockResolvedValue(true),
|
||||
},
|
||||
statusDetails: () => [{ title: "Thread", auditFacts: [{ key: "Thread", value: "thread-1" }] }],
|
||||
statusDetails: () => [{ auditFacts: [{ key: "Thread", value: "thread-1" }] }],
|
||||
permissionDetails: () => [{ title: "Permissions", auditFacts: [{ key: "Profile", value: "read-only" }] }],
|
||||
connectionDiagnosticDetails: () => [{ title: "Process", rows: [{ key: "connection", value: "connected" }] }],
|
||||
toolInventoryDetails: vi.fn(() => [{ title: "Tool providers", auditFacts: [{ key: "codex_apps", value: "github" }] }]),
|
||||
modelStatusDetails: () => [{ title: "Model", auditFacts: [{ key: "Model", value: "gpt-5.5" }] }],
|
||||
effortStatusDetails: () => [{ title: "Reasoning", auditFacts: [{ key: "Effort", value: "high" }] }],
|
||||
modelStatusDetails: () => [{ auditFacts: [{ key: "Model", value: "gpt-5.5" }] }],
|
||||
effortStatusDetails: () => [{ auditFacts: [{ key: "Effort", value: "high" }] }],
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
|
@ -621,8 +621,12 @@ describe("slash commands", () => {
|
|||
|
||||
it("shows status as a structured system result", async () => {
|
||||
const details = [
|
||||
{ title: "Thread", auditFacts: [{ key: "Thread", value: "thread-1" }] },
|
||||
{ title: "Usage Limits", auditFacts: [{ key: "5h", value: "42%" }] },
|
||||
{
|
||||
auditFacts: [
|
||||
{ key: "Thread", value: "thread-1" },
|
||||
{ key: "Usage Limits", value: "5h 42%" },
|
||||
],
|
||||
},
|
||||
];
|
||||
const ctx = context({ statusDetails: () => details });
|
||||
|
||||
|
|
@ -772,8 +776,8 @@ describe("slash commands", () => {
|
|||
});
|
||||
|
||||
it("shows model and reasoning status for empty runtime commands", async () => {
|
||||
const modelDetails = [{ title: "Model", auditFacts: [{ key: "Model", value: "gpt-5.5" }] }];
|
||||
const effortDetails = [{ title: "Reasoning", auditFacts: [{ key: "Effort", value: "high" }] }];
|
||||
const modelDetails = [{ auditFacts: [{ key: "Model", value: "gpt-5.5" }] }];
|
||||
const effortDetails = [{ auditFacts: [{ key: "Effort", value: "high" }] }];
|
||||
const ctx = context({
|
||||
modelStatusDetails: () => modelDetails,
|
||||
effortStatusDetails: () => effortDetails,
|
||||
|
|
|
|||
|
|
@ -31,20 +31,15 @@ describe("createChatPanelRuntimeProjection", () => {
|
|||
|
||||
expect(projection.statusDetails()).toEqual([
|
||||
{
|
||||
title: "Thread",
|
||||
auditFacts: [
|
||||
{ key: "Thread", value: "thread-1" },
|
||||
{ key: "Context", value: "0 tokens. No turns in this thread yet." },
|
||||
{ key: "Usage Limits", value: "not available" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Usage Limits",
|
||||
auditFacts: [{ key: "Status", value: "not available" }],
|
||||
},
|
||||
]);
|
||||
expect(projection.modelStatusDetails()).toEqual([
|
||||
{
|
||||
title: "Model",
|
||||
auditFacts: [
|
||||
{ key: "Model", value: "gpt-5.5" },
|
||||
{ key: "Override", value: "(none)" },
|
||||
|
|
@ -57,7 +52,6 @@ describe("createChatPanelRuntimeProjection", () => {
|
|||
]);
|
||||
expect(projection.effortStatusDetails()).toEqual([
|
||||
{
|
||||
title: "Reasoning",
|
||||
auditFacts: [
|
||||
{ key: "Effort", value: "high" },
|
||||
{ key: "Override", value: "(none)" },
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import {
|
|||
permissionProfileRequestForThreadStart,
|
||||
serviceTierRequestForThreadStart,
|
||||
} from "../../src/features/chat/domain/runtime/thread-settings-patch";
|
||||
import { contextSummary, rateLimitSummary } from "../../src/features/chat/presentation/runtime/status";
|
||||
import { contextSummary, rateLimitSummary, statusDetails } from "../../src/features/chat/presentation/runtime/status";
|
||||
|
||||
describe("runtime settings", () => {
|
||||
it("formats runtime override messages", () => {
|
||||
|
|
@ -983,6 +983,30 @@ describe("runtime settings", () => {
|
|||
level: "warn",
|
||||
});
|
||||
});
|
||||
|
||||
it("formats runtime status details as flat rows", () => {
|
||||
expect(
|
||||
statusDetails({
|
||||
activeThreadId: "thread",
|
||||
snapshot: runtimeSnapshot({
|
||||
activeThreadId: "thread",
|
||||
rateLimit: {
|
||||
limitId: "codex",
|
||||
limitName: "Codex",
|
||||
primary: { usedPercent: 15, windowDurationMins: 300, resetsAt: null },
|
||||
secondary: { usedPercent: 38, windowDurationMins: 10_080, resetsAt: null },
|
||||
individualLimit: null,
|
||||
rateLimitReachedType: null,
|
||||
},
|
||||
}),
|
||||
nowMs: 0,
|
||||
}),
|
||||
).toEqual([
|
||||
{ label: "Thread", value: "thread" },
|
||||
{ label: "Context", value: "0 / 100,000 (0%). No turns in this thread yet." },
|
||||
{ label: "Usage Limits", value: "5h 15%, 1w 38%" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
interface RuntimeSnapshotPatch extends Partial<Omit<RuntimeSnapshot, "active" | "pending">> {
|
||||
|
|
|
|||
Loading…
Reference in a new issue