Skip to content

Commit 4023cbe

Browse files
author
Test
committed
fix(kanban): normalize tool kinds for shared card data
Map desktop-only tool kinds into the shared AgentToolKind subset before building kanban and fallback tool rows so Svelte typechecking stays aligned with the UI contracts.
1 parent b0ac756 commit 4023cbe

5 files changed

Lines changed: 64 additions & 43 deletions

File tree

packages/desktop/src/lib/acp/components/tool-calls/tool-call-fallback.svelte

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { TurnState } from "../../store/types.js";
1111
import type { ToolCall } from "../../types/tool-call.js";
1212
import type { ToolKind } from "../../types/tool-kind.js";
1313
import { getToolStatus } from "../../utils/tool-state-utils.js";
14+
import { toAgentToolKind } from "./tool-kind-to-agent-tool-kind.js";
1415
1516
interface Props {
1617
toolCall: ToolCall;
@@ -31,23 +32,7 @@ const title = $derived(getToolKindTitle(resolvedKind, toolCall, turnState));
3132
const subtitle = $derived(getToolKindSubtitle(resolvedKind, toolCall));
3233
const filePath = $derived(getToolKindFilePath(resolvedKind, toolCall));
3334
34-
// Map desktop ToolKind to shared AgentToolKind
35-
const SHARED_KINDS = new Set<string>([
36-
"read",
37-
"edit",
38-
"write",
39-
"execute",
40-
"search",
41-
"fetch",
42-
"web_search",
43-
"think",
44-
"task",
45-
"other",
46-
]);
47-
48-
const agentKind = $derived<AgentToolKind>(
49-
SHARED_KINDS.has(resolvedKind) ? (resolvedKind as AgentToolKind) : "other"
50-
);
35+
const agentKind = $derived<AgentToolKind>(toAgentToolKind(resolvedKind));
5136
5237
// Map tool status to AgentToolStatus
5338
const agentStatus = $derived.by(() => {

packages/desktop/src/lib/acp/components/tool-calls/tool-call-task/logic/convert-task-children.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,7 @@ import {
77
import type { TurnState } from "../../../../store/types.js";
88
import type { ToolCall } from "../../../../types/tool-call.js";
99
import type { ToolKind } from "../../../../types/tool-kind.js";
10-
11-
/** Map ToolKind to AgentToolKind (presentational subset). */
12-
const KIND_MAP: Record<ToolKind, AgentToolKind> = {
13-
read: "read",
14-
edit: "edit",
15-
execute: "execute",
16-
search: "search",
17-
glob: "search",
18-
fetch: "fetch",
19-
web_search: "web_search",
20-
think: "think",
21-
task: "task",
22-
task_output: "task_output",
23-
todo: "other",
24-
question: "other",
25-
skill: "other",
26-
move: "other",
27-
delete: "other",
28-
enter_plan_mode: "other",
29-
exit_plan_mode: "other",
30-
create_plan: "other",
31-
tool_search: "other",
32-
other: "other",
33-
};
10+
import { toAgentToolKind } from "../../tool-kind-to-agent-tool-kind.js";
3411

3512
/** Map ToolCallStatus to AgentToolStatus. */
3613
function mapStatus(
@@ -79,7 +56,7 @@ function convertChild(
7956
return {
8057
id: child.id,
8158
type: "tool_call",
82-
kind: KIND_MAP[kind] ?? "other",
59+
kind: toAgentToolKind(kind),
8360
title: child.title ?? getToolKindTitle(kind, child) ?? child.name,
8461
subtitle: getToolKindSubtitle(kind, child) || undefined,
8562
filePath: getToolKindFilePath(kind, child) ?? undefined,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { toAgentToolKind } from "./tool-kind-to-agent-tool-kind.js";
4+
5+
describe("toAgentToolKind", () => {
6+
it("maps shared-compatible tool kinds directly", () => {
7+
expect(toAgentToolKind("read")).toBe("read");
8+
expect(toAgentToolKind("task")).toBe("task");
9+
expect(toAgentToolKind("task_output")).toBe("task_output");
10+
});
11+
12+
it("normalizes desktop-only tool kinds to the shared presentational subset", () => {
13+
expect(toAgentToolKind("glob")).toBe("search");
14+
expect(toAgentToolKind("tool_search")).toBe("other");
15+
expect(toAgentToolKind("todo")).toBe("other");
16+
});
17+
18+
it("preserves an omitted kind", () => {
19+
expect(toAgentToolKind(null)).toBeUndefined();
20+
expect(toAgentToolKind(undefined)).toBeUndefined();
21+
});
22+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import type { AgentToolKind } from "@acepe/ui/agent-panel";
2+
3+
import type { ToolKind } from "$lib/acp/types/tool-kind.js";
4+
5+
const TOOL_KIND_TO_AGENT_TOOL_KIND: Record<ToolKind, AgentToolKind> = {
6+
read: "read",
7+
edit: "edit",
8+
execute: "execute",
9+
search: "search",
10+
glob: "search",
11+
fetch: "fetch",
12+
web_search: "web_search",
13+
think: "think",
14+
task: "task",
15+
task_output: "task_output",
16+
todo: "other",
17+
question: "other",
18+
skill: "other",
19+
move: "other",
20+
delete: "other",
21+
enter_plan_mode: "other",
22+
exit_plan_mode: "other",
23+
create_plan: "other",
24+
tool_search: "other",
25+
other: "other",
26+
};
27+
28+
export function toAgentToolKind(kind: ToolKind): AgentToolKind;
29+
export function toAgentToolKind(kind: ToolKind | null | undefined): AgentToolKind | undefined;
30+
export function toAgentToolKind(kind: ToolKind | null | undefined): AgentToolKind | undefined {
31+
if (kind === null || kind === undefined) {
32+
return undefined;
33+
}
34+
35+
return TOOL_KIND_TO_AGENT_TOOL_KIND[kind];
36+
}

packages/desktop/src/lib/components/main-app-view/components/content/kanban-view.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import { WorktreeToggleControl } from "$lib/acp/components/worktree-toggle/index.js";
4848
import { getWorktreeDefaultStore } from "$lib/acp/components/worktree-toggle/worktree-default-store.svelte.js";
4949
import { loadWorktreeEnabled } from "$lib/acp/components/worktree-toggle/worktree-storage.js";
50+
import { toAgentToolKind } from "$lib/acp/components/tool-calls/tool-kind-to-agent-tool-kind.js";
5051
import { getToolCompactDisplayText } from "$lib/acp/registry/tool-kind-ui-registry.js";
5152
import { normalizeTitleForDisplay } from "$lib/acp/store/session-title-policy.js";
5253
import {
@@ -517,7 +518,7 @@
517518
: "pending" as const;
518519
return {
519520
id: tc.id,
520-
kind: toolDisplay.toolKind ? toolDisplay.toolKind : undefined,
521+
kind: toAgentToolKind(toolDisplay.toolKind),
521522
title: displayTitle ? displayTitle : tc.name,
522523
filePath,
523524
status,

0 commit comments

Comments
 (0)