Merge branch 'main' into feature-foundry-agents

This commit is contained in:
Chris
2025-11-11 12:23:56 -08:00
committed by GitHub
Unverified
3 changed files with 50 additions and 5 deletions
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using Microsoft.Extensions.AI;
using Microsoft.Shared.Diagnostics;
namespace Microsoft.Agents.AI;
@@ -32,6 +33,7 @@ public class AgentRunOptions
_ = Throw.IfNull(options);
this.ContinuationToken = options.ContinuationToken;
this.AllowBackgroundResponses = options.AllowBackgroundResponses;
this.AdditionalProperties = options.AdditionalProperties?.Clone();
}
/// <summary>
@@ -74,4 +76,18 @@ public class AgentRunOptions
/// </para>
/// </remarks>
public bool? AllowBackgroundResponses { get; set; }
/// <summary>
/// Gets or sets additional properties associated with these options.
/// </summary>
/// <value>
/// An <see cref="AdditionalPropertiesDictionary"/> containing custom properties,
/// or <see langword="null"/> if no additional properties are present.
/// </value>
/// <remarks>
/// Additional properties provide a way to include custom metadata or provider-specific
/// information that doesn't fit into the standard options schema. This is useful for
/// preserving implementation-specific details or extending the options with custom data.
/// </remarks>
public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }
}
@@ -18,7 +18,12 @@ public class AgentRunOptionsTests
var options = new AgentRunOptions
{
ContinuationToken = new object(),
AllowBackgroundResponses = true
AllowBackgroundResponses = true,
AdditionalProperties = new AdditionalPropertiesDictionary
{
["key1"] = "value1",
["key2"] = 42
}
};
// Act
@@ -28,6 +33,10 @@ public class AgentRunOptionsTests
Assert.NotNull(clone);
Assert.Same(options.ContinuationToken, clone.ContinuationToken);
Assert.Equal(options.AllowBackgroundResponses, clone.AllowBackgroundResponses);
Assert.NotNull(clone.AdditionalProperties);
Assert.NotSame(options.AdditionalProperties, clone.AdditionalProperties);
Assert.Equal("value1", clone.AdditionalProperties["key1"]);
Assert.Equal(42, clone.AdditionalProperties["key2"]);
}
[Fact]
@@ -42,7 +51,12 @@ public class AgentRunOptionsTests
var options = new AgentRunOptions
{
ContinuationToken = ResponseContinuationToken.FromBytes(new byte[] { 1, 2, 3 }),
AllowBackgroundResponses = true
AllowBackgroundResponses = true,
AdditionalProperties = new AdditionalPropertiesDictionary
{
["key1"] = "value1",
["key2"] = 42
}
};
// Act
@@ -54,5 +68,13 @@ public class AgentRunOptionsTests
Assert.NotNull(deserialized);
Assert.Equivalent(ResponseContinuationToken.FromBytes(new byte[] { 1, 2, 3 }), deserialized!.ContinuationToken);
Assert.Equal(options.AllowBackgroundResponses, deserialized.AllowBackgroundResponses);
Assert.NotNull(deserialized.AdditionalProperties);
Assert.Equal(2, deserialized.AdditionalProperties.Count);
Assert.True(deserialized.AdditionalProperties.TryGetValue("key1", out object? value1));
Assert.IsType<JsonElement>(value1);
Assert.Equal("value1", ((JsonElement)value1!).GetString());
Assert.True(deserialized.AdditionalProperties.TryGetValue("key2", out object? value2));
Assert.IsType<JsonElement>(value2);
Assert.Equal(42, ((JsonElement)value2!).GetInt32());
}
}
+10 -3
View File
@@ -19,7 +19,7 @@ from mcp.client.websocket import websocket_client
from mcp.shared.context import RequestContext
from mcp.shared.exceptions import McpError
from mcp.shared.session import RequestResponder
from pydantic import BaseModel, create_model
from pydantic import BaseModel, Field, create_model
from ._tools import AIFunction, HostedMCPSpecificApproval
from ._types import ChatMessage, Contents, DataContent, Role, TextContent, UriContent
@@ -224,13 +224,20 @@ def _get_input_model_from_mcp_tool(tool: types.Tool) -> type[BaseModel]:
prop_details = json.loads(prop_details) if isinstance(prop_details, str) else prop_details
python_type = resolve_type(prop_details)
description = prop_details.get("description", "")
# Create field definition for create_model
if prop_name in required:
field_definitions[prop_name] = (python_type, ...)
field_definitions[prop_name] = (
(python_type, Field(description=description)) if description else (python_type, ...)
)
else:
default_value = prop_details.get("default", None)
field_definitions[prop_name] = (python_type, default_value)
field_definitions[prop_name] = (
(python_type, Field(default=default_value, description=description))
if description
else (python_type, default_value)
)
return create_model(f"{tool.name}_input", **field_definitions)