Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.

Commit 6e71dd2

Browse files
authored
Add tool calling to generateText (#21)
* Fix tool calling on textGeneration * tidying up * chore: add changeset * wip
1 parent aaf8a81 commit 6e71dd2

File tree

19 files changed

+377
-57
lines changed

19 files changed

+377
-57
lines changed

.changeset/tough-wasps-peel.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"workers-ai-provider": patch
3+
---
4+
5+
Fixes tool calling for generateText

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ lerna-debug.log*
3131

3232
# misc
3333
.DS_Store
34+
.idea
3435

3536
/random

examples/ai-chat/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
"dependencies": {
99
"ai": "^4.0.14",
1010
"react": "^19.0.0",
11-
"react-dom": "^19.0.0"
11+
"react-dom": "^19.0.0",
12+
"zod": "^3.24.2"
1213
},
1314
"devDependencies": {
14-
"@cloudflare/workers-types": "^4.20241205.0",
15+
"@cloudflare/workers-types": "^4.20250214.0",
1516
"@types/react": "^19.0.1",
1617
"@types/react-dom": "^19.0.2",
1718
"wrangler": "3.95.0"

examples/ai-chat/src/server/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export default {
1818
messages: Parameters<typeof convertToCoreMessages>[0];
1919
}>();
2020
const result = streamText({
21-
// @ts-expect-error
2221
model: workersai("@cf/meta/llama-3.3-70b-instruct-fp8-fast"),
2322
messages: convertToCoreMessages(messages),
2423
});

examples/tool-calling/package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "@cloudflare/example-tool-calling",
3+
"private": true,
4+
"scripts": {
5+
"start": "wrangler dev",
6+
"deploy": "wrangler deploy"
7+
},
8+
"dependencies": {
9+
"@ai-sdk/openai": "^1.1.9",
10+
"ai": "^4.0.14",
11+
"react": "^19.0.0",
12+
"react-dom": "^19.0.0",
13+
"zod": "^3.24.2"
14+
},
15+
"devDependencies": {
16+
"@cloudflare/workers-types": "^4.20250214.0",
17+
"@types/react": "^19.0.1",
18+
"@types/react-dom": "^19.0.2",
19+
"wrangler": "3.95.0"
20+
},
21+
"overrides": {
22+
"react": "^19.0.0",
23+
"react-dom": "^19.0.0"
24+
}
25+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta name="description" content="Vercel AI ⤫ Workers AI" />
7+
<title>Workers AI Tool Calling</title>
8+
9+
<link
10+
rel="icon"
11+
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🙂‍↔️</text></svg>"
12+
/>
13+
14+
<!-- Link to Google Fonts -->
15+
<link
16+
rel="stylesheet"
17+
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap"
18+
/>
19+
20+
<!-- Favicon -->
21+
<link rel="icon" href="favicon.ico" type="image/x-icon" />
22+
23+
<!-- Social Media Metadata -->
24+
<meta property="og:title" content="YoHello Chat" />
25+
<meta
26+
property="og:description"
27+
content="Your website description goes here"
28+
/>
29+
<meta property="og:image" content="/og-image.jpg" />
30+
<meta name="twitter:card" content="/og-image.jpg" />
31+
32+
<!-- Add any other external libraries if needed -->
33+
</head>
34+
35+
<body>
36+
<div id="root"></div>
37+
<script src="/dist/index.js"></script>
38+
</body>
39+
</html>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { useChat } from "ai/react";
2+
import { useState } from "react";
3+
4+
type ChatProps = {
5+
id: string;
6+
};
7+
8+
export default function Chat(props: ChatProps) {
9+
const { input, handleInputChange, setInput } = useChat();
10+
const [messages, setMessages] = useState<{ role: string; content: string }[]>(
11+
[]
12+
);
13+
14+
const handleSubmit = async (e: React.FormEvent) => {
15+
e.preventDefault();
16+
17+
setMessages((prevMessages) => [
18+
...prevMessages,
19+
{ role: "user", content: input },
20+
]);
21+
const currentInput = input;
22+
setInput("");
23+
24+
const response = await fetch(`/api`, {
25+
method: "POST",
26+
headers: {
27+
"Content-Type": "application/json",
28+
},
29+
body: JSON.stringify({
30+
messages: [{ role: "user", content: currentInput }],
31+
}),
32+
});
33+
34+
if (!response.ok) {
35+
console.error("Failed to send message");
36+
return;
37+
}
38+
39+
const data = await response.text();
40+
41+
if (data) {
42+
setMessages((prevMessages) => [
43+
...prevMessages,
44+
{ role: "assistant", content: data },
45+
]);
46+
}
47+
};
48+
49+
return (
50+
<>
51+
{messages.map((message) => (
52+
<div key={message.id}>
53+
{message.role === "user" ? "User: " : "AI: "}
54+
{message.content}
55+
</div>
56+
))}
57+
58+
<form onSubmit={handleSubmit}>
59+
<input name="prompt" value={input} onChange={handleInputChange} />
60+
<button type="submit">Submit</button>
61+
</form>
62+
</>
63+
);
64+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { createRoot } from "react-dom/client";
2+
import Chat from "./chat";
3+
4+
function App() {
5+
return <Chat id="example-room" />;
6+
}
7+
8+
const root = createRoot(document.getElementById("root")!);
9+
10+
root.render(<App />);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"extends": "../../../../tsconfig.base.json",
3+
"compilerOptions": {
4+
"lib": ["DOM", "ESNext"]
5+
}
6+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { generateText, tool, type Message } from "ai";
2+
import { createWorkersAI } from "workers-ai-provider/src";
3+
import z from "zod";
4+
5+
export interface Env {
6+
AI: Ai;
7+
}
8+
9+
export default {
10+
async fetch(request, env) {
11+
const url = new URL(request.url);
12+
13+
if (request.method === "POST") {
14+
const { messages } = await request.json<{
15+
messages: Message[];
16+
}>();
17+
const workersai = createWorkersAI({ binding: env.AI });
18+
const model = workersai("@cf/meta/llama-3.3-70b-instruct-fp8-fast");
19+
20+
const weather = tool({
21+
description: "Get the weather in a location",
22+
parameters: z.object({
23+
location: z.string().describe("The location to get the weather for"),
24+
}),
25+
execute: async ({ location }) =>
26+
location === "London" ? "Raining" : "Sunny",
27+
});
28+
29+
const result = await generateText({
30+
model,
31+
messages,
32+
tools: {
33+
weather,
34+
},
35+
maxSteps: 5,
36+
});
37+
38+
return new Response(result.text);
39+
}
40+
41+
return new Response("Not Found!!", { status: 404 });
42+
},
43+
} satisfies ExportedHandler<Env>;

0 commit comments

Comments
 (0)