Verbose: include tool arg metadata in prefixes
This commit is contained in:
@@ -69,11 +69,16 @@ describe("agent buildArgs + parseOutput helpers", () => {
|
||||
|
||||
it("piSpec carries tool names when present", () => {
|
||||
const stdout =
|
||||
'{"type":"message_end","message":{"role":"tool_result","name":"bash","content":[{"type":"text","text":"ls output"}]}}';
|
||||
'{"type":"message_end","message":{"role":"tool_result","name":"bash","details":{"command":"ls -la"},"content":[{"type":"text","text":"ls output"}]}}';
|
||||
const parsed = piSpec.parseOutput(stdout);
|
||||
const tool = parsed.toolResults?.[0] as { text?: string; toolName?: string };
|
||||
const tool = parsed.toolResults?.[0] as {
|
||||
text?: string;
|
||||
toolName?: string;
|
||||
meta?: string;
|
||||
};
|
||||
expect(tool?.text).toBe("ls output");
|
||||
expect(tool?.toolName).toBe("bash");
|
||||
expect(tool?.meta).toBe("ls -la");
|
||||
});
|
||||
|
||||
it("codexSpec parses agent_message and aggregates usage", () => {
|
||||
|
||||
@@ -18,6 +18,8 @@ type PiAssistantMessage = {
|
||||
toolName?: string;
|
||||
tool_call_id?: string;
|
||||
toolCallId?: string;
|
||||
details?: Record<string, unknown>;
|
||||
arguments?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
function inferToolName(msg: PiAssistantMessage): string | undefined {
|
||||
@@ -39,6 +41,23 @@ function inferToolName(msg: PiAssistantMessage): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function deriveToolMeta(msg: PiAssistantMessage): string | undefined {
|
||||
const details = msg.details ?? msg.arguments;
|
||||
const pathVal = details && typeof details.path === "string" ? details.path : undefined;
|
||||
const offset = details && typeof details.offset === "number" ? details.offset : undefined;
|
||||
const limit = details && typeof details.limit === "number" ? details.limit : undefined;
|
||||
const command = details && typeof details.command === "string" ? details.command : undefined;
|
||||
|
||||
if (pathVal) {
|
||||
if (offset !== undefined && limit !== undefined) {
|
||||
return `${pathVal}:${offset}-${offset + limit}`;
|
||||
}
|
||||
return pathVal;
|
||||
}
|
||||
if (command) return command;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parsePiJson(raw: string): AgentParseResult {
|
||||
const lines = raw.split(/\n+/).filter((l) => l.trim().startsWith("{"));
|
||||
|
||||
@@ -87,7 +106,11 @@ function parsePiJson(raw: string): AgentParseResult {
|
||||
.join("\n")
|
||||
.trim();
|
||||
if (toolText) {
|
||||
toolResults.push({ text: toolText, toolName: inferToolName(msg) });
|
||||
toolResults.push({
|
||||
text: toolText,
|
||||
toolName: inferToolName(msg),
|
||||
meta: deriveToolMeta(msg),
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -18,6 +18,7 @@ export type AgentMeta = {
|
||||
export type AgentToolResult = {
|
||||
text: string;
|
||||
toolName?: string;
|
||||
meta?: string;
|
||||
};
|
||||
|
||||
export type AgentParseResult = {
|
||||
|
||||
@@ -59,6 +59,8 @@ type ToolMessageLike = {
|
||||
tool_call_id?: string;
|
||||
toolCallId?: string;
|
||||
role?: string;
|
||||
details?: Record<string, unknown>;
|
||||
arguments?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
function inferToolName(message?: ToolMessageLike): string | undefined {
|
||||
@@ -80,6 +82,24 @@ function inferToolName(message?: ToolMessageLike): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferToolMeta(message?: ToolMessageLike): string | undefined {
|
||||
if (!message) return undefined;
|
||||
const details = message.details ?? message.arguments;
|
||||
const pathVal = details && typeof details.path === "string" ? details.path : undefined;
|
||||
const offset = details && typeof details.offset === "number" ? details.offset : undefined;
|
||||
const limit = details && typeof details.limit === "number" ? details.limit : undefined;
|
||||
const command = details && typeof details.command === "string" ? details.command : undefined;
|
||||
|
||||
if (pathVal) {
|
||||
if (offset !== undefined && limit !== undefined) {
|
||||
return `${pathVal}:${offset}-${offset + limit}`;
|
||||
}
|
||||
return pathVal;
|
||||
}
|
||||
if (command) return command;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function normalizeToolResults(
|
||||
toolResults?: Array<string | AgentToolResult>,
|
||||
): AgentToolResult[] {
|
||||
@@ -89,13 +109,15 @@ function normalizeToolResults(
|
||||
.map((tr) => ({
|
||||
text: (tr.text ?? "").trim(),
|
||||
toolName: tr.toolName?.trim() || undefined,
|
||||
meta: tr.meta?.trim() || undefined,
|
||||
}))
|
||||
.filter((tr) => tr.text.length > 0);
|
||||
}
|
||||
|
||||
function formatToolPrefix(toolName?: string) {
|
||||
function formatToolPrefix(toolName?: string, meta?: string) {
|
||||
const label = toolName?.trim() || "tool";
|
||||
return `[🛠️ ${label}]`;
|
||||
const extra = meta?.trim();
|
||||
return extra ? `[🛠️ ${label} ${extra}]` : `[🛠️ ${label}]`;
|
||||
}
|
||||
|
||||
export function summarizeClaudeMetadata(payload: unknown): string | undefined {
|
||||
@@ -327,7 +349,12 @@ export async function runCommandReply(
|
||||
try {
|
||||
const ev = JSON.parse(line) as {
|
||||
type?: string;
|
||||
message?: { role?: string; content?: unknown[] };
|
||||
message?: {
|
||||
role?: string;
|
||||
content?: unknown[];
|
||||
details?: Record<string, unknown>;
|
||||
arguments?: Record<string, unknown>;
|
||||
};
|
||||
};
|
||||
if (
|
||||
(ev.type === "message" || ev.type === "message_end") &&
|
||||
@@ -335,7 +362,8 @@ export async function runCommandReply(
|
||||
Array.isArray(ev.message.content)
|
||||
) {
|
||||
const toolName = inferToolName(ev.message);
|
||||
const prefix = formatToolPrefix(toolName);
|
||||
const meta = inferToolMeta(ev.message);
|
||||
const prefix = formatToolPrefix(toolName, meta);
|
||||
const { text: cleanedText, mediaUrls: mediaFound } =
|
||||
splitMediaFromOutput(prefix);
|
||||
void onPartialReply({
|
||||
@@ -387,7 +415,7 @@ export async function runCommandReply(
|
||||
|
||||
if (includeToolResultsInline) {
|
||||
for (const tr of parsedToolResults) {
|
||||
const prefixed = formatToolPrefix(tr.toolName);
|
||||
const prefixed = formatToolPrefix(tr.toolName, tr.meta);
|
||||
const { text: cleanedText, mediaUrls: mediaFound } =
|
||||
splitMediaFromOutput(prefixed);
|
||||
replyItems.push({
|
||||
|
||||
@@ -719,7 +719,7 @@ describe("config and templating", () => {
|
||||
const rpcSpy = vi.spyOn(tauRpc, "runPiRpc").mockResolvedValue({
|
||||
stdout:
|
||||
'{"type":"message","message":{"role":"assistant","content":[{"type":"text","text":"summary"}]}}\n' +
|
||||
'{"type":"message_end","message":{"role":"tool_result","name":"bash","content":[{"type":"text","text":"ls output"}]}}',
|
||||
'{"type":"message_end","message":{"role":"tool_result","name":"bash","details":{"command":"ls"},"content":[{"type":"text","text":"ls output"}]}}',
|
||||
stderr: "",
|
||||
code: 0,
|
||||
signal: null,
|
||||
@@ -744,7 +744,7 @@ describe("config and templating", () => {
|
||||
expect(rpcSpy).toHaveBeenCalled();
|
||||
const payloads = Array.isArray(res) ? res : res ? [res] : [];
|
||||
expect(payloads.length).toBeGreaterThanOrEqual(2);
|
||||
expect(payloads[0]?.text).toBe("[🛠️ bash]");
|
||||
expect(payloads[0]?.text).toBe("[🛠️ bash ls]");
|
||||
expect(payloads[1]?.text).toContain("summary");
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user