Skip to content

Commit 709e76d

Browse files
authored
Update code-interpreter-samples.md
Porting over the SDK sample that uses code interpreter tool to create an image, download the image and display it using streaming and additional instructions.
1 parent 9315c8b commit 709e76d

File tree

1 file changed

+151
-73
lines changed

1 file changed

+151
-73
lines changed

articles/ai-services/agents/how-to/tools/code-interpreter-samples.md

Lines changed: 151 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -144,125 +144,203 @@ for image_content in messages.image_contents:
144144

145145
:::zone pivot="csharp"
146146

147-
## Create a project client
147+
# How to use the code interpreter tool
148148

149-
To use code interpreter, first you need to create a project client, which will contain a connection string to your AI project, and will be used to authenticate API calls.
149+
In this example we will demonstrate the Agent streaming support, code interpreter creating an image and downloading and viewing the image.
150150

151-
```csharp
152-
var connectionString = Environment.GetEnvironmentVariable("PROJECT_CONNECTION_STRING");
153-
AgentsClient client = new AgentsClient(connectionString, new DefaultAzureCredential());
154-
```
151+
1. First, we set up configuration using `appsettings.json`, create a `PersistentAgentsClient`, and then create a `PersistentAgent` with the Code Interpreter tool.
155152

156-
## Upload a File
153+
```C# Snippet:AgentsStreaming_Step1_Common_SetupClientAndConfig
154+
using Azure;
155+
using Azure.AI.Agents.Persistent;
156+
using Azure.Identity;
157+
using Microsoft.Extensions.Configuration;
158+
using System.Diagnostics;
157159

158-
Files can be uploaded and then referenced by agents or messages. First, use the generalized upload API with a `purpose` of `Agents` to make a file ID available. Once uploaded, the file ID can then be provided to create a vector store for it. The vector store ID can then be provided to an agent upon creation.
160+
IConfigurationRoot configuration = new ConfigurationBuilder()
161+
.SetBasePath(AppContext.BaseDirectory)
162+
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
163+
.Build();
159164

160-
```csharp
161-
// Upload a file and wait for it to be processed
162-
Response<AgentFile> uploadAgentFileResponse = await client.UploadFileAsync(
163-
filePath: "sample_file_for_upload.txt",
164-
purpose: AgentFilePurpose.Agents);
165+
var projectEndpoint = configuration["ProjectEndpoint"];
166+
var modelDeploymentName = configuration["ModelDeploymentName"];
165167

166-
AgentFile uploadedAgentFile = uploadAgentFileResponse.Value;
168+
PersistentAgentsClient client = new(projectEndpoint, new DefaultAzureCredential());
169+
```
167170

168-
// Create a vector store with the file and wait for it to be processed.
169-
// If you do not specify a vector store, create_message will create a vector store with a default expiration policy of seven days after they were last active
170-
VectorStore vectorStore = await client.CreateVectorStoreAsync(
171-
fileIds: new List<string> { uploadedAgentFile.Id },
172-
name: "my_vector_store");
171+
Synchronous sample:
173172

174-
CodeInterpreterToolResource codeInterpreterToolResource = new CodeInterpreterToolResource();
175-
CodeInterpreterToolResource.VectorStoreIds.Add(vectorStore.Id);
173+
```C# Snippet:AgentsStreaming_Step1_Sync_CreateAgent
174+
PersistentAgent agent = client.Administration.CreateAgent(
175+
model: modelDeploymentName,
176+
name: "My Friendly Test Agent",
177+
instructions: "You politely help with math questions. Use the code interpreter tool when asked to visualize numbers.",
178+
tools: [new CodeInterpreterToolDefinition()]
179+
);
176180
```
177181

178-
## Create an Agent with the Code Interpreter Tool
182+
Asynchronous sample:
179183

180-
```csharp
181-
Response<Agent> agentResponse = await client.CreateAgentAsync(
182-
model: "gpt-4o-mini",
183-
name: "My agent",
184-
instructions: "You are a helpful agent.",
185-
tools: new List<ToolDefinition> { new CodeInterpreterToolDefinition() },
186-
toolResources: new ToolResources() { CodeInterpreter = codeInterpreterToolResource });
187-
Agent agent = agentResponse.Value;
184+
```C# Snippet:AgentsStreaming_Step1_Async_CreateAgent
185+
PersistentAgent agent = await client.Administration.CreateAgentAsync(
186+
model: modelDeploymentName,
187+
name: "My Friendly Test Agent",
188+
instructions: "You politely help with math questions. Use the code interpreter tool when asked to visualize numbers.",
189+
tools: [new CodeInterpreterToolDefinition()]
190+
);
188191
```
189192

190-
## Create a Thread, Message, and Get the Agent Response
193+
2. Next, we create a `PersistentAgentThread` and add a user message to it.
191194

192-
Next create a thread with `CreateThreadAsync()` and a thread with `CreateMessageAsync()`. After the thread is created, you can add messages to it with `CreateMessageAsync()` that will cause the code interpreter tool to trigger. Create a run, and then continue polling it until it reaches a terminal status. Assuming the run was successful, parse the agent's response by listing the messages.
195+
Synchronous sample:
193196

194-
```csharp
195-
//Create a thread
196-
Response<AgentThread> threadResponse = await client.CreateThreadAsync();
197-
AgentThread thread = threadResponse.Value;
197+
```C# Snippet:AgentsStreaming_Step2_Sync_CreateThreadAndMessage
198+
PersistentAgentThread thread = client.Threads.CreateThread();
198199

199-
//With a thread created, messages can be created on it:
200-
Response<ThreadMessage> messageResponse = await client.CreateMessageAsync(
200+
client.Messages.CreateMessage(
201201
thread.Id,
202202
MessageRole.User,
203-
"I need to solve the equation `3x + 11 = 14`. Can you help me?");
204-
ThreadMessage message = messageResponse.Value;
203+
"Hi, Agent! Draw a graph for a line with a slope of 4 and y-intercept of 9.");
204+
```
205+
206+
Asynchronous sample:
207+
208+
```C# Snippet:AgentsStreaming_Step2_Async_CreateThreadAndMessage
209+
PersistentAgentThread thread = await client.Threads.CreateThreadAsync();
210+
211+
await client.Messages.CreateMessageAsync(
212+
thread.Id,
213+
MessageRole.User,
214+
"Hi, Agent! Draw a graph for a line with a slope of 4 and y-intercept of 9.");
215+
```
216+
217+
3. Then, we create a `ThreadRun` for the thread and agent, providing any additional instructions. We poll the run's status until it is no longer queued, in progress, or requires action.
218+
219+
Synchronous sample:
220+
221+
```C# Snippet:AgentsStreaming_Step3_Sync_CreateAndPollRun
222+
ThreadRun run = client.Runs.CreateRun(
223+
thread.Id,
224+
agent.Id,
225+
additionalInstructions: "Please address the user as Jane Doe. The user has a premium account.");
205226

206-
//A run can then be started that evaluates the thread against an agent:
207-
Response<ThreadRun> runResponse = await client.CreateRunAsync(
227+
do
228+
{
229+
Thread.Sleep(TimeSpan.FromMilliseconds(500));
230+
run = client.Runs.GetRun(thread.Id, run.Id);
231+
}
232+
while (run.Status == RunStatus.Queued
233+
|| run.Status == RunStatus.InProgress
234+
|| run.Status == RunStatus.RequiresAction);
235+
```
236+
237+
Asynchronous sample:
238+
239+
```C# Snippet:AgentsStreaming_Step3_Async_CreateAndPollRun
240+
ThreadRun run = await client.Runs.CreateRunAsync(
208241
thread.Id,
209242
agent.Id,
210243
additionalInstructions: "Please address the user as Jane Doe. The user has a premium account.");
211-
ThreadRun run = runResponse.Value;
212244

213-
//Once the run has started, it should then be polled until it reaches a terminal status:
214245
do
215246
{
216247
await Task.Delay(TimeSpan.FromMilliseconds(500));
217-
runResponse = await client.GetRunAsync(thread.Id, runResponse.Value.Id);
248+
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
218249
}
219-
while (runResponse.Value.Status == RunStatus.Queued
220-
|| runResponse.Value.Status == RunStatus.InProgress);
250+
while (run.Status == RunStatus.Queued
251+
|| run.Status == RunStatus.InProgress
252+
|| run.Status == RunStatus.RequiresAction);
253+
```
254+
255+
4. Once the run is finished, we retrieve all messages from the thread. We then iterate through the messages to display text content and handle any image files by saving them locally and opening them.
221256

222-
//Assuming the run successfully completed, listing messages from the thread that was run will now reflect new information added by the agent:
257+
Synchronous sample:
223258

224-
Response<PageableList<ThreadMessage>> afterRunMessagesResponse
225-
= await client.GetMessagesAsync(thread.Id);
226-
IReadOnlyList<ThreadMessage> messages = afterRunMessagesResponse.Value.Data;
259+
```C# Snippet:AgentsStreaming_Step4_Sync_ProcessMessages
260+
Pageable<ThreadMessage> messages = client.Messages.GetMessages(
261+
threadId: thread.Id,
262+
order: ListSortOrder.Ascending);
227263

228-
// Note: messages iterate from newest to oldest, with the messages[0] being the most recent
229264
foreach (ThreadMessage threadMessage in messages)
230265
{
231-
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
232-
foreach (MessageContent contentItem in threadMessage.ContentItems)
266+
foreach (MessageContent content in threadMessage.ContentItems)
233267
{
234-
if (contentItem is MessageTextContent textItem)
235-
{
236-
Console.Write(textItem.Text);
237-
}
238-
else if (contentItem is MessageImageFileContent imageFileItem)
268+
switch (content)
239269
{
240-
Console.Write($"<image from ID: {imageFileItem.FileId}");
270+
case MessageTextContent textItem:
271+
Console.WriteLine($"[{threadMessage.Role}]: {textItem.Text}");
272+
break;
273+
case MessageImageFileContent imageFileContent:
274+
Console.WriteLine($"[{threadMessage.Role}]: Image content file ID = {imageFileContent.FileId}");
275+
BinaryData imageContent = client.Files.GetFileContent(imageFileContent.FileId);
276+
string tempFilePath = Path.Combine(AppContext.BaseDirectory, $"{Guid.NewGuid()}.png");
277+
File.WriteAllBytes(tempFilePath, imageContent.ToArray());
278+
client.Files.DeleteFile(imageFileContent.FileId);
279+
280+
ProcessStartInfo psi = new()
281+
{
282+
FileName = tempFilePath,
283+
UseShellExecute = true
284+
};
285+
Process.Start(psi);
286+
break;
241287
}
242-
Console.WriteLine();
243288
}
244289
}
245290
```
246291

247-
## Download Files Generated by Code Interpreter
292+
Asynchronous sample:
248293

249-
Files generated by code interpreter can be found in the Agent message responses. You can download image files generated by code interpreter by iterating through the response's messages and checking for an `ImageFileId`. If that field exists, use the following code:
294+
```C# Snippet:AgentsStreaming_Step4_Async_ProcessMessages
295+
AsyncPageable<ThreadMessage> messages = client.Messages.GetMessagesAsync(
296+
threadId: thread.Id,
297+
order: ListSortOrder.Ascending);
250298

251-
```csharp
252-
foreach (MessageContent contentItem in message.Content)
299+
await foreach (ThreadMessage threadMessage in messages)
253300
{
254-
if (!string.IsNullOrEmpty(contentItem.ImageFileId))
301+
foreach (MessageContent content in threadMessage.ContentItems)
255302
{
256-
OpenAIFileInfo imageInfo = await fileClient.GetFileAsync(contentItem.ImageFileId);
257-
BinaryData imageBytes = await fileClient.DownloadFileAsync(contentItem.ImageFileId);
258-
using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png");
259-
imageBytes.ToStream().CopyTo(stream);
260-
261-
Console.WriteLine($"<image: {imageInfo.Filename}.png>");
303+
switch (content)
304+
{
305+
case MessageTextContent textItem:
306+
Console.WriteLine($"[{threadMessage.Role}]: {textItem.Text}");
307+
break;
308+
case MessageImageFileContent imageFileContent:
309+
Console.WriteLine($"[{threadMessage.Role}]: Image content file ID = {imageFileContent.FileId}");
310+
BinaryData imageContent = await client.Files.GetFileContentAsync(imageFileContent.FileId);
311+
string tempFilePath = Path.Combine(AppContext.BaseDirectory, $"{Guid.NewGuid()}.png");
312+
File.WriteAllBytes(tempFilePath, imageContent.ToArray());
313+
await client.Files.DeleteFileAsync(imageFileContent.FileId);
314+
315+
ProcessStartInfo psi = new()
316+
{
317+
FileName = tempFilePath,
318+
UseShellExecute = true
319+
};
320+
Process.Start(psi);
321+
break;
322+
}
262323
}
263324
}
264325
```
265326

327+
5. Finally, we delete the thread and the agent to clean up the resources created in this sample.
328+
329+
Synchronous sample:
330+
331+
```C# Snippet:AgentsStreaming_Step5_Sync_Cleanup
332+
client.Threads.DeleteThread(threadId: thread.Id);
333+
client.Administration.DeleteAgent(agentId: agent.Id);
334+
```
335+
336+
Asynchronous sample:
337+
338+
```C# Snippet:AgentsStreaming_Step5_Async_Cleanup
339+
await client.Threads.DeleteThreadAsync(threadId: thread.Id);
340+
await client.Administration.DeleteAgentAsync(agentId: agent.Id);
341+
```
342+
343+
266344
:::zone-end
267345

268346
:::zone pivot="javascript"
@@ -470,4 +548,4 @@ curl $AZURE_AI_AGENTS_ENDPOINT/threads/thread_abc123/messages?api-version=2024-1
470548
-H "Authorization: Bearer $AZURE_AI_AGENTS_TOKEN"
471549
```
472550
473-
:::zone-end
551+
:::zone-end

0 commit comments

Comments
 (0)