fix(hermes): project native completion and tool activity

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-09 01:57:28 -05:00
1 parent 300afb3fe3
commit f628d54bc8
12 files changed
+225 -12

No files matched your search

@@ -248,14 +248,14 @@ describe("omitProgressRepeatedByResponseAcrossSegments", () => {
});
});
function toolCall(name: string, input?: unknown): TranscriptEntry {
function toolCall(name: string, input?: unknown): Extract<TranscriptEntry, { kind: "tool_call" }> {
return {
kind: "tool_call",
ts: TS,
name,
toolUseId: `tool-${name}`,
input,
} as TranscriptEntry;
};
}
describe("splitTranscriptAtAnchors", () => {
@@ -366,6 +366,43 @@ describe("toolDisplayName", () => {
describe("transcriptToTaskChatItems tool_call updates", () => {
const opts = { runId: "run-1", running: false };
it("renders serialized native command arguments as the invocation", () => {
const items = transcriptToTaskChatItems([
toolCall("terminal", JSON.stringify({ cmd: "printf 'hello'", cwd: "/workspace" })),
{ kind: "tool_result", ts: TS, toolUseId: "tool-terminal", content: "hello", isError: false },
], opts);
expect(items).toMatchObject([{ kind: "tool", target: "printf 'hello'", detail: "hello", status: "completed" }]);
});
it("updates a missing invocation without merging overlapping same-name calls", () => {
const items = transcriptToTaskChatItems([
toolCall("terminal"),
{ ...toolCall("terminal", { command: "echo second" }), toolUseId: "second-call" },
toolCall("terminal", JSON.stringify({ command: "echo first" })),
{ kind: "tool_result", ts: TS, toolUseId: "second-call", content: "second", isError: false },
{ kind: "tool_result", ts: TS, toolUseId: "tool-terminal", content: "first", isError: false },
], opts);
expect(items).toMatchObject([
{ kind: "tool", target: "echo first", detail: "first", status: "completed" },
{ kind: "tool", target: "echo second", detail: "second", status: "completed" },
]);
});
it("shows native output and failures while retaining unknown structured details", () => {
const metadata = JSON.stringify({ disposition: "applied", document: { key: "plan" } });
const items = transcriptToTaskChatItems([
toolCall("terminal", { command: "run checks" }),
{ kind: "tool_result", ts: TS, toolUseId: "tool-terminal", isError: true,
content: JSON.stringify({ stdout: "Checking\nTwo checks failed", stderr: "Missing input", exit_code: 2 }) },
toolCall("write_document", { key: "plan" }),
{ kind: "tool_result", ts: TS, toolUseId: "tool-write_document", content: metadata, isError: false },
], opts);
expect(items).toMatchObject([
{ kind: "tool", status: "failed", detail: "Checking\nTwo checks failed\nMissing input\nExit code: 2" },
{ kind: "tool", status: "completed", detail: metadata },
]);
});
function update(toolUseId: string, status: string): TranscriptEntry {
// Mirrors what a persisted acpx tool_call_update line parses to: the
// literal placeholder name plus a synthesized { text, status } input.
@@ -139,6 +139,7 @@ const TARGET_KEYS = [
"path",
"notebook_path",
"command",
"cmd",
"pattern",
"query",
"url",
@@ -162,6 +163,12 @@ function clip(text: string, max: number): string {
*/
export function summarizeToolInput(input: unknown): string | undefined {
if (input == null) return undefined;
if (typeof input === "string") {
try {
const parsed: unknown = JSON.parse(input);
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) input = parsed;
} catch { /* Ordinary text remains a valid tool input. */ }
}
if (typeof input === "string")
return input.trim() ? clip(input, TARGET_MAX) : undefined;
if (typeof input !== "object") return clip(String(input), TARGET_MAX);
@@ -555,7 +562,19 @@ function mergeProviderActivityItem(
/** Result content → the expandable mono detail block (clipped, trimmed). */
function formatToolResultDetail(content: unknown): string | undefined {
if (content == null) return undefined;
const text = typeof content === "string" ? content : String(content);
let text = typeof content === "string" ? content : String(content);
try {
const result: unknown = typeof content === "string" ? JSON.parse(content) : content;
const output = objectRecord(result);
const parts = [output.output ?? output.stdout ?? output.content, output.stderr, output.error]
.filter((value): value is string => typeof value === "string" && value.trim().length > 0);
if (parts.length > 0) {
text = [...new Set(parts)].join("\n");
if (typeof output.exit_code === "number" && output.exit_code !== 0) {
text += `\nExit code: ${output.exit_code}`;
}
}
} catch { /* Preserve plain output and unrecognized structured results. */ }
const trimmed = text.trim();
if (!trimmed) return undefined;
return trimmed.length > DETAIL_MAX
@@ -733,6 +752,8 @@ export function transcriptToTaskChatItems(
existing.target = clip(entry.name!, TARGET_MAX);
}
}
const incomingTarget = summarizeToolInput(entry.input);
if (incomingTarget) existing.target = incomingTarget;
lastToolIndex = existingIndex!;
} else {
items.push({
@@ -118,6 +118,30 @@ describe("provider notice presentation", () => {
});
describe("nativeRunEventsToTranscript", () => {
it.each(["command", "cmd"])("uses native %s arguments for process previews and preserves plain results", (key) => {
const input = { [key]: "printf 'native output'", cwd: "/workspace" };
const transcript = nativeRunEventsToTranscript([
event(1, "tool.execution.started", {
schema: "paperclip.tool.execution.v1", executionId: "hermes-terminal",
transport: "process", operation: "execute", name: "terminal", status: "running",
}),
itemEvent(2, "item.started", "hermes-terminal", {
item: { type: "tool_use", id: "hermes-terminal", name: "terminal", input: JSON.stringify(input) },
}),
event(3, "tool.execution.completed", {
schema: "paperclip.tool.execution.v1", executionId: "hermes-terminal",
transport: "process", operation: "execute", name: "terminal", status: "completed",
}),
itemEvent(4, "item.completed", "hermes-terminal", {
item: { type: "tool_result", tool_use_id: "hermes-terminal", result: "native output\nnext line" },
}),
]);
expect(transcript).toMatchObject([
{ kind: "tool_call", toolUseId: "hermes-terminal", name: "Bash", input },
{ kind: "tool_result", toolUseId: "hermes-terminal", content: "native output\nnext line", isError: false },
]);
});
describe("accepted response-wake authority", () => {
function fixture() {
const result = {
@@ -547,6 +547,7 @@ function nativeToolItemDetails(
function serializedNativeToolResult(item: NativeToolItemDetails): string {
if (item.result === undefined) return "";
if (typeof item.result === "string") return item.result;
try {
return JSON.stringify(item.result) ?? "";
} catch {
@@ -562,6 +563,14 @@ function toolPresentation(
const operation = text(payload.operation);
const reportedName = text(payload.name) ?? item?.name ?? null;
if (transport === "process") {
let input = item?.input;
if (typeof input === "string") {
try { input = JSON.parse(input); } catch { /* Keep the reported invocation fallback. */ }
}
const argumentsRecord = record(input);
if (text(argumentsRecord?.command) || text(argumentsRecord?.cmd)) {
return { name: "Bash", input };
}
return {
name: "Bash",
input: reportedName ? { command: reportedName } : { operation: operation ?? "execute" },