.NET: Foundry Agents V2 - Add CodeInterpreter Sample (#2180)

* Adding Code Interpreter sample and AgentName naming validation

* Add agent name check UT

* Improve sample code

* Apply suggestion

* Apply suggestion
This commit is contained in:
Roger Barreto
2025-11-13 15:23:51 +00:00
committed by GitHub
Unverified
parent eb2d573f03
commit 59d08ad29e
6 changed files with 457 additions and 15 deletions
+1
View File
@@ -114,6 +114,7 @@
<Project Path="samples/GettingStarted/FoundryAgents/FoundryAgents_Step11_AsFunctionTool/FoundryAgents_Step11_AsFunctionTool.csproj" />
<Project Path="samples/GettingStarted/FoundryAgents/FoundryAgents_Step12_Middleware/FoundryAgents_Step12_Middleware.csproj" />
<Project Path="samples/GettingStarted/FoundryAgents/FoundryAgents_Step13_Plugins/FoundryAgents_Step13_Plugins.csproj" />
<Project Path="samples/GettingStarted/FoundryAgents/FoundryAgents_Step14_CodeInterpreter/FoundryAgents_Step14_CodeInterpreter.csproj" />
</Folder>
<Folder Name="/Samples/GettingStarted/ModelContextProtocol/">
<File Path="samples/GettingStarted/ModelContextProtocol/README.md" />
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);CA1812</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Azure.AI.Agents" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,89 @@
// Copyright (c) Microsoft. All rights reserved.
// This sample shows how to use Code Interpreter Tool with AI Agents.
using System.Text;
using Azure.AI.Agents;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using OpenAI.Assistants;
using OpenAI.Responses;
string endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
const string AgentInstructions = "You are a personal math tutor. When asked a math question, write and run code using the python tool to answer the question.";
const string AgentNameMEAI = "CoderAgent-MEAI";
const string AgentNameNative = "CoderAgent-NATIVE";
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
AgentClient agentClient = new(new Uri(endpoint), new AzureCliCredential());
// Option 1 - Using HostedCodeInterpreterTool + AgentOptions (MEAI + AgentFramework)
// Create the server side agent version
AIAgent agentOption1 = await agentClient.CreateAIAgentAsync(
model: deploymentName,
name: AgentNameMEAI,
instructions: AgentInstructions,
tools: [new HostedCodeInterpreterTool() { Inputs = [] }]);
// Option 2 - Using PromptAgentDefinition SDK native type
// Create the server side agent version
AIAgent agentOption2 = await agentClient.CreateAIAgentAsync(
name: AgentNameNative,
creationOptions: new AgentVersionCreationOptions(
new PromptAgentDefinition(model: deploymentName)
{
Instructions = AgentInstructions,
Tools = {
ResponseTool.CreateCodeInterpreterTool(
new CodeInterpreterToolContainer(
CodeInterpreterToolContainerConfiguration.CreateAutomaticContainerConfiguration(fileIds: [])
)
),
}
})
);
// Either invoke option1 or option2 agent, should have same result
// Option 1
AgentRunResponse response = await agentOption1.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
// Option 2
// AgentRunResponse response = await agentOption2.RunAsync("I need to solve the equation sin(x) + x^2 = 42");
// Get the CodeInterpreterToolCallContent
CodeInterpreterToolCallContent? toolCallContent = response.Messages.SelectMany(m => m.Contents).OfType<CodeInterpreterToolCallContent>().SingleOrDefault();
if (toolCallContent?.Inputs is not null)
{
DataContent? codeInput = toolCallContent.Inputs.OfType<DataContent>().FirstOrDefault();
if (codeInput?.HasTopLevelMediaType("text") ?? false)
{
Console.WriteLine($"Code Input: {Encoding.UTF8.GetString(codeInput.Data.ToArray()) ?? "Not available"}");
}
}
// Get the CodeInterpreterToolResultContent
CodeInterpreterToolResultContent? toolResultContent = response.Messages.SelectMany(m => m.Contents).OfType<CodeInterpreterToolResultContent>().FirstOrDefault();
if (toolResultContent?.Outputs is not null && toolResultContent.Outputs.OfType<TextContent>().FirstOrDefault() is { } resultOutput)
{
Console.WriteLine($"Code Tool Result: {resultOutput.Text}");
}
// Getting any annotations generated by the tool
foreach (AIAnnotation annotation in response.Messages.SelectMany(m => m.Contents).SelectMany(C => C.Annotations ?? []))
{
if (annotation.RawRepresentation is TextAnnotationUpdate citationAnnotation)
{
Console.WriteLine($$"""
File Id: {{citationAnnotation.OutputFileId}}
Text to Replace: {{citationAnnotation.TextToReplace}}
Filename: {{Path.GetFileName(citationAnnotation.TextToReplace)}}
""");
}
}
// Cleanup by agent name removes the agent version created.
await agentClient.DeleteAgentAsync(agentOption1.Name);
await agentClient.DeleteAgentAsync(agentOption2.Name);
@@ -0,0 +1,53 @@
# Using Code Interpreter with AI Agents
This sample demonstrates how to use the code interpreter tool with AI agents. The code interpreter allows agents to write and execute Python code to solve problems, perform calculations, and analyze data.
## What this sample demonstrates
- Creating agents with code interpreter capabilities
- Using HostedCodeInterpreterTool (MEAI abstraction)
- Using native SDK code interpreter tools (ResponseTool.CreateCodeInterpreterTool)
- Extracting code inputs and results from agent responses
- Handling code interpreter annotations
- Managing agent lifecycle (creation and deletion)
## Prerequisites
Before you begin, ensure you have the following prerequisites:
- .NET 8.0 SDK or later
- Azure Foundry service endpoint and deployment configured
- Azure CLI installed and authenticated (for Azure credential authentication)
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
Set the following environment variables:
```powershell
$env:AZURE_FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" # Replace with your Azure Foundry resource endpoint
$env:AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
```
## Run the sample
Navigate to the FoundryAgents sample directory and run:
```powershell
cd dotnet/samples/GettingStarted/FoundryAgents
dotnet run --project .\FoundryAgents_Step14_CodeInterpreter
```
## Expected behavior
The sample will:
1. Create two agents with code interpreter capabilities:
- Option 1: Using HostedCodeInterpreterTool (MEAI abstraction)
- Option 2: Using native SDK code interpreter tools
2. Run the agent with a mathematical problem: "I need to solve the equation sin(x) + x^2 = 42"
3. The agent will use the code interpreter to write and execute Python code to solve the equation
4. Extract and display the code that was executed
5. Display the results from the code execution
6. Display any annotations generated by the code interpreter tool
7. Clean up resources by deleting both agents
@@ -7,6 +7,7 @@ using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;
using Microsoft.Extensions.AI;
@@ -22,7 +23,7 @@ namespace Azure.AI.Agents;
/// <summary>
/// Provides extension methods for <see cref="AgentClient"/>.
/// </summary>
public static class AgentClientExtensions
public static partial class AgentClientExtensions
{
/// <summary>
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AgentClient"/>.
@@ -50,6 +51,7 @@ public static class AgentClientExtensions
{
Throw.IfNull(agentClient);
Throw.IfNull(agentReference);
ThrowIfInvalidAgentName(agentReference.Name);
return CreateChatClientAgent(
agentClient,
@@ -89,7 +91,7 @@ public static class AgentClientExtensions
CancellationToken cancellationToken = default)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
ThrowIfInvalidAgentName(name);
AgentRecord agentRecord = GetAgentRecordByName(agentClient, name, cancellationToken);
@@ -126,7 +128,7 @@ public static class AgentClientExtensions
CancellationToken cancellationToken = default)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
ThrowIfInvalidAgentName(name);
AgentRecord agentRecord = await GetAgentRecordByNameAsync(agentClient, name, cancellationToken).ConfigureAwait(false);
@@ -234,6 +236,8 @@ public static class AgentClientExtensions
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
}
ThrowIfInvalidAgentName(options.Name);
AgentRecord agentRecord = GetAgentRecordByName(agentClient, options.Name, cancellationToken);
var agentVersion = agentRecord.Versions.Latest;
@@ -275,6 +279,8 @@ public static class AgentClientExtensions
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
}
ThrowIfInvalidAgentName(options.Name);
AgentRecord agentRecord = await GetAgentRecordByNameAsync(agentClient, options.Name, cancellationToken).ConfigureAwait(false);
var agentVersion = agentRecord.Versions.Latest;
@@ -319,7 +325,7 @@ public static class AgentClientExtensions
CancellationToken cancellationToken = default)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
ThrowIfInvalidAgentName(name);
Throw.IfNullOrWhitespace(model);
Throw.IfNullOrWhitespace(instructions);
@@ -364,7 +370,7 @@ public static class AgentClientExtensions
CancellationToken cancellationToken = default)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
ThrowIfInvalidAgentName(name);
Throw.IfNullOrWhitespace(model);
Throw.IfNullOrWhitespace(instructions);
@@ -411,6 +417,8 @@ public static class AgentClientExtensions
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
}
ThrowIfInvalidAgentName(options.Name);
PromptAgentDefinition agentDefinition = new(model)
{
Instructions = options.Instructions,
@@ -478,6 +486,8 @@ public static class AgentClientExtensions
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
}
ThrowIfInvalidAgentName(options.Name);
PromptAgentDefinition agentDefinition = new(model)
{
Instructions = options.Instructions,
@@ -537,7 +547,7 @@ public static class AgentClientExtensions
CancellationToken cancellationToken = default)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
ThrowIfInvalidAgentName(name);
Throw.IfNull(creationOptions);
return CreateAIAgent(
@@ -575,8 +585,8 @@ public static class AgentClientExtensions
OpenAIClientOptions? openAIClientOptions = null,
CancellationToken cancellationToken = default)
{
Throw.IfNullOrWhitespace(name);
Throw.IfNull(agentClient);
ThrowIfInvalidAgentName(name);
Throw.IfNull(creationOptions);
return CreateAIAgentAsync(
@@ -642,10 +652,6 @@ public static class AgentClientExtensions
IServiceProvider? services,
CancellationToken cancellationToken)
{
Throw.IfNull(agentClient);
Throw.IfNullOrWhitespace(name);
Throw.IfNull(creationOptions);
var allowDeclarativeMode = tools is not { Count: > 0 };
if (!allowDeclarativeMode)
@@ -675,10 +681,6 @@ public static class AgentClientExtensions
IServiceProvider? services,
CancellationToken cancellationToken)
{
Throw.IfNullOrWhitespace(name);
Throw.IfNull(agentClient);
Throw.IfNull(creationOptions);
var allowDeclarativeMode = tools is not { Count: > 0 };
if (!allowDeclarativeMode)
@@ -1051,6 +1053,23 @@ public static class AgentClientExtensions
}
}
#endregion
#if NET
[GeneratedRegex("^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$")]
private static partial Regex AgentNameValidationRegex();
#else
private static Regex AgentNameValidationRegex() => new("^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$");
#endif
private static string ThrowIfInvalidAgentName(string? name)
{
Throw.IfNullOrWhitespace(name);
if (!AgentNameValidationRegex().IsMatch(name))
{
throw new ArgumentException("Agent name must be 1-63 characters long, start and end with an alphanumeric character, and can only contain alphanumeric characters or hyphens.", nameof(name));
}
return name;
}
}
[JsonSerializable(typeof(JsonElement))]
@@ -1629,6 +1629,217 @@ public sealed class AgentClientExtensionsTests
#endregion
#region AgentName Validation Tests
/// <summary>
/// Verify that GetAIAgent throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void GetAIAgent_ByName_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
mockClient.Object.GetAIAgent(invalidName));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that GetAIAgentAsync throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public async Task GetAIAgentAsync_ByName_WithInvalidAgentName_ThrowsArgumentExceptionAsync(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
mockClient.Object.GetAIAgentAsync(invalidName));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that GetAIAgent with ChatClientAgentOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void GetAIAgent_WithOptions_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
AgentClient client = this.CreateTestAgentClient();
var options = new ChatClientAgentOptions { Name = invalidName };
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
client.GetAIAgent(options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that GetAIAgentAsync with ChatClientAgentOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public async Task GetAIAgentAsync_WithOptions_WithInvalidAgentName_ThrowsArgumentExceptionAsync(string invalidName)
{
// Arrange
AgentClient client = this.CreateTestAgentClient();
var options = new ChatClientAgentOptions { Name = invalidName };
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
client.GetAIAgentAsync(options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgent throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void CreateAIAgent_WithBasicParams_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
mockClient.Object.CreateAIAgent(invalidName, "model", "instructions"));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgentAsync throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public async Task CreateAIAgentAsync_WithBasicParams_WithInvalidAgentName_ThrowsArgumentExceptionAsync(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
mockClient.Object.CreateAIAgentAsync(invalidName, "model", "instructions"));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgent with AgentVersionCreationOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void CreateAIAgent_WithAgentDefinition_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
var definition = new PromptAgentDefinition("test-model");
var options = new AgentVersionCreationOptions(definition);
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
mockClient.Object.CreateAIAgent(invalidName, options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgentAsync with AgentVersionCreationOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public async Task CreateAIAgentAsync_WithAgentDefinition_WithInvalidAgentName_ThrowsArgumentExceptionAsync(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
var definition = new PromptAgentDefinition("test-model");
var options = new AgentVersionCreationOptions(definition);
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
mockClient.Object.CreateAIAgentAsync(invalidName, options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgent with ChatClientAgentOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void CreateAIAgent_WithOptions_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
AgentClient client = this.CreateTestAgentClient();
var options = new ChatClientAgentOptions { Name = invalidName };
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
client.CreateAIAgent("test-model", options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that CreateAIAgentAsync with ChatClientAgentOptions throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public async Task CreateAIAgentAsync_WithOptions_WithInvalidAgentName_ThrowsArgumentExceptionAsync(string invalidName)
{
// Arrange
AgentClient client = this.CreateTestAgentClient();
var options = new ChatClientAgentOptions { Name = invalidName };
// Act & Assert
var exception = await Assert.ThrowsAsync<ArgumentException>(() =>
client.CreateAIAgentAsync("test-model", options));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
/// <summary>
/// Verify that GetAIAgent with AgentReference throws ArgumentException when agent name is invalid.
/// </summary>
[Theory]
[MemberData(nameof(InvalidAgentNameTestData.GetInvalidAgentNames), MemberType = typeof(InvalidAgentNameTestData))]
public void GetAIAgent_WithAgentReference_WithInvalidAgentName_ThrowsArgumentException(string invalidName)
{
// Arrange
var mockClient = new Mock<AgentClient>();
var agentReference = new AgentReference(invalidName) { Version = "1" };
// Act & Assert
var exception = Assert.Throws<ArgumentException>(() =>
mockClient.Object.GetAIAgent(agentReference));
Assert.Equal("name", exception.ParamName);
Assert.Contains("Agent name must be 1-63 characters long", exception.Message);
}
#endregion
#region AzureAIChatClient Behavior Tests
/// <summary>
@@ -2543,3 +2754,50 @@ public sealed class AgentClientExtensionsTests
return chatOptionsProperty?.GetValue(agent) as ChatOptions;
}
}
/// <summary>
/// Provides test data for invalid agent name validation tests.
/// </summary>
internal static class InvalidAgentNameTestData
{
/// <summary>
/// Gets a collection of invalid agent names for theory-based testing.
/// </summary>
/// <returns>Collection of invalid agent name test cases.</returns>
public static IEnumerable<object[]> GetInvalidAgentNames()
{
yield return new object[] { "-agent" };
yield return new object[] { "agent-" };
yield return new object[] { "agent_name" };
yield return new object[] { "agent name" };
yield return new object[] { "agent@name" };
yield return new object[] { "agent#name" };
yield return new object[] { "agent$name" };
yield return new object[] { "agent%name" };
yield return new object[] { "agent&name" };
yield return new object[] { "agent*name" };
yield return new object[] { "agent.name" };
yield return new object[] { "agent/name" };
yield return new object[] { "agent\\name" };
yield return new object[] { "agent:name" };
yield return new object[] { "agent;name" };
yield return new object[] { "agent,name" };
yield return new object[] { "agent<name" };
yield return new object[] { "agent>name" };
yield return new object[] { "agent?name" };
yield return new object[] { "agent!name" };
yield return new object[] { "agent~name" };
yield return new object[] { "agent`name" };
yield return new object[] { "agent^name" };
yield return new object[] { "agent|name" };
yield return new object[] { "agent[name" };
yield return new object[] { "agent]name" };
yield return new object[] { "agent{name" };
yield return new object[] { "agent}name" };
yield return new object[] { "agent(name" };
yield return new object[] { "agent)name" };
yield return new object[] { "agent+name" };
yield return new object[] { "agent=name" };
yield return new object[] { "a" + new string('b', 63) };
}
}