Skip to content

Commit 4bf8808

Browse files
committed
add tools
1 parent 39a1105 commit 4bf8808

File tree

1 file changed

+97
-7
lines changed

1 file changed

+97
-7
lines changed

packages/sample-app/src/sample_chatbot_interactive.ts

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import * as traceloop from "@traceloop/node-server-sdk";
22
import { openai } from "@ai-sdk/openai";
3-
import { streamText, CoreMessage } from "ai";
3+
import { streamText, CoreMessage, tool } from "ai";
44
import * as readline from "readline";
5+
import { z } from "zod";
56

67
import "dotenv/config";
78

@@ -25,13 +26,18 @@ const colors = {
2526
class InteractiveChatbot {
2627
private conversationHistory: CoreMessage[] = [];
2728
private rl: readline.Interface;
29+
private conversationId: string;
30+
private userId: string;
2831

2932
constructor() {
3033
this.rl = readline.createInterface({
3134
input: process.stdin,
3235
output: process.stdout,
3336
prompt: `${colors.cyan}${colors.bright}You: ${colors.reset}`,
3437
});
38+
// Generate unique IDs for this session
39+
this.conversationId = `conv-${Date.now()}`;
40+
this.userId = `user-${Math.random().toString(36).substring(7)}`;
3541
}
3642

3743
@traceloop.task({ name: "summarize_interaction" })
@@ -72,6 +78,12 @@ class InteractiveChatbot {
7278

7379
@traceloop.workflow({ name: "chat_interaction" })
7480
async processMessage(userMessage: string): Promise<string> {
81+
// Set associations for tracing
82+
traceloop.Associations.set([
83+
[traceloop.AssociationProperty.CONVERSATION_ID, this.conversationId],
84+
[traceloop.AssociationProperty.USER_ID, this.userId],
85+
]);
86+
7587
// Add user message to history
7688
this.conversationHistory.push({
7789
role: "user",
@@ -87,10 +99,85 @@ class InteractiveChatbot {
8799
{
88100
role: "system",
89101
content:
90-
"You are a helpful AI assistant. Provide clear, concise, and friendly responses.",
102+
"You are a helpful AI assistant with access to tools. Use the available tools when appropriate to provide accurate information. Provide clear, concise, and friendly responses.",
91103
},
92104
...this.conversationHistory,
93105
],
106+
tools: {
107+
calculator: tool({
108+
description:
109+
"Perform mathematical calculations. Supports basic arithmetic operations.",
110+
parameters: z.object({
111+
expression: z
112+
.string()
113+
.describe("The mathematical expression to evaluate (e.g., '2 + 2' or '10 * 5')"),
114+
}),
115+
execute: async ({ expression }) => {
116+
try {
117+
// Simple safe eval for basic math (only allow numbers and operators)
118+
const sanitized = expression.replace(/[^0-9+\-*/().\s]/g, "");
119+
const result = eval(sanitized);
120+
console.log(
121+
`\n${colors.yellow}🔧 Calculator: ${expression} = ${result}${colors.reset}`,
122+
);
123+
return { result, expression };
124+
} catch (error) {
125+
return { error: "Invalid mathematical expression" };
126+
}
127+
},
128+
}),
129+
getCurrentWeather: tool({
130+
description:
131+
"Get the current weather for a location. Use this when users ask about weather conditions.",
132+
parameters: z.object({
133+
location: z.string().describe("The city and country, e.g., 'London, UK'"),
134+
}),
135+
execute: async ({ location }) => {
136+
console.log(
137+
`\n${colors.yellow}🔧 Weather: Checking weather for ${location}${colors.reset}`,
138+
);
139+
// Simulated weather data
140+
const weatherConditions = ["sunny", "cloudy", "rainy", "partly cloudy"];
141+
const condition =
142+
weatherConditions[Math.floor(Math.random() * weatherConditions.length)];
143+
const temperature = Math.floor(Math.random() * 30) + 10; // 10-40°C
144+
return {
145+
location,
146+
temperature: `${temperature}°C`,
147+
condition,
148+
humidity: `${Math.floor(Math.random() * 40) + 40}%`,
149+
};
150+
},
151+
}),
152+
getTime: tool({
153+
description:
154+
"Get the current date and time. Use this when users ask about the current time or date.",
155+
parameters: z.object({
156+
timezone: z
157+
.string()
158+
.optional()
159+
.describe("Optional timezone (e.g., 'America/New_York')"),
160+
}),
161+
execute: async ({ timezone }) => {
162+
const now = new Date();
163+
const options: Intl.DateTimeFormatOptions = {
164+
timeZone: timezone,
165+
dateStyle: "full",
166+
timeStyle: "long",
167+
};
168+
const formatted = now.toLocaleString("en-US", options);
169+
console.log(
170+
`\n${colors.yellow}🔧 Time: ${formatted}${colors.reset}`,
171+
);
172+
return {
173+
datetime: formatted,
174+
timestamp: now.toISOString(),
175+
timezone: timezone || "local",
176+
};
177+
},
178+
}),
179+
},
180+
maxSteps: 5,
94181
experimental_telemetry: { isEnabled: true },
95182
});
96183

@@ -102,11 +189,14 @@ class InteractiveChatbot {
102189

103190
console.log("\n");
104191

105-
// Add assistant response to history
106-
this.conversationHistory.push({
107-
role: "assistant",
108-
content: fullResponse,
109-
});
192+
// Wait for the full response to complete to get all messages including tool calls
193+
const finalResult = await result.response;
194+
195+
// Add all response messages (including tool calls and results) to history
196+
// This ensures the conversation history includes the complete interaction
197+
for (const message of finalResult.messages) {
198+
this.conversationHistory.push(message);
199+
}
110200

111201
// Generate summary for this interaction
112202
await this.generateSummary(userMessage, fullResponse);

0 commit comments

Comments
 (0)