Skip to content

Commit d2a5293

Browse files
committed
original engineering code
1 parent edf3e36 commit d2a5293

File tree

8 files changed

+973
-18
lines changed

8 files changed

+973
-18
lines changed
135 KB
Loading

quickstarts/ai-agents/ts/data/nifty500QuarterlyResults.csv

Lines changed: 502 additions & 6 deletions
Large diffs are not rendered by default.

quickstarts/ai-agents/ts/data/undefinedImageFile.png

Lines changed: 0 additions & 6 deletions
This file was deleted.

quickstarts/ai-agents/ts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
"name": "azureaiagents",
33
"version": "1.0.0",
44
"main": "index.js",
5-
"type": "module",
65
"scripts": {
76
"build": "tsc",
87
"start": "tsc && node -r dotenv/config dist/index.js",
8+
"start:js": "node -r dotenv/config src/original.js",
99
"test": "echo \"Error: no test specified\" && exit 1"
1010
},
1111
"author": "",

quickstarts/ai-agents/ts/src/index.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import "dotenv/config";
2424
const projectEndpoint = process.env["PROJECT_ENDPOINT"]!;
2525
const modelDeploymentName = process.env["MODEL_DEPLOYMENT_NAME"]! || "gpt-4o";
2626

27+
if (!process.env["PROJECT_ENDPOINT"]) {
28+
throw new Error("PROJECT_ENDPOINT environment variable is required");
29+
}
30+
2731
/**
2832
* Initialize the client, upload files, and create agent and thread
2933
*/
@@ -138,12 +142,12 @@ async function executeAgentTask(
138142
/**
139143
* Retrieve and process the results from the agent
140144
*/
141-
async function processResults(client: AgentsClient, threadId: string): Promise<any[]> {
145+
async function processResults(client: AgentsClient, threadId: string): Promise<ThreadMessage[]> {
142146
console.log("Processing results...");
143147

144148
// Print the messages from the agent
145149
const messagesIterator = client.messages.list(threadId);
146-
const messagesArray = [];
150+
const messagesArray: ThreadMessage[] = [];
147151

148152
for await (const m of messagesIterator) {
149153
messagesArray.push(m);
@@ -176,7 +180,7 @@ async function processResults(client: AgentsClient, threadId: string): Promise<a
176180
*/
177181
async function downloadGeneratedFiles(
178182
client: AgentsClient,
179-
messages: any[]
183+
messages: ThreadMessage[]
180184
): Promise<string | undefined> {
181185
console.log("Checking for and downloading generated files...");
182186

@@ -233,7 +237,14 @@ async function downloadGeneratedFiles(
233237
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
234238
}
235239
const buffer = Buffer.concat(chunks);
236-
fs.writeFileSync(imageFileName, buffer);
240+
241+
try {
242+
fs.writeFileSync(imageFileName, buffer);
243+
console.log(`File saved to ${imageFileName}`);
244+
} catch (error) {
245+
console.error(`Error saving file to ${imageFileName}:`, error);
246+
}
247+
237248
console.log(`File saved to ${imageFileName}`);
238249

239250
return imageFileName;
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
// index.ts
2+
// This sample demonstrates how to use the Azure AI Agents SDK
3+
// It's organized in phases: setup, execution, processing results, downloading files, and cleanup
4+
import {
5+
RunStreamEvent,
6+
MessageStreamEvent,
7+
DoneEvent,
8+
ErrorEvent,
9+
AgentsClient,
10+
isOutputOfType,
11+
ToolUtility,
12+
Agent,
13+
Thread,
14+
File,
15+
Message,
16+
} from "@azure/ai-agents";
17+
import { DefaultAzureCredential } from "@azure/identity";
18+
19+
import * as fs from "fs";
20+
import * as path from "node:path";
21+
import "dotenv/config";
22+
23+
// Configuration
24+
const projectEndpoint = process.env["PROJECT_ENDPOINT"]!;
25+
const modelDeploymentName = process.env["MODEL_DEPLOYMENT_NAME"]! || "gpt-4o";
26+
27+
/**
28+
* Initialize the client, upload files, and create agent and thread
29+
*/
30+
async function setupAgentAndResources(client: AgentsClient): Promise<{
31+
agent: Agent;
32+
thread: Thread;
33+
localFile: File;
34+
}> {
35+
console.log("Setting up agent and resources...");
36+
37+
// Upload file and wait for it to be processed
38+
const filePath = "./data/nifty500QuarterlyResults.csv";
39+
const localFileStream = fs.createReadStream(filePath);
40+
const localFile = await client.files.upload(localFileStream, "assistants", {
41+
fileName: "myLocalFile",
42+
});
43+
console.log(`Uploaded local file, file ID : ${localFile.id}`);
44+
45+
// Create code interpreter tool
46+
const codeInterpreterTool = ToolUtility.createCodeInterpreterTool([localFile.id]);
47+
48+
// Create agent with code interpreter tool
49+
const agent = await client.createAgent(modelDeploymentName, {
50+
name: "my-agent",
51+
instructions: "You are a helpful agent",
52+
tools: [codeInterpreterTool.definition],
53+
toolResources: codeInterpreterTool.resources,
54+
});
55+
console.log(`Created agent, agent ID: ${agent.id}`);
56+
57+
// Create a thread
58+
const thread = await client.threads.create();
59+
console.log(`Created thread, thread ID: ${thread.id}`);
60+
61+
return { agent, thread, localFile };
62+
}
63+
64+
/**
65+
* Execute a task by sending a message to the agent and processing the streaming response
66+
*/
67+
async function executeAgentTask(
68+
client: AgentsClient,
69+
thread: Thread,
70+
agent: Agent,
71+
userPrompt: string
72+
): Promise<Message> {
73+
console.log("Executing agent task...");
74+
75+
// Create a message
76+
const message = await client.messages.create(thread.id, "user", userPrompt);
77+
console.log(`Created message, message ID: ${message.id}`);
78+
79+
// Create and execute a run with streaming responses
80+
const streamEventMessages = await client.runs.create(thread.id, agent.id).stream();
81+
82+
// Process streaming events
83+
for await (const eventMessage of streamEventMessages) {
84+
switch (eventMessage.event) {
85+
case RunStreamEvent.ThreadRunCreated:
86+
// Type check or cast to access the status property safely
87+
if (typeof eventMessage.data === 'object' && eventMessage.data !== null && 'status' in eventMessage.data) {
88+
console.log(`ThreadRun status: ${eventMessage.data.status}`);
89+
} else {
90+
console.log(`ThreadRun created: ${JSON.stringify(eventMessage.data)}`);
91+
}
92+
break;
93+
94+
case MessageStreamEvent.ThreadMessageDelta:
95+
{
96+
const messageDelta = eventMessage.data;
97+
// Type check or cast to access the delta property safely
98+
if (typeof messageDelta === 'object' &&
99+
messageDelta !== null &&
100+
'delta' in messageDelta &&
101+
messageDelta.delta &&
102+
'content' in messageDelta.delta &&
103+
Array.isArray(messageDelta.delta.content)) {
104+
105+
messageDelta.delta.content.forEach((contentPart) => {
106+
if (contentPart.type === "text") {
107+
const textContent = contentPart;
108+
// Add type guard for text content
109+
if ('text' in textContent &&
110+
textContent.text &&
111+
typeof textContent.text === 'object') {
112+
const textValue = textContent.text.value || "No text";
113+
console.log(`Text delta received:: ${textValue}`);
114+
}
115+
}
116+
});
117+
}
118+
}
119+
break;
120+
121+
case RunStreamEvent.ThreadRunCompleted:
122+
console.log("Thread Run Completed");
123+
break;
124+
125+
case ErrorEvent.Error:
126+
console.log(`An error occurred. Data ${eventMessage.data}`);
127+
break;
128+
129+
case DoneEvent.Done:
130+
console.log("Stream completed.");
131+
break;
132+
}
133+
}
134+
135+
return message;
136+
}
137+
138+
/**
139+
* Retrieve and process the results from the agent
140+
*/
141+
async function processResults(client: AgentsClient, threadId: string): Promise<any[]> {
142+
console.log("Processing results...");
143+
144+
// Print the messages from the agent
145+
const messagesIterator = client.messages.list(threadId);
146+
const messagesArray = [];
147+
148+
for await (const m of messagesIterator) {
149+
messagesArray.push(m);
150+
}
151+
152+
console.log(`Message Details:`);
153+
messagesArray.forEach((m) => {
154+
console.log(`File Paths:`);
155+
console.log(`Type: ${m.content[0].type}`);
156+
157+
if (isOutputOfType(m.content[0], "text")) {
158+
const textContent = m.content[0];
159+
// Use type guard to safely access text property
160+
if ('text' in textContent &&
161+
textContent.text &&
162+
typeof textContent.text === 'object' &&
163+
'value' in textContent.text) {
164+
console.log(`Text: ${textContent.text.value}`);
165+
}
166+
}
167+
168+
console.log(`File ID: ${m.id}`);
169+
});
170+
171+
return messagesArray;
172+
}
173+
174+
/**
175+
* Download and save any files generated by the agent
176+
*/
177+
async function downloadGeneratedFiles(
178+
client: AgentsClient,
179+
messages: any[]
180+
): Promise<string | undefined> {
181+
console.log("Checking for and downloading generated files...");
182+
183+
// Get most recent message from the assistant
184+
const assistantMessage = messages.find((msg) => msg.role === "assistant");
185+
if (!assistantMessage) {
186+
console.log("No assistant message found");
187+
return;
188+
}
189+
190+
const textContent = assistantMessage.content.find((content) => isOutputOfType(content, "text"));
191+
if (!textContent) {
192+
console.log("No text content found in assistant message");
193+
return;
194+
}
195+
196+
// Save the newly created file
197+
console.log(`Saving new files...`);
198+
const imageFileOutput = messages[0].content[0];
199+
200+
// Use type checking to safely access the imageFile property
201+
let imageFileId = '';
202+
203+
// Check if content has image file type and has the correct structure
204+
if (isOutputOfType(imageFileOutput, "image_file") &&
205+
'image_file' in imageFileOutput &&
206+
imageFileOutput.image_file &&
207+
typeof imageFileOutput.image_file === 'object') {
208+
// Use type assertion after validating the structure
209+
const typedImageFile = imageFileOutput.image_file as { fileId: string };
210+
if ('fileId' in typedImageFile && typeof typedImageFile.fileId === 'string') {
211+
imageFileId = typedImageFile.fileId;
212+
}
213+
}
214+
215+
if (!imageFileId) {
216+
console.log("No image file found in the message content");
217+
return;
218+
}
219+
220+
const imageFileName = path.resolve(
221+
"./data/" + (await client.files.get(imageFileId)).filename + "ImageFile.png",
222+
);
223+
console.log(`Image file name : ${imageFileName}`);
224+
225+
const fileContent = await (await client.files.getContent(imageFileId).asNodeStream()).body;
226+
if (!fileContent) {
227+
console.log("No file content available");
228+
return;
229+
}
230+
231+
const chunks = [];
232+
for await (const chunk of fileContent) {
233+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
234+
}
235+
const buffer = Buffer.concat(chunks);
236+
fs.writeFileSync(imageFileName, buffer);
237+
console.log(`File saved to ${imageFileName}`);
238+
239+
return imageFileName;
240+
}
241+
242+
/**
243+
* Clean up resources - delete files and agent
244+
*/
245+
async function cleanupResources(
246+
client: AgentsClient,
247+
agentId: string,
248+
fileId: string
249+
): Promise<void> {
250+
console.log("Cleaning up resources...");
251+
252+
// Delete the file from the agent to free up space
253+
await client.files.delete(fileId);
254+
console.log(`Deleted file, file ID : ${fileId}`);
255+
256+
// Delete the agent once done
257+
await client.deleteAgent(agentId);
258+
console.log(`Deleted agent, agent ID: ${agentId}`);
259+
}
260+
261+
/**
262+
* Main function to demonstrate the Azure AI Agents SDK
263+
*/
264+
async function main() {
265+
try {
266+
// Create an Azure AI Client
267+
const client = new AgentsClient(projectEndpoint, new DefaultAzureCredential());
268+
269+
// Step 1: Setup agent and resources
270+
const { agent, thread, localFile } = await setupAgentAndResources(client);
271+
272+
// Step 2: Execute a task
273+
const userPrompt = "Could you please create a bar chart in the TRANSPORTATION sector for the operating profit from the uploaded CSV file and provide the file to me?";
274+
await executeAgentTask(client, thread, agent, userPrompt);
275+
276+
// Step 3: Process the results
277+
const messages = await processResults(client, thread.id);
278+
279+
// Step 4: Download any generated files
280+
await downloadGeneratedFiles(client, messages);
281+
282+
// Step 5: Cleanup resources
283+
await cleanupResources(client, agent.id, localFile.id);
284+
285+
console.log("Azure AI Agents sample completed successfully!");
286+
} catch (error) {
287+
console.error("The sample encountered an error:", error);
288+
}
289+
}
290+
291+
// Execute the sample
292+
main();

0 commit comments

Comments
 (0)