Skip to content

Commit d6e05d1

Browse files
committed
[Claude] Add support for custom tools
1 parent e3969bf commit d6e05d1

File tree

3 files changed

+44
-27
lines changed

3 files changed

+44
-27
lines changed

src/providers/claude/markdown.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import type { ContentToolResult, ContentToolUse, Message } from "./models";
1+
import * as v from "valibot";
2+
import {
3+
artifacts as artifactModels,
4+
repl,
5+
type ContentToolResult,
6+
type ContentToolUse,
7+
type Message,
8+
} from "./models";
29

310
interface RenderContext {
411
artifacts: Map<
@@ -45,20 +52,27 @@ function renderToolUse(ctx: RenderContext, content: ContentToolUse): boolean {
4552
switch (name) {
4653
case "artifacts":
4754
return renderToolUseArtifact(ctx, content);
48-
case "repl":
55+
case "repl": {
56+
const { input } = v.parse(repl.toolUseSchema, content);
4957
ctx.markdown.push(`## Tool use: ${name}`);
5058
ctx.markdown.push(`\`\`\`js\n${input.code.trim()}\n\`\`\``);
5159
return true;
60+
}
61+
default: {
62+
const str =
63+
typeof input === "string" ? input : JSON.stringify(input, null, 2);
64+
ctx.markdown.push(`## Tool use: ${name}`);
65+
ctx.markdown.push(`\`\`\`\n${str.trim()}\n\`\`\``);
66+
return true;
67+
}
5268
}
5369
}
5470

5571
function renderToolUseArtifact(
5672
ctx: RenderContext,
5773
content: ContentToolUse,
5874
): boolean {
59-
const { name, input } = content;
60-
if (name !== "artifacts") return false;
61-
75+
const { input } = v.parse(artifactModels.toolUseSchema, content);
6276
const { artifacts, markdown } = ctx;
6377

6478
switch (input.command) {
@@ -110,16 +124,18 @@ function renderToolResult(
110124
ctx: RenderContext,
111125
content: ContentToolResult,
112126
): boolean {
113-
const { name, content: result } = content;
114-
switch (name) {
115-
case "artifacts":
116-
return false;
117-
case "repl":
118-
for (const item of result) {
119-
ctx.markdown.push(
120-
`\`\`\`json\n${JSON.stringify(item.text, null, 2)}\n\`\`\``,
121-
);
122-
}
123-
return true;
127+
const { name } = content;
128+
if (name === "artifacts") {
129+
return false;
130+
}
131+
132+
const { content: result } = v.parse(repl.toolResultSchema, content);
133+
for (const item of result) {
134+
ctx.markdown.push("<details><summary>Tool result</summary>");
135+
ctx.markdown.push(
136+
`\`\`\`json\n${JSON.stringify(item.text, null, 2)}\n\`\`\``,
137+
);
138+
ctx.markdown.push("</details>\n\n");
124139
}
140+
return true;
125141
}

src/providers/claude/models/index.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
import * as v from "valibot";
2-
import * as artifacts from "./tool_artifacts";
3-
import * as repl from "./tool_repl";
2+
export * as artifacts from "./tool_artifacts";
3+
export * as repl from "./tool_repl";
44

55
const messageContentTextSchema = v.object({
66
type: v.literal("text"),
77
text: v.string(),
88
});
99

10-
const messageContentToolUseSchema = v.variant("name", [
11-
artifacts.toolUseSchema,
12-
repl.toolUseSchema,
13-
]);
10+
const messageContentToolUseSchema = v.object({
11+
type: v.literal("tool_use"),
12+
name: v.string(),
13+
input: v.unknown(),
14+
});
1415

1516
export type ContentToolUse = v.InferOutput<typeof messageContentToolUseSchema>;
1617

17-
const messageContentToolResultSchema = v.variant("name", [
18-
artifacts.toolResultSchema,
19-
repl.toolResultSchema,
20-
]);
18+
const messageContentToolResultSchema = v.object({
19+
type: v.literal("tool_result"),
20+
name: v.string(),
21+
content: v.array(v.unknown()),
22+
});
2123

2224
export type ContentToolResult = v.InferOutput<
2325
typeof messageContentToolResultSchema

src/providers/claude/models/tool_repl.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export const toolUseSchema = v.object({
1212

1313
export const toolResultSchema = v.object({
1414
type: v.literal("tool_result"),
15-
name,
1615
content: v.array(
1716
v.object({
1817
text: v.pipe(

0 commit comments

Comments
 (0)