refactor: split claude cli history import pipeline

This commit is contained in:
Peter Steinberger
2026-03-26 22:11:14 +00:00
parent d0ce2d1044
commit 00aedb3414
10 changed files with 563 additions and 528 deletions

View File

@@ -3,6 +3,10 @@
*/
import { stripInboundMetadata } from "../../../../src/auto-reply/reply/strip-inbound-meta.js";
import {
isToolResultContentType,
resolveToolBlockArgs,
} from "../../../../src/chat/tool-content.js";
import type { NormalizedMessage, MessageContentItem } from "../types/chat-types.ts";
/**
@@ -22,8 +26,7 @@ export function normalizeMessage(message: unknown): NormalizedMessage {
Array.isArray(contentItems) &&
contentItems.some((item) => {
const x = item as Record<string, unknown>;
const t = (typeof x.type === "string" ? x.type : "").toLowerCase();
return t === "toolresult" || t === "tool_result";
return isToolResultContentType(x.type);
});
const hasToolName = typeof m.toolName === "string" || typeof m.tool_name === "string";
@@ -42,7 +45,7 @@ export function normalizeMessage(message: unknown): NormalizedMessage {
type: (item.type as MessageContentItem["type"]) || "text",
text: item.text as string | undefined,
name: item.name as string | undefined,
args: item.args || item.arguments || item.input,
args: resolveToolBlockArgs(item),
}));
} else if (typeof m.text === "string") {
content = [{ type: "text", text: m.text }];

View File

@@ -0,0 +1,34 @@
/* @vitest-environment jsdom */
import { render } from "lit";
import { describe, expect, it } from "vitest";
import { extractToolCards, renderToolCardSidebar } from "./tool-cards.ts";
describe("tool cards", () => {
it("renders anthropic tool_use input details in tool cards", () => {
const cards = extractToolCards({
role: "assistant",
content: [
{
type: "tool_use",
id: "toolu_123",
name: "Bash",
input: { command: 'time claude -p "say ok"' },
},
],
});
expect(cards).toHaveLength(1);
expect(cards[0]).toMatchObject({
kind: "call",
name: "Bash",
args: { command: 'time claude -p "say ok"' },
});
const container = document.createElement("div");
render(renderToolCardSidebar(cards[0]), container);
expect(container.textContent).toContain('time claude -p "say ok"');
expect(container.textContent).toContain("Bash");
});
});

View File

@@ -1,4 +1,9 @@
import { html, nothing } from "lit";
import {
isToolCallContentType,
isToolResultContentType,
resolveToolBlockArgs,
} from "../../../../src/chat/tool-content.js";
import { icons } from "../icons.ts";
import { formatToolDetail, resolveToolDisplay } from "../tool-display.ts";
import type { ToolCard } from "../types/chat-types.ts";
@@ -13,23 +18,20 @@ export function extractToolCards(message: unknown): ToolCard[] {
const cards: ToolCard[] = [];
for (const item of content) {
const kind = (typeof item.type === "string" ? item.type : "").toLowerCase();
const isToolCall =
["toolcall", "tool_call", "tooluse", "tool_use"].includes(kind) ||
(typeof item.name === "string" &&
(item.arguments != null || item.args != null || item.input != null));
isToolCallContentType(item.type) ||
(typeof item.name === "string" && resolveToolBlockArgs(item) != null);
if (isToolCall) {
cards.push({
kind: "call",
name: (item.name as string) ?? "tool",
args: coerceArgs(item.arguments ?? item.args ?? item.input),
args: coerceArgs(resolveToolBlockArgs(item)),
});
}
}
for (const item of content) {
const kind = (typeof item.type === "string" ? item.type : "").toLowerCase();
if (kind !== "toolresult" && kind !== "tool_result") {
if (!isToolResultContentType(item.type)) {
continue;
}
const text = extractToolText(item);

View File

@@ -453,46 +453,6 @@ describe("chat view", () => {
expect(groupedLogo?.getAttribute("src")).toBe("/openclaw/favicon.svg");
});
it("renders anthropic tool_use input details in tool cards", () => {
const container = document.createElement("div");
render(
renderChat(
createProps({
messages: [
{
role: "assistant",
content: [
{
type: "tool_use",
id: "toolu_123",
name: "Bash",
input: { command: 'time claude -p "say ok"' },
},
],
timestamp: 1000,
},
{
role: "user",
content: [
{
type: "tool_result",
name: "Bash",
tool_use_id: "toolu_123",
content: "ok",
},
],
timestamp: 1001,
},
],
}),
),
container,
);
expect(container.textContent).toContain('time claude -p "say ok"');
expect(container.textContent).toContain("Bash");
});
it("keeps the persisted overview locale selected before i18n hydration finishes", async () => {
const container = document.createElement("div");
const props = createOverviewProps({