Skip to content

Commit 887b63b

Browse files
authored
Add activity run step to MCP (Azure#51580)
* Add activity step * Update samples for MCP Activity step * Remove test code and regenerate * Regerste the code * Regenerate code * Fix comment * Update tsp-location
1 parent 84aacaf commit 887b63b

29 files changed

+1833
-69
lines changed

sdk/ai/Azure.AI.Agents.Persistent/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features Added
66

77
- Implemented streaming scenario for MCP tool.
8+
- Added `RunStepDetailsActivity`, describing MCP function parameters.
89

910
### Breaking Changes
1011

sdk/ai/Azure.AI.Agents.Persistent/api/Azure.AI.Agents.Persistent.net8.0.cs

Lines changed: 103 additions & 0 deletions
Large diffs are not rendered by default.

sdk/ai/Azure.AI.Agents.Persistent/api/Azure.AI.Agents.Persistent.netstandard2.0.cs

Lines changed: 103 additions & 0 deletions
Large diffs are not rendered by default.

sdk/ai/Azure.AI.Agents.Persistent/samples/Sample26_PersistentAgents_MCP.md

Lines changed: 78 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -147,59 +147,103 @@ Assert.AreEqual(
147147
run.LastError?.Message);
148148
```
149149

150-
5. Print the agent messages to console in chronological order.
150+
5. We will create the helper method `PrintActivitySteps` to list the functions being called with the descriptions and arguments.
151151

152-
Synchronous sample:
153-
```C# Snippet:AgentsMCP_Print
154-
Pageable<PersistentThreadMessage> messages = agentClient.Messages.GetMessages(
155-
threadId: thread.Id,
156-
order: ListSortOrder.Ascending
157-
);
158-
159-
foreach (PersistentThreadMessage threadMessage in messages)
152+
```C# Snippet:AgentsMcpPrintActivityStep
153+
private static void PrintActivitySteps(IReadOnlyList<RunStep> runSteps)
160154
{
161-
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
162-
foreach (MessageContent contentItem in threadMessage.ContentItems)
155+
foreach (RunStep step in runSteps)
163156
{
164-
if (contentItem is MessageTextContent textItem)
157+
if (step.StepDetails is RunStepActivityDetails activityDetails)
165158
{
166-
Console.Write(textItem.Text);
167-
}
168-
else if (contentItem is MessageImageFileContent imageFileItem)
169-
{
170-
Console.Write($"<image from ID: {imageFileItem.FileId}>");
159+
foreach (RunStepDetailsActivity activity in activityDetails.Activities)
160+
{
161+
foreach (KeyValuePair<string, ActivityFunctionDefinition> activityFunction in activity.Tools)
162+
{
163+
Console.WriteLine($"The function {activityFunction.Key} with description \"{activityFunction.Value.Description}\" will be called.");
164+
if (activityFunction.Value.Parameters.Properties.Count > 0)
165+
{
166+
Console.WriteLine("Function parameters:");
167+
foreach (KeyValuePair<string, FunctionArgument> arg in activityFunction.Value.Parameters.Properties)
168+
{
169+
Console.WriteLine($"\t{arg.Key}");
170+
Console.WriteLine($"\t\tType: {arg.Value.Type}");
171+
if (!string.IsNullOrEmpty(arg.Value.Description))
172+
Console.WriteLine($"\t\tDescription: {arg.Value.Description}");
173+
}
174+
}
175+
else
176+
{
177+
Console.WriteLine("This function has no parameters");
178+
}
179+
}
180+
}
171181
}
172-
Console.WriteLine();
173182
}
174183
}
175184
```
176185

186+
6. Print activities description.
187+
188+
Synchronous sample:
189+
```C# Snippet:AgentsMCP_PrintRunSteps
190+
IReadOnlyList<RunStep> runSteps = [..agentClient.Runs.GetRunSteps(run: run)];
191+
PrintActivitySteps(runSteps);
192+
```
193+
177194
Asynchronous sample:
178-
```C# Snippet:AgentsMCPAsync_Print
179-
AsyncPageable<PersistentThreadMessage> messages = agentClient.Messages.GetMessagesAsync(
180-
threadId: thread.Id,
181-
order: ListSortOrder.Ascending
182-
);
195+
```C# Snippet:AgentsMCPAsync_PrintRunSteps
196+
IReadOnlyList<RunStep> runSteps = [.. agentClient.Runs.GetRunSteps(run: run)];
197+
PrintActivitySteps(runSteps);
198+
```
183199

184-
await foreach (PersistentThreadMessage threadMessage in messages)
200+
7. To print messages, we will use the helper method `PrintMessages`.
201+
202+
```C# Snippet:AgentsMcpPrintMessages
203+
private static void PrintMessages(IReadOnlyList<PersistentThreadMessage> messages)
185204
{
186-
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
187-
foreach (MessageContent contentItem in threadMessage.ContentItems)
205+
foreach (PersistentThreadMessage threadMessage in messages)
188206
{
189-
if (contentItem is MessageTextContent textItem)
190-
{
191-
Console.Write(textItem.Text);
192-
}
193-
else if (contentItem is MessageImageFileContent imageFileItem)
207+
Console.Write($"{threadMessage.CreatedAt:yyyy-MM-dd HH:mm:ss} - {threadMessage.Role,10}: ");
208+
foreach (MessageContent contentItem in threadMessage.ContentItems)
194209
{
195-
Console.Write($"<image from ID: {imageFileItem.FileId}>");
210+
if (contentItem is MessageTextContent textItem)
211+
{
212+
Console.Write(textItem.Text);
213+
}
214+
else if (contentItem is MessageImageFileContent imageFileItem)
215+
{
216+
Console.Write($"<image from ID: {imageFileItem.FileId}>");
217+
}
218+
Console.WriteLine();
196219
}
197-
Console.WriteLine();
198220
}
199221
}
200222
```
201223

202-
6. Clean up resources by deleting thread and agent.
224+
8. Print the agent messages to console in chronological order.
225+
226+
Synchronous sample:
227+
```C# Snippet:AgentsMCP_Print
228+
IReadOnlyList<PersistentThreadMessage> messages = [..agentClient.Messages.GetMessages(
229+
threadId: thread.Id,
230+
order: ListSortOrder.Ascending
231+
)];
232+
233+
PrintMessages(messages);
234+
```
235+
236+
Asynchronous sample:
237+
```C# Snippet:AgentsMCPAsync_Print
238+
IReadOnlyList<PersistentThreadMessage> messages = await agentClient.Messages.GetMessagesAsync(
239+
threadId: thread.Id,
240+
order: ListSortOrder.Ascending
241+
).ToListAsync();
242+
243+
PrintMessages(messages);
244+
```
245+
246+
9. Clean up resources by deleting thread and agent.
203247

204248
Synchronous sample:
205249
```C# Snippet:AgentsMCPCleanup

sdk/ai/Azure.AI.Agents.Persistent/samples/Sample27_PersistentAgents_MCP_Streaming.md

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,40 @@ CreateRunStreamingOptions options = new()
8484
};
8585
```
8686

87-
5 Start the streaming update loop. When asked, we will approve using tool.
87+
5. To simplify the code we will use `PrintActivityStep` to display functions called and along with their parameters.
88+
89+
```C# Snippet:AgentsMCPStreaming_PrintActivityStep
90+
private static void PrintActivityStep(RunStep step)
91+
{
92+
if (step.StepDetails is RunStepActivityDetails activityDetails)
93+
{
94+
foreach (RunStepDetailsActivity activity in activityDetails.Activities)
95+
{
96+
foreach (KeyValuePair<string, ActivityFunctionDefinition> activityFunction in activity.Tools)
97+
{
98+
Console.WriteLine($"The function {activityFunction.Key} with description \"{activityFunction.Value.Description}\" will be called.");
99+
if (activityFunction.Value.Parameters.Properties.Count > 0)
100+
{
101+
Console.WriteLine("Function parameters:");
102+
foreach (KeyValuePair<string, FunctionArgument> arg in activityFunction.Value.Parameters.Properties)
103+
{
104+
Console.WriteLine($"\t{arg.Key}");
105+
Console.WriteLine($"\t\tType: {arg.Value.Type}");
106+
if (!string.IsNullOrEmpty(arg.Value.Description))
107+
Console.WriteLine($"\t\tDescription: {arg.Value.Description}");
108+
}
109+
}
110+
else
111+
{
112+
Console.WriteLine("This function has no parameters");
113+
}
114+
}
115+
}
116+
}
117+
}
118+
```
119+
120+
6. Start the streaming update loop. When asked, we will approve using tool.
88121

89122
Synchronous sample:
90123
```C# Snippet:AgentsMCPStreaming_UpdateCycle
@@ -113,6 +146,10 @@ do
113146
{
114147
Console.Write(contentUpdate.Text);
115148
}
149+
else if (streamingUpdate is RunStepUpdate runStepUpdate)
150+
{
151+
PrintActivityStep(runStepUpdate.Value);
152+
}
116153
else if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunCompleted)
117154
{
118155
Console.WriteLine();
@@ -158,6 +195,10 @@ do
158195
{
159196
Console.Write(contentUpdate.Text);
160197
}
198+
else if (streamingUpdate is RunStepUpdate runStepUpdate)
199+
{
200+
PrintActivityStep(runStepUpdate.Value);
201+
}
161202
else if (streamingUpdate.UpdateKind == StreamingUpdateReason.RunCompleted)
162203
{
163204
Console.WriteLine();

sdk/ai/Azure.AI.Agents.Persistent/src/Generated/ActivityFunctionDefinition.Serialization.cs

Lines changed: 153 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)