11import * as traceloop from "@traceloop/node-server-sdk" ;
22import { openai } from "@ai-sdk/openai" ;
3- import { streamText , CoreMessage } from "ai" ;
3+ import { streamText , CoreMessage , tool } from "ai" ;
44import * as readline from "readline" ;
5+ import { z } from "zod" ;
56
67import "dotenv/config" ;
78
@@ -25,13 +26,18 @@ const colors = {
2526class 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