mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Coarsen message stream diagnostics
This commit is contained in:
parent
7d36b552a0
commit
612782ded9
6 changed files with 44 additions and 43 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import type { CommandMessageStreamTarget, MessageStreamItem } from "../../../domain/message-stream/items";
|
||||
import type { CommandMessageStreamTarget, MessageStreamDiagnosticSection, MessageStreamItem } from "../../../domain/message-stream/items";
|
||||
import type { MessageStreamItemProvenance } from "../../../domain/message-stream/provenance";
|
||||
import type { HistoricalTurn } from "../../../../../domain/threads/history";
|
||||
import type { TurnItem } from "../../../../../app-server/protocol/turn";
|
||||
import { definedProp } from "../../../../../utils";
|
||||
import { definedProp, jsonPreview } from "../../../../../utils";
|
||||
import { referencedThreadMetadataFromPrompt } from "../../../../../domain/threads/reference";
|
||||
import { turnUserItemText } from "../../../../../app-server/protocol/turn";
|
||||
import { agentMessageStreamItem } from "./agent-items";
|
||||
|
|
@ -201,11 +201,14 @@ function mcpToolCallMessageStreamItem(item: McpToolCallItem, turnId?: string): M
|
|||
...(target ? { primaryTarget: { kind: "value" as const, value: target } } : {}),
|
||||
...(item.error?.message ? { failureReason: item.error.message } : {}),
|
||||
status: item.status,
|
||||
toolCall: {
|
||||
arguments: item.arguments,
|
||||
result: item.result,
|
||||
error: item.error,
|
||||
},
|
||||
...definedProp(
|
||||
"diagnostics",
|
||||
jsonDiagnosticSections(
|
||||
{ title: "Arguments JSON", value: item.arguments },
|
||||
{ title: "Result JSON", value: item.result },
|
||||
{ title: "Error JSON", value: item.error },
|
||||
),
|
||||
),
|
||||
output: "",
|
||||
executionState: mcpToolCallExecutionState(item.status),
|
||||
};
|
||||
|
|
@ -223,10 +226,10 @@ function dynamicToolCallMessageStreamItem(item: DynamicToolCallItem, turnId?: st
|
|||
...(target ? { primaryTarget: { kind: "value" as const, value: target } } : {}),
|
||||
...(failure ? { failureReason: failure } : {}),
|
||||
status: item.status,
|
||||
toolCall: {
|
||||
arguments: item.arguments,
|
||||
result: item.contentItems,
|
||||
},
|
||||
...definedProp(
|
||||
"diagnostics",
|
||||
jsonDiagnosticSections({ title: "Arguments JSON", value: item.arguments }, { title: "Result JSON", value: item.contentItems }),
|
||||
),
|
||||
output: "",
|
||||
executionState: dynamicToolCallExecutionState(item.status, item.success),
|
||||
};
|
||||
|
|
@ -502,6 +505,15 @@ function jsonTargetLabel(value: unknown): string | null {
|
|||
return firstEntry ? jsonTargetPrimitive(firstEntry[1]) : null;
|
||||
}
|
||||
|
||||
function jsonDiagnosticSections(
|
||||
...sections: readonly { readonly title: string; readonly value: unknown }[]
|
||||
): readonly MessageStreamDiagnosticSection[] | undefined {
|
||||
const diagnostics = sections
|
||||
.filter((section) => section.value !== null && section.value !== undefined)
|
||||
.map((section) => ({ title: section.title, body: jsonPreview(section.value) }));
|
||||
return diagnostics.length > 0 ? diagnostics : undefined;
|
||||
}
|
||||
|
||||
function jsonTargetPrimitive(value: unknown): string | null {
|
||||
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
||||
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
||||
|
|
|
|||
|
|
@ -41,10 +41,9 @@ export type MessageStreamPrimaryTarget =
|
|||
readonly value: string;
|
||||
};
|
||||
|
||||
interface MessageStreamToolCallDetails {
|
||||
readonly arguments?: unknown;
|
||||
readonly result?: unknown;
|
||||
readonly error?: unknown;
|
||||
export interface MessageStreamDiagnosticSection {
|
||||
readonly title: string;
|
||||
readonly body: string;
|
||||
}
|
||||
|
||||
interface MessageStreamWebSearchDetails {
|
||||
|
|
@ -227,7 +226,7 @@ interface ToolMessageStreamBase extends MessageStreamBase {
|
|||
|
||||
export interface ToolCallMessageStreamItem extends ToolMessageStreamBase {
|
||||
readonly kind: "tool";
|
||||
readonly toolCall?: MessageStreamToolCallDetails;
|
||||
readonly diagnostics?: readonly MessageStreamDiagnosticSection[];
|
||||
readonly webSearch?: MessageStreamWebSearchDetails;
|
||||
readonly imageGeneration?: MessageStreamImageGenerationDetails;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { jsonPreview, shortThreadId, truncate } from "../../../../utils";
|
||||
import { shortThreadId, truncate } from "../../../../utils";
|
||||
import { failedStatusLabel } from "../../domain/message-stream/execution-state";
|
||||
import { pathRelativeToRoot } from "../../domain/message-stream/format/path-labels";
|
||||
import type {
|
||||
|
|
@ -265,7 +265,7 @@ function resultDetails(item: ApprovalResultMessageStreamItem | ReviewResultMessa
|
|||
|
||||
function genericToolDetails(item: ToolCallMessageStreamItem | HookMessageStreamItem): DetailSection[] {
|
||||
if (item.kind === "hook") return hookRunDetails(item);
|
||||
return [...toolCallDetails(item), ...webSearchDetails(item), ...imageGenerationDetails(item)];
|
||||
return [...diagnosticDetails(item), ...webSearchDetails(item), ...imageGenerationDetails(item)];
|
||||
}
|
||||
|
||||
function genericDetailSections(item: MessageStreamItem, workspaceRoot?: string | null): DetailSection[] {
|
||||
|
|
@ -279,14 +279,8 @@ function genericDetailSections(item: MessageStreamItem, workspaceRoot?: string |
|
|||
return [...(rows.length > 0 ? [{ kind: "kv" as const, rows }] : []), ...outputSection("Output", outputField(item))];
|
||||
}
|
||||
|
||||
function toolCallDetails(item: ToolCallMessageStreamItem): DetailSection[] {
|
||||
const details = item.toolCall;
|
||||
if (!details) return [];
|
||||
return [
|
||||
...jsonOutputSection("Arguments JSON", details.arguments),
|
||||
...jsonOutputSection("Result JSON", details.result),
|
||||
...jsonOutputSection("Error JSON", details.error),
|
||||
];
|
||||
function diagnosticDetails(item: ToolCallMessageStreamItem): DetailSection[] {
|
||||
return item.diagnostics?.map((section) => ({ kind: "output" as const, title: section.title, body: section.body })) ?? [];
|
||||
}
|
||||
|
||||
function webSearchDetails(item: ToolCallMessageStreamItem): DetailSection[] {
|
||||
|
|
@ -328,10 +322,6 @@ function outputSection(title: string, body: string | null | undefined): DetailSe
|
|||
return body ? [{ kind: "output", title, body }] : [];
|
||||
}
|
||||
|
||||
function jsonOutputSection(title: string, value: unknown): DetailSection[] {
|
||||
return value === null || value === undefined ? [] : outputSection(title, jsonPreview(value));
|
||||
}
|
||||
|
||||
function metaRow(key: string, value: string | null | undefined): { key: string; value: string }[] {
|
||||
return value ? [{ key, value }] : [];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -636,10 +636,10 @@ describe("turn item conversion preserves app-server semantics", () => {
|
|||
primaryTarget: { kind: "value", value: "123" },
|
||||
failureReason: "Not found",
|
||||
toolName: "github.pull_request_read",
|
||||
toolCall: {
|
||||
arguments: expect.objectContaining({ id: 123 }),
|
||||
error: { message: "Not found" },
|
||||
},
|
||||
diagnostics: expect.arrayContaining([
|
||||
{ title: "Arguments JSON", body: expect.stringContaining('"id": 123') },
|
||||
{ title: "Error JSON", body: expect.stringContaining("Not found") },
|
||||
]),
|
||||
executionState: "failed",
|
||||
});
|
||||
});
|
||||
|
|
@ -661,10 +661,10 @@ describe("turn item conversion preserves app-server semantics", () => {
|
|||
kind: "tool",
|
||||
primaryTarget: { kind: "value", value: "https://example.com" },
|
||||
toolName: "web.open",
|
||||
toolCall: {
|
||||
arguments: { url: "https://example.com" },
|
||||
result: [{ type: "inputText", text: "ok" }],
|
||||
},
|
||||
diagnostics: expect.arrayContaining([
|
||||
{ title: "Arguments JSON", body: expect.stringContaining("https://example.com") },
|
||||
{ title: "Result JSON", body: expect.stringContaining("inputText") },
|
||||
]),
|
||||
executionState: "completed",
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ describe("message stream semantic classification", () => {
|
|||
changes: [{ kind: "update", path: "src/main.ts", diff: "@@" }],
|
||||
executionState: "completed",
|
||||
},
|
||||
{ id: "tool", kind: "tool", role: "tool", text: "tool", toolCall: { arguments: { k: "v" } } },
|
||||
{ id: "tool", kind: "tool", role: "tool", text: "tool", diagnostics: [{ title: "Arguments JSON", body: '{"k":"v"}' }] },
|
||||
{ id: "hook", kind: "hook", role: "tool", text: "hook" },
|
||||
{ id: "reasoning", kind: "reasoning", role: "tool", text: "thinking" },
|
||||
{ id: "wait", kind: "wait", role: "tool", text: "Waited 2.5s", executionState: "completed" },
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ describe("message stream item renderer decisions", () => {
|
|||
toolName: "github.pull_request_read",
|
||||
turnId: "turn",
|
||||
status: "completed",
|
||||
toolCall: {
|
||||
arguments: { id: 123 },
|
||||
result: { ok: true },
|
||||
},
|
||||
diagnostics: [
|
||||
{ title: "Arguments JSON", body: '{\n "id": 123\n}' },
|
||||
{ title: "Result JSON", body: '{\n "ok": true\n}' },
|
||||
],
|
||||
},
|
||||
],
|
||||
disclosures: emptyDisclosures(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue