diff --git a/samples/microsoft/javascript/mslearn-resources/quickstart/src/quickstart.js b/samples/microsoft/javascript/mslearn-resources/quickstart/src/quickstart.js index 6ca834dfc..5d3c53068 100644 --- a/samples/microsoft/javascript/mslearn-resources/quickstart/src/quickstart.js +++ b/samples/microsoft/javascript/mslearn-resources/quickstart/src/quickstart.js @@ -1,9 +1,14 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; import { DefaultAzureCredential } from '@azure/identity'; import { AIProjectClient } from '@azure/ai-projects'; -import { AgentsClient } from '@azure/ai-agents'; +import { AgentsClient, ToolUtility, DoneEvent, ErrorEvent, RunStreamEvent, MessageStreamEvent } from '@azure/ai-agents'; import { config } from 'dotenv'; config(); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + async function chatCompletion() { // const endpoint = process.env.INFERENCE_ENDPOINT; @@ -11,7 +16,6 @@ async function chatCompletion() { const project = new AIProjectClient(endpoint, new DefaultAzureCredential()); const client = project.inference.azureOpenAI(); - const chatCompletion = await client.chat.completions.create({ deployment, messages: [ @@ -24,9 +28,9 @@ async function chatCompletion() { // } -chatCompletion().catch(console.error); +// chatCompletion().catch(console.error); -async function runAgent() { +async function runAgents() { // // Create an Azure AI Client @@ -39,36 +43,140 @@ async function runAgent() { name: 'my-agent', instructions: 'You are a helpful agent', }); + console.log(`\n==================== ๐Ÿ•ต๏ธ POEM AGENT ====================`); - // Create a thread and mesage + // Create a thread and message const thread = await client.createThread(); - const message = await client.createMessage(thread.id, 'user', 'hello, world!'); - - console.log(`Created message, message ID: ${message.id}`); + const prompt = 'Write me a poem about flowers'; + console.log(`\n---------------- ๐Ÿ“ User Prompt ---------------- \n${prompt}`); + await client.createMessage(thread.id, 'user', prompt); // Create run let run = await client.createRun(thread.id, agent.id); - console.log(`Usage for run ${run.id}:`, JSON.stringify(run.usage, null, 2)); // Wait for run to complete + console.log(`\n---------------- ๐Ÿšฆ Run Status ----------------`); while (['queued', 'in_progress', 'requires_action'].includes(run.status)) { + // Avoid adding a lot of messages to the console await new Promise((resolve) => setTimeout(resolve, 1000)); run = await client.getRun(thread.id, run.id); console.log(`Run status: ${run.status}`); } - console.log(`Usage for run ${run.id}:`, JSON.stringify(run.usage, null, 2)); + console.log('\n---------------- ๐Ÿ“Š Token Usage ----------------'); + console.table([run.usage]); + + const messages = await client.listMessages(thread.id); + const assistantMessage = messages.data.find(m => m.role === 'assistant'); + console.log('\n---------------- ๐Ÿ’ฌ Response ----------------'); + printAssistantMessage(assistantMessage); // Delete the Agent await client.deleteAgent(agent.id); console.log(`Deleted Agent, Agent ID: ${agent.id}`); + // // - // Create the file search agent - + // Upload a file named product_info_1.md + console.log(`\n==================== ๐Ÿ•ต๏ธ FILE AGENT ====================`); + const filePath = path.join(__dirname, '../../../../data/product_info_1.md'); + const fileStream = fs.createReadStream(filePath); + const file = await client.uploadFile(fileStream, 'assistants', { + fileName: 'product_info_1.md' + }); + console.log(`Uploaded file, ID: ${file.id}`); + const vectorStore = await client.createVectorStore({ + fileIds: [file.id], + name: 'my_vectorstore' + }); + console.log('\n---------------- ๐Ÿ—ƒ๏ธ Vector Store Info ----------------'); + console.table([ + { + 'Vector Store ID': vectorStore.id, + 'Usage (bytes)': vectorStore.usageBytes, + 'File Count': vectorStore.fileCounts?.total ?? 'N/A' + } + ]); + + // Create an Agent and a FileSearch tool + const fileSearchTool = ToolUtility.createFileSearchTool([vectorStore.id]); + const fileAgent = await client.createAgent(deployment, { + name: 'my-file-agent', + instructions: 'You are a helpful assistant and can search information from uploaded files', + tools: [fileSearchTool.definition], + toolResources: fileSearchTool.resources, + }); + + // Create a thread and message + const fileSearchThread = await client.createThread({ toolResources: fileSearchTool.resources }); + const filePrompt = 'What are the steps to setup the TrailMaster X4 Tent?'; + console.log(`\n---------------- ๐Ÿ“ User Prompt ---------------- \n${filePrompt}`); + await client.createMessage(fileSearchThread.id, 'user', filePrompt); + + // Create run + let fileSearchRun = await client.createRun(fileSearchThread.id, fileAgent.id).stream(); + + for await (const eventMessage of fileSearchRun) { + switch (eventMessage.event) { + case RunStreamEvent.ThreadRunCreated: + break; + case MessageStreamEvent.ThreadMessageDelta: + { + const messageDelta = eventMessage.data; + messageDelta.delta.content.forEach((contentPart) => { + if (contentPart.type === "text") { + const textContent = contentPart; + const textValue = textContent.text?.value || "No text"; + } + }); + } + break; + + case RunStreamEvent.ThreadRunCompleted: + break; + case ErrorEvent.Error: + console.log(`An error occurred. Data ${eventMessage.data}`); + break; + case DoneEvent.Done: + break; + } + } + + const fileSearchMessages = await client.listMessages(fileSearchThread.id); + const fileAssistantMessage = fileSearchMessages.data.find(m => m.role === 'assistant'); + console.log(`\n---------------- ๐Ÿ’ฌ Response ---------------- \n`); + printAssistantMessage(fileAssistantMessage); + + client.deleteVectorStore(vectorStore.id); + client.deleteFile(file.id); + client.deleteAgent(fileAgent.id); + console.log(`\n๐Ÿงน Deleted VectorStore, File, and FileAgent. FileAgent ID: ${fileAgent.id}`); + // } -runAgent().catch(console.error); +runAgents().catch(console.error); + +// Helper function to print assistant message content nicely (handles nested text.value) +function printAssistantMessage(message) { + if (!message || !Array.isArray(message.content)) { + console.log('No assistant message found or content is not in expected format.'); + return; + } + let output = message.content.map(c => { + if (typeof c.text === 'object' && c.text.value) { + return c.text.value; + } else if (typeof c.text === 'string') { + return c.text; + } else { + return JSON.stringify(c); + } + }).join(''); + if (typeof output !== 'string') { + console.log('Value is not a string:', output); + return; + } + output.split('\n').forEach(line => console.log(line)); +}