mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-26 16:06:16 +00:00
refactor: split claude cli history import pipeline
This commit is contained in:
@@ -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 }];
|
||||
|
||||
34
ui/src/ui/chat/tool-cards.test.ts
Normal file
34
ui/src/ui/chat/tool-cards.test.ts
Normal 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");
|
||||
});
|
||||
});
|
||||
@@ -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);
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user