Archived
Align live tool event rendering
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { api, type CommandResult, type SessionActivity, type SessionInfo, type SessionStatus } from "../api";
|
import { api, type CommandResult, type SessionActivity, type SessionInfo, type SessionStatus } from "../api";
|
||||||
import { appendText, normalizeMessages, textMessage } from "../chatMessages";
|
import { appendText, normalizeMessages, textMessage } from "../chatMessages";
|
||||||
import { GlobalSessionSocket, SessionSocket, type SessionUiEvent } from "../sessionSocket";
|
import { GlobalSessionSocket, SessionSocket, type SessionUiEvent } from "../sessionSocket";
|
||||||
|
import type { ChatLine, ChatPart } from "../components/shared";
|
||||||
import type { GetState, SetState, UpdateUrl } from "./types";
|
import type { GetState, SetState, UpdateUrl } from "./types";
|
||||||
|
|
||||||
export class SessionController {
|
export class SessionController {
|
||||||
@@ -139,9 +140,9 @@ export class SessionController {
|
|||||||
if (event.type === "assistant.delta") {
|
if (event.type === "assistant.delta") {
|
||||||
this.setState({ messages: appendText(messages, "assistant", event.text) });
|
this.setState({ messages: appendText(messages, "assistant", event.text) });
|
||||||
} else if (event.type === "tool.start") {
|
} else if (event.type === "tool.start") {
|
||||||
this.setState({ messages: [...messages, { role: "tool", parts: [{ type: "toolCall", toolName: event.toolName, summary: "" }] }] });
|
this.setState({ messages: appendPart(messages, "assistant", { type: "toolCall", toolName: event.toolName, summary: event.summary }) });
|
||||||
} else if (event.type === "tool.end") {
|
} else if (event.type === "tool.end") {
|
||||||
this.setState({ messages: [...messages, textMessage("tool", `${event.isError ? "✖" : "✓"} ${event.toolName}`)] });
|
this.setState({ messages: [...messages, { role: "tool", parts: [{ type: "toolResult", toolName: event.toolName, text: event.text, isError: event.isError }] }] });
|
||||||
} else if (event.type === "status.update") {
|
} else if (event.type === "status.update") {
|
||||||
this.applyStatus(event.status);
|
this.applyStatus(event.status);
|
||||||
} else if (event.type === "activity.update") {
|
} else if (event.type === "activity.update") {
|
||||||
@@ -153,3 +154,9 @@ export class SessionController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function appendPart(messages: ChatLine[], role: ChatLine["role"], part: ChatPart): ChatLine[] {
|
||||||
|
const last = messages.at(-1);
|
||||||
|
if (last?.role === role) return [...messages.slice(0, -1), { ...last, parts: [...last.parts, part] }];
|
||||||
|
return [...messages, { role, parts: [part] }];
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { globalSessionEvents, sessionEvents, type SessionActivity, type SessionS
|
|||||||
|
|
||||||
export type SessionUiEvent =
|
export type SessionUiEvent =
|
||||||
| { type: "assistant.delta"; text: string }
|
| { type: "assistant.delta"; text: string }
|
||||||
| { type: "tool.start"; toolName: string }
|
| { type: "tool.start"; toolName: string; summary: string }
|
||||||
| { type: "tool.end"; toolName: string; isError: boolean }
|
| { type: "tool.end"; toolName: string; text: string; isError: boolean }
|
||||||
| { type: "status.update"; status: SessionStatus }
|
| { type: "status.update"; status: SessionStatus }
|
||||||
| { type: "activity.update"; activity: SessionActivity }
|
| { type: "activity.update"; activity: SessionActivity }
|
||||||
| { type: "command.output"; level: "info" | "success" | "error"; message: string }
|
| { type: "command.output"; level: "info" | "success" | "error"; message: string }
|
||||||
|
|||||||
@@ -245,13 +245,42 @@ function toClientEvent(event: any): unknown {
|
|||||||
return { type: "assistant.delta", text: event.assistantMessageEvent.delta };
|
return { type: "assistant.delta", text: event.assistantMessageEvent.delta };
|
||||||
}
|
}
|
||||||
if (event.type === "tool_execution_start") {
|
if (event.type === "tool_execution_start") {
|
||||||
return { type: "tool.start", toolName: event.toolName, toolCallId: event.toolCallId };
|
return { type: "tool.start", toolName: event.toolName, toolCallId: event.toolCallId, summary: summarizeToolArgs(event.args) };
|
||||||
}
|
}
|
||||||
if (event.type === "tool_execution_end") {
|
if (event.type === "tool_execution_end") {
|
||||||
return { type: "tool.end", toolName: event.toolName, toolCallId: event.toolCallId, isError: event.isError };
|
return { type: "tool.end", toolName: event.toolName, toolCallId: event.toolCallId, text: stringifyToolResult(event.result), isError: event.isError };
|
||||||
}
|
}
|
||||||
if (event.type === "agent_start") return { type: "agent.start" };
|
if (event.type === "agent_start") return { type: "agent.start" };
|
||||||
if (event.type === "agent_end") return { type: "agent.end" };
|
if (event.type === "agent_end") return { type: "agent.end" };
|
||||||
if (event.type === "message_end") return { type: "message.end" };
|
if (event.type === "message_end") return { type: "message.end" };
|
||||||
return { type: "pi.event", eventType: event.type };
|
return { type: "pi.event", eventType: event.type };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function summarizeToolArgs(args: any): string {
|
||||||
|
if (!args || typeof args !== "object") return args == null ? "" : String(args);
|
||||||
|
if (typeof args.command === "string") return args.command;
|
||||||
|
if (typeof args.path === "string") return args.path;
|
||||||
|
if (typeof args.oldText === "string" && typeof args.newText === "string") return "edit text replacement";
|
||||||
|
if (Array.isArray(args.edits)) return `${args.edits.length} edit${args.edits.length === 1 ? "" : "s"}`;
|
||||||
|
const entries = Object.entries(args).filter(([, value]) => value != null).slice(0, 3);
|
||||||
|
return entries.map(([key, value]) => `${key}: ${shortToolValue(value)}`).join(" · ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function shortToolValue(value: unknown): string {
|
||||||
|
if (typeof value === "string") return value.length > 80 ? `${value.slice(0, 77)}…` : value;
|
||||||
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
||||||
|
if (Array.isArray(value)) return `${value.length} item${value.length === 1 ? "" : "s"}`;
|
||||||
|
if (typeof value === "object" && value) return "object";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringifyToolResult(result: unknown): string {
|
||||||
|
if (typeof result === "string") return result;
|
||||||
|
if (Array.isArray(result)) return result.map(stringifyToolResult).filter(Boolean).join("\n");
|
||||||
|
if (result && typeof result === "object") {
|
||||||
|
const text = (result as any).text ?? (result as any).content ?? (result as any).output;
|
||||||
|
if (typeof text === "string") return text;
|
||||||
|
return JSON.stringify(result, null, 2);
|
||||||
|
}
|
||||||
|
return result == null ? "" : String(result);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user