Skip to content

Commit 49a12a9

Browse files
authored
Merge pull request #65 from DanWahlin/js-ts-quickstart
Update JS agents code + enhance output formatting
2 parents 951f0bc + 2971cfc commit 49a12a9

File tree

1 file changed

+121
-13
lines changed
  • samples/microsoft/javascript/mslearn-resources/quickstart/src

1 file changed

+121
-13
lines changed
Lines changed: 121 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { fileURLToPath } from 'url';
14
import { DefaultAzureCredential } from '@azure/identity';
25
import { AIProjectClient } from '@azure/ai-projects';
3-
import { AgentsClient } from '@azure/ai-agents';
6+
import { AgentsClient, ToolUtility, DoneEvent, ErrorEvent, RunStreamEvent, MessageStreamEvent } from '@azure/ai-agents';
47
import { config } from 'dotenv';
58
config();
69

10+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
11+
712
async 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

Comments
 (0)