1+ import fs from 'fs' ;
2+ import path from 'path' ;
3+ import { fileURLToPath } from 'url' ;
14import { DefaultAzureCredential } from '@azure/identity' ;
25import { AIProjectClient } from '@azure/ai-projects' ;
3- import { AgentsClient } from '@azure/ai-agents' ;
6+ import { AgentsClient , ToolUtility , DoneEvent , ErrorEvent , RunStreamEvent , MessageStreamEvent } from '@azure/ai-agents' ;
47import { config } from 'dotenv' ;
58config ( ) ;
69
10+ const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
11+
712async function chatCompletion ( ) {
813 // <chat_completion>
914 const endpoint = process . env . INFERENCE_ENDPOINT ;
1015 const deployment = process . env . MODEL_DEPLOYMENT_NAME || 'gpt-4o' ;
1116 const project = new AIProjectClient ( endpoint , new DefaultAzureCredential ( ) ) ;
1217
1318 const client = project . inference . azureOpenAI ( ) ;
14-
1519 const chatCompletion = await client . chat . completions . create ( {
1620 deployment,
1721 messages : [
@@ -24,9 +28,9 @@ async function chatCompletion() {
2428 // </chat_completion>
2529}
2630
27- chatCompletion ( ) . catch ( console . error ) ;
31+ // chatCompletion().catch(console.error);
2832
29- async function runAgent ( ) {
33+ async function runAgents ( ) {
3034 // <create_and_run_agent>
3135
3236 // Create an Azure AI Client
@@ -39,36 +43,140 @@ async function runAgent() {
3943 name : 'my-agent' ,
4044 instructions : 'You are a helpful agent' ,
4145 } ) ;
46+ console . log ( `\n==================== 🕵️ POEM AGENT ====================` ) ;
4247
43- // Create a thread and mesage
48+ // Create a thread and message
4449 const thread = await client . createThread ( ) ;
45- const message = await client . createMessage ( thread . id , 'user' , 'hello, world!' ) ;
46-
47- console . log ( `Created message, message ID: ${ message . id } ` ) ;
50+ const prompt = 'Write me a poem about flowers' ;
51+ console . log ( `\n---------------- 📝 User Prompt ---------------- \n ${ prompt } ` ) ;
52+ await client . createMessage ( thread . id , 'user' , prompt ) ;
4853
4954 // Create run
5055 let run = await client . createRun ( thread . id , agent . id ) ;
51- console . log ( `Usage for run ${ run . id } :` , JSON . stringify ( run . usage , null , 2 ) ) ;
5256
5357 // Wait for run to complete
58+ console . log ( `\n---------------- 🚦 Run Status ----------------` ) ;
5459 while ( [ 'queued' , 'in_progress' , 'requires_action' ] . includes ( run . status ) ) {
60+ // Avoid adding a lot of messages to the console
5561 await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
5662 run = await client . getRun ( thread . id , run . id ) ;
5763 console . log ( `Run status: ${ run . status } ` ) ;
5864 }
5965
60- console . log ( `Usage for run ${ run . id } :` , JSON . stringify ( run . usage , null , 2 ) ) ;
66+ console . log ( '\n---------------- 📊 Token Usage ----------------' ) ;
67+ console . table ( [ run . usage ] ) ;
68+
69+ const messages = await client . listMessages ( thread . id ) ;
70+ const assistantMessage = messages . data . find ( m => m . role === 'assistant' ) ;
71+ console . log ( '\n---------------- 💬 Response ----------------' ) ;
72+ printAssistantMessage ( assistantMessage ) ;
6173
6274 // Delete the Agent
6375 await client . deleteAgent ( agent . id ) ;
6476 console . log ( `Deleted Agent, Agent ID: ${ agent . id } ` ) ;
77+
6578 // </create_and_run_agent>
6679
6780 // <create_filesearch_agent>
6881
69- // Create the file search agent
70-
82+ // Upload a file named product_info_1.md
83+ console . log ( `\n==================== 🕵️ FILE AGENT ====================` ) ;
84+ const filePath = path . join ( __dirname , '../../../../data/product_info_1.md' ) ;
85+ const fileStream = fs . createReadStream ( filePath ) ;
86+ const file = await client . uploadFile ( fileStream , 'assistants' , {
87+ fileName : 'product_info_1.md'
88+ } ) ;
89+ console . log ( `Uploaded file, ID: ${ file . id } ` ) ;
90+ const vectorStore = await client . createVectorStore ( {
91+ fileIds : [ file . id ] ,
92+ name : 'my_vectorstore'
93+ } ) ;
94+ console . log ( '\n---------------- 🗃️ Vector Store Info ----------------' ) ;
95+ console . table ( [
96+ {
97+ 'Vector Store ID' : vectorStore . id ,
98+ 'Usage (bytes)' : vectorStore . usageBytes ,
99+ 'File Count' : vectorStore . fileCounts ?. total ?? 'N/A'
100+ }
101+ ] ) ;
102+
103+ // Create an Agent and a FileSearch tool
104+ const fileSearchTool = ToolUtility . createFileSearchTool ( [ vectorStore . id ] ) ;
105+ const fileAgent = await client . createAgent ( deployment , {
106+ name : 'my-file-agent' ,
107+ instructions : 'You are a helpful assistant and can search information from uploaded files' ,
108+ tools : [ fileSearchTool . definition ] ,
109+ toolResources : fileSearchTool . resources ,
110+ } ) ;
111+
112+ // Create a thread and message
113+ const fileSearchThread = await client . createThread ( { toolResources : fileSearchTool . resources } ) ;
114+ const filePrompt = 'What are the steps to setup the TrailMaster X4 Tent?' ;
115+ console . log ( `\n---------------- 📝 User Prompt ---------------- \n${ filePrompt } ` ) ;
116+ await client . createMessage ( fileSearchThread . id , 'user' , filePrompt ) ;
117+
118+ // Create run
119+ let fileSearchRun = await client . createRun ( fileSearchThread . id , fileAgent . id ) . stream ( ) ;
120+
121+ for await ( const eventMessage of fileSearchRun ) {
122+ switch ( eventMessage . event ) {
123+ case RunStreamEvent . ThreadRunCreated :
124+ break ;
125+ case MessageStreamEvent . ThreadMessageDelta :
126+ {
127+ const messageDelta = eventMessage . data ;
128+ messageDelta . delta . content . forEach ( ( contentPart ) => {
129+ if ( contentPart . type === "text" ) {
130+ const textContent = contentPart ;
131+ const textValue = textContent . text ?. value || "No text" ;
132+ }
133+ } ) ;
134+ }
135+ break ;
136+
137+ case RunStreamEvent . ThreadRunCompleted :
138+ break ;
139+ case ErrorEvent . Error :
140+ console . log ( `An error occurred. Data ${ eventMessage . data } ` ) ;
141+ break ;
142+ case DoneEvent . Done :
143+ break ;
144+ }
145+ }
146+
147+ const fileSearchMessages = await client . listMessages ( fileSearchThread . id ) ;
148+ const fileAssistantMessage = fileSearchMessages . data . find ( m => m . role === 'assistant' ) ;
149+ console . log ( `\n---------------- 💬 Response ---------------- \n` ) ;
150+ printAssistantMessage ( fileAssistantMessage ) ;
151+
152+ client . deleteVectorStore ( vectorStore . id ) ;
153+ client . deleteFile ( file . id ) ;
154+ client . deleteAgent ( fileAgent . id ) ;
155+ console . log ( `\n🧹 Deleted VectorStore, File, and FileAgent. FileAgent ID: ${ fileAgent . id } ` ) ;
156+
71157 // </create_filesearch_agent>
72158}
73159
74- runAgent ( ) . catch ( console . error ) ;
160+ runAgents ( ) . catch ( console . error ) ;
161+
162+ // Helper function to print assistant message content nicely (handles nested text.value)
163+ function printAssistantMessage ( message ) {
164+ if ( ! message || ! Array . isArray ( message . content ) ) {
165+ console . log ( 'No assistant message found or content is not in expected format.' ) ;
166+ return ;
167+ }
168+ let output = message . content . map ( c => {
169+ if ( typeof c . text === 'object' && c . text . value ) {
170+ return c . text . value ;
171+ } else if ( typeof c . text === 'string' ) {
172+ return c . text ;
173+ } else {
174+ return JSON . stringify ( c ) ;
175+ }
176+ } ) . join ( '' ) ;
177+ if ( typeof output !== 'string' ) {
178+ console . log ( 'Value is not a string:' , output ) ;
179+ return ;
180+ }
181+ output . split ( '\n' ) . forEach ( line => console . log ( line ) ) ;
182+ }
0 commit comments