Show task notifications as synthetic tool calls in chat (#79)

* fix(server): render claude task notifications as synthetic tool calls

* refactor(claude): extract task-notification tool-call mapper

* refactor: drive tool icons from plain_text detail metadata

* refactor(claude): make task-notification parsing schema-first
This commit is contained in:
Mohamed Boudra
2026-02-24 18:15:23 +07:00
committed by GitHub
parent 9d2ec0e9e1
commit 0832b12608
11 changed files with 659 additions and 30 deletions
@@ -146,4 +146,42 @@ describe("shared messages tool_call schema", () => {
}
}
});
it("parses plain_text detail with icon and rejects unknown icon names", () => {
const parsed = AgentTimelineItemPayloadSchema.parse({
type: "tool_call",
callId: "call_plain_text_1",
name: "task_notification",
status: "completed",
error: null,
detail: {
type: "plain_text",
label: "Background task completed",
icon: "wrench",
},
});
expect(parsed.type).toBe("tool_call");
if (parsed.type === "tool_call") {
expect(parsed.detail.type).toBe("plain_text");
if (parsed.detail.type === "plain_text") {
expect(parsed.detail.icon).toBe("wrench");
}
}
const invalid = AgentTimelineItemPayloadSchema.safeParse({
type: "tool_call",
callId: "call_plain_text_invalid",
name: "task_notification",
status: "completed",
error: null,
detail: {
type: "plain_text",
label: "Background task completed",
icon: "laser",
},
});
expect(invalid.success).toBe(false);
});
});
+2
View File
@@ -2,6 +2,7 @@ import { z } from 'zod'
import { AGENT_LIFECYCLE_STATUSES } from './agent-lifecycle.js'
import { MAX_EXPLICIT_AGENT_TITLE_CHARS } from '../server/agent/agent-title-limits.js'
import { AgentProviderSchema } from '../server/agent/provider-manifest.js'
import { TOOL_CALL_ICON_NAMES } from '../server/agent/agent-sdk-types.js'
import type {
AgentCapabilityFlags,
AgentModelDefinition,
@@ -215,6 +216,7 @@ const ToolCallDetailPayloadSchema: z.ZodType<ToolCallDetail> = z.discriminatedUn
type: z.literal('plain_text'),
label: z.string().optional(),
text: z.string().optional(),
icon: z.enum(TOOL_CALL_ICON_NAMES).optional(),
}),
z.object({
type: z.literal('unknown'),