Compare commits

..
Author SHA1 Message Date
Evan Mattson 8b0ef62802 Add azure-monitor-opentelemetry to dev deps
Fixes Samples & Markdown CI failure. The PR's new transitive dep on
azure-monitor-opentelemetry-exporter (via azure-ai-agentserver-core) makes
pyright resolve the azure.monitor.opentelemetry namespace, flipping the
check_md_code_blocks diagnostic for `configure_azure_monitor` from
reportMissingImports (filtered) to reportAttributeAccessIssue (not filtered).
Installing the umbrella azure-monitor-opentelemetry package in dev makes
pyright resolve the symbol correctly, matching the install guidance the
observability README already gives users.
2026-04-21 13:50:12 +09:00
Tao Chen 49677ba789 Fix pre commit 6 2026-04-20 20:36:33 -07:00
Tao Chen 7f751e7a0f Fix pre commit 5 2026-04-20 20:30:25 -07:00
Tao Chen 01d8a8af53 Fix pre commit 4 2026-04-20 20:27:26 -07:00
Tao Chen 9d2a55ecfb Fix pre commit 3 2026-04-20 18:47:15 -07:00
Tao Chen cbe3e8fd95 Fix pre commit 2 2026-04-20 18:42:11 -07:00
Tao Chen 93b03140c7 Fix pre commit 2026-04-20 18:39:56 -07:00
Tao Chen 7aa40b16de Fix README 2026-04-20 18:37:24 -07:00
Tao ChenandGitHub fc9194dcb6 Merge branch 'main' into feature/python-foundry-hosted-agent-vnext 2026-04-20 18:35:09 -07:00
Tao Chen fd36871d60 User agent scoped 2026-04-20 18:34:30 -07:00
Tao Chen e24d72be75 Comments and mypy 2026-04-20 18:11:32 -07:00
Tao Chen 8b77baf4a2 Fix README 2026-04-20 17:54:44 -07:00
Tao ChenandGitHub cd48c1424c Python: Add more types (#5378)
* Add more type supports

* Upgrade packages

* Remove TODOs in README
2026-04-20 17:46:06 -07:00
Tao ChenandGitHub 8bc7c3a7a8 Improve samples (#5372) 2026-04-20 16:34:53 -07:00
Tao ChenandGitHub 0fcd71dbeb Python: Add special handling for workflows (#5298)
* Add special handling for workflows

* Address comments
2026-04-16 17:55:45 -07:00
Tao Chen 55e0705923 Merge branch 'main' into feature/python-foundry-hosted-agent-vnext 2026-04-16 13:55:04 -07:00
Tao Chen 892d88df28 Merge branch 'main' into feature/python-foundry-hosted-agent-vnext 2026-04-15 20:59:51 -07:00
Tao ChenandGitHub 3225a59fd3 Python: Upgrade agentserver packages (#5284)
* Upgrade agentserver packages

* Fix new types
2026-04-15 14:16:37 -07:00
Tao ChenandGitHub 9e3983e547 Move samples (#5281) 2026-04-15 11:33:15 -07:00
Tao ChenandGitHub 383a2afca2 Python: Refine samples and upgrade packages (#5261)
* Refine samples and upgrade pacakges

* Upgrade to a new package that fixes a bug

* Update model env var
2026-04-15 10:46:19 -07:00
Tao Chen 0402b1aac4 Merge branch 'main' into feature/python-foundry-hosted-agent-vnext 2026-04-14 10:32:14 -07:00
Tao Chen 448f46aff2 Merge branch 'main' into feature/python-foundry-hosted-agent-vnext 2026-04-13 16:47:46 -07:00
Tao ChenandGitHub 9ce2aafff7 Add tests and more content types (#5235)
* Add tests

* fix tests and sample

* Fix formatting

* Remove function approval contents
2026-04-13 16:12:02 -07:00
Tao ChenandGitHub a98a585afb Update dependency (#5215) 2026-04-10 16:10:35 -07:00
Tao ChenandGitHub 615ef9049f Python: Wrapper + Samples 1st (#5177)
* Experiment

* Update dependency and add non streaming

* Add more samples

* Rename samples

* Add invocations

* Comments 1

* Comments 2

* Comments 3

* Improve README

* Add local shell sample

* WIP: Add eval and memory samples

* Update user agent prefix

* Update user agent prefix doc
2026-04-10 10:18:32 -07:00
42 changed files with 213 additions and 697 deletions
@@ -426,7 +426,7 @@ internal sealed class HandoffAgentExecutor :
{
AgentId = this._agent.Id,
AuthorName = this._agent.Name ?? this._agent.Id,
Contents = [CreateHandoffResult(handoffRequest.CallId)],
Contents = [new FunctionResultContent(handoffRequest.CallId, "Transferred.")],
CreatedAt = DateTimeOffset.UtcNow,
MessageId = Guid.NewGuid().ToString("N"),
Role = ChatRole.Tool,
@@ -459,6 +459,4 @@ internal sealed class HandoffAgentExecutor :
? this._handoffFunctionToAgentId.TryGetValue(requestedHandoff, out string? targetId) ? targetId : null
: null;
}
internal static FunctionResultContent CreateHandoffResult(string requestCallId) => new(requestCallId, "Transferred.");
}
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Workflows.Specialized;
@@ -30,78 +31,113 @@ internal sealed class HandoffMessagesFilter
return messages;
}
HashSet<string> filteredCallsWithoutResponses = new();
List<ChatMessage> retainedMessages = [];
bool filterAllToolCalls = this._filteringBehavior == HandoffToolCallFilteringBehavior.All;
// The logic of filtering is fairly straightforward: We are only interested in FunctionCallContent and FunctionResponseContent.
// We are going to assume that Handoff operates as follows:
// * Each agent is only taking one turn at a time
// * Each agent is taking a turn alone
//
// In the case of certain providers, like Gemini (see microsoft/agent-framework #5244), we will see the function call name as the
// call id as well, so we may see multiple calls with the same call id, and assume that the call is terminated before another
// "CallId-less" FCC is issued. We also need to rely on the idea that FRC follows their corresponding FCC in the message stream.
// (This changes the previous behaviour where FRC could arrive earlier, and relies on strict ordering).
//
// The benefit of expecting all the AIContent to be strictly ordered is that we never need to reach back into a post-filtered
// content to retroactively remove it, or to try to inject it back into the middle of a Message that has already been processed.
Dictionary<string, FilterCandidateState> filteringCandidates = new();
List<ChatMessage> filteredMessages = [];
HashSet<int> messagesToRemove = [];
bool filterHandoffOnly = this._filteringBehavior == HandoffToolCallFilteringBehavior.HandoffOnly;
foreach (ChatMessage unfilteredMessage in messages)
{
if (unfilteredMessage.Contents is null || unfilteredMessage.Contents.Count == 0)
{
retainedMessages.Add(unfilteredMessage);
continue;
}
ChatMessage filteredMessage = unfilteredMessage.Clone();
// We may need to filter out a subset of the message's content, but we won't know until we iterate through it. Create a new list
// of AIContent which we will stuff into a clone of the message if we need to filter out any content.
List<AIContent> retainedContents = new(capacity: unfilteredMessage.Contents.Count);
// .Clone() is shallow, so we cannot modify the contents of the cloned message in place.
List<AIContent> contents = [];
contents.Capacity = unfilteredMessage.Contents?.Count ?? 0;
filteredMessage.Contents = contents;
foreach (AIContent content in unfilteredMessage.Contents)
// Because this runs after the role changes from assistant to user for the target agent, we cannot rely on tool calls
// originating only from messages with the Assistant role. Instead, we need to inspect the contents of all non-Tool (result)
// FunctionCallContent.
if (unfilteredMessage.Role != ChatRole.Tool)
{
if (content is FunctionCallContent fcc
&& (filterAllToolCalls || IsHandoffFunctionName(fcc.Name)))
for (int i = 0; i < unfilteredMessage.Contents!.Count; i++)
{
// If we already have an unmatched candidate with the same CallId, that means we have two FCCs in a row without an FRC,
// which violates our assumption of strict ordering.
if (!filteredCallsWithoutResponses.Add(fcc.CallId))
AIContent content = unfilteredMessage.Contents[i];
if (content is not FunctionCallContent fcc || (filterHandoffOnly && !IsHandoffFunctionName(fcc.Name)))
{
throw new InvalidOperationException($"Duplicate FunctionCallContent with CallId '{fcc.CallId}' without corresponding FunctionResultContent.");
}
filteredMessage.Contents.Add(content);
// If we are filtering all tool calls, or this is a handoff call (and we are not filtering None, already checked), then
// filter this FCC
// Track non-handoff function calls so their tool results are preserved in HandoffOnly mode
if (filterHandoffOnly && content is FunctionCallContent nonHandoffFcc)
{
filteringCandidates[nonHandoffFcc.CallId] = new FilterCandidateState(nonHandoffFcc.CallId)
{
IsHandoffFunction = false,
};
}
}
else if (filterHandoffOnly)
{
if (!filteringCandidates.TryGetValue(fcc.CallId, out FilterCandidateState? candidateState))
{
filteringCandidates[fcc.CallId] = new FilterCandidateState(fcc.CallId)
{
IsHandoffFunction = true,
};
}
else
{
candidateState.IsHandoffFunction = true;
(int messageIndex, int contentIndex) = candidateState.FunctionCallResultLocation!.Value;
ChatMessage messageToFilter = filteredMessages[messageIndex];
messageToFilter.Contents.RemoveAt(contentIndex);
if (messageToFilter.Contents.Count == 0)
{
messagesToRemove.Add(messageIndex);
}
}
}
else
{
// All mode: strip all FunctionCallContent
}
}
}
else
{
if (!filterHandoffOnly)
{
continue;
}
else if (content is FunctionResultContent frc)
for (int i = 0; i < unfilteredMessage.Contents!.Count; i++)
{
// We rely on the corresponding FCC to have already been processed, so check if it is in the candidate dictionary.
// If it is, we can filter out the FRC, but we need to remove the candidate from the dictionary, since a future FCC can
// come in with the same CallId, and should be considered a new call that may need to be filtered.
if (filteredCallsWithoutResponses.Remove(frc.CallId))
AIContent content = unfilteredMessage.Contents[i];
if (content is not FunctionResultContent frc
|| (filteringCandidates.TryGetValue(frc.CallId, out FilterCandidateState? candidateState)
&& candidateState.IsHandoffFunction is false))
{
continue;
// Either this is not a function result content, so we should let it through, or it is a FRC that
// we know is not related to a handoff call. In either case, we should include it.
filteredMessage.Contents.Add(content);
}
else if (candidateState is null)
{
// We haven't seen the corresponding function call yet, so add it as a candidate to be filtered later
filteringCandidates[frc.CallId] = new FilterCandidateState(frc.CallId)
{
FunctionCallResultLocation = (filteredMessages.Count, filteredMessage.Contents.Count),
};
}
// else we have seen the corresponding function call and it is a handoff, so we should filter it out.
}
// FCC/FRC, but not filtered, or neither FCC nor FRC: this should not be filtered out
retainedContents.Add(content);
}
if (retainedContents.Count == 0)
if (filteredMessage.Contents.Count > 0)
{
// message was fully filtered, skip it
continue;
filteredMessages.Add(filteredMessage);
}
ChatMessage filteredMessage = unfilteredMessage.Clone();
filteredMessage.Contents = retainedContents;
retainedMessages.Add(filteredMessage);
}
return retainedMessages;
return filteredMessages.Where((_, index) => !messagesToRemove.Contains(index));
}
private class FilterCandidateState(string callId)
{
public (int MessageIndex, int ContentIndex)? FunctionCallResultLocation { get; set; }
public string CallId => callId;
public bool? IsHandoffFunction { get; set; }
}
}
@@ -1,115 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using FluentAssertions;
using Microsoft.Agents.AI.Workflows.Specialized;
using Microsoft.Extensions.AI;
namespace Microsoft.Agents.AI.Workflows.UnitTests;
public class HandoffMessageFilterTests
{
private List<ChatMessage> CreateTestMessages(bool firstAgentUsesCallId, bool secondAgentUsesCallId, HandoffToolCallFilteringBehavior filter = HandoffToolCallFilteringBehavior.None)
{
FunctionCallContent handoffRequest1 = CreateHandoffCall(1, firstAgentUsesCallId);
FunctionResultContent handoffResponse1 = CreateHandoffResponse(handoffRequest1);
FunctionCallContent toolCall = CreateToolCall(secondAgentUsesCallId);
FunctionResultContent toolResponse = CreateToolResponse(toolCall);
// Approvals come from the function call middleware over ChatClient, so we can expect there to be a RequestId (not that we
// care, because we do not filter approval content)
ToolApprovalRequestContent toolApproval = new(Guid.NewGuid().ToString("N"), toolCall);
ToolApprovalResponseContent toolApprovalResponse = new(toolApproval.RequestId, true, toolCall);
FunctionCallContent handoffRequest2 = CreateHandoffCall(1, secondAgentUsesCallId);
FunctionResultContent handoffResponse2 = CreateHandoffResponse(handoffRequest2);
List<ChatMessage> result = [new(ChatRole.User, "Hello")];
// Agent 1 turn
result.Add(new(ChatRole.Assistant, "Hello! What do you want help with today?"));
result.Add(new(ChatRole.User, "Please explain temperature"));
// Unless we are filtering none, we expect the handoff call to be filtered out, so we add it conditionally
if (filter == HandoffToolCallFilteringBehavior.None)
{
result.Add(new(ChatRole.Assistant, [handoffRequest1]));
result.Add(new(ChatRole.Tool, [handoffResponse1]));
}
// Agent 2 turn
// Tool approvals are never filtered, so we add them unconditionally
result.Add(new(ChatRole.Assistant, [toolApproval]));
result.Add(new(ChatRole.User, [toolApprovalResponse]));
// Unless we are filtering all, we expect the tool call to be retained, so we add it conditionally
if (filter != HandoffToolCallFilteringBehavior.All)
{
result.Add(new(ChatRole.Assistant, [toolCall]));
result.Add(new(ChatRole.Tool, [toolResponse]));
}
result.Add(new(ChatRole.Assistant, "Temperature is a measure of the average kinetic energy of the particles in a substance."));
if (filter == HandoffToolCallFilteringBehavior.None)
{
result.Add(new(ChatRole.Assistant, [handoffRequest2]));
result.Add(new(ChatRole.Tool, [handoffResponse2]));
}
return result;
}
private static FunctionCallContent CreateHandoffCall(int id, bool useCallId)
{
string callName = $"{HandoffWorkflowBuilder.FunctionPrefix}{id}";
string callId = useCallId ? Guid.NewGuid().ToString("N") : callName;
return new FunctionCallContent(callId, callName);
}
private static FunctionResultContent CreateHandoffResponse(FunctionCallContent call)
=> HandoffAgentExecutor.CreateHandoffResult(call.CallId);
private static FunctionCallContent CreateToolCall(bool useCallId)
{
const string CallName = "ToolFunction";
string callId = useCallId ? Guid.NewGuid().ToString("N") : CallName;
return new FunctionCallContent(callId, CallName);
}
private static FunctionResultContent CreateToolResponse(FunctionCallContent call)
=> new(call.CallId, new object());
[Theory]
[InlineData(true, true, HandoffToolCallFilteringBehavior.None)]
[InlineData(true, false, HandoffToolCallFilteringBehavior.None)]
[InlineData(false, true, HandoffToolCallFilteringBehavior.None)]
[InlineData(false, false, HandoffToolCallFilteringBehavior.None)]
[InlineData(true, true, HandoffToolCallFilteringBehavior.HandoffOnly)]
[InlineData(true, false, HandoffToolCallFilteringBehavior.HandoffOnly)]
[InlineData(false, true, HandoffToolCallFilteringBehavior.HandoffOnly)]
[InlineData(false, false, HandoffToolCallFilteringBehavior.HandoffOnly)]
[InlineData(true, true, HandoffToolCallFilteringBehavior.All)]
[InlineData(true, false, HandoffToolCallFilteringBehavior.All)]
[InlineData(false, true, HandoffToolCallFilteringBehavior.All)]
[InlineData(false, false, HandoffToolCallFilteringBehavior.All)]
public void Test_HandoffMessageFilter_FiltersOnlyExpectedMessages(bool firstAgentUsesCallId, bool secondAgentUsesCallId, HandoffToolCallFilteringBehavior behavior)
{
// Arrange
List<ChatMessage> messages = this.CreateTestMessages(firstAgentUsesCallId, secondAgentUsesCallId);
List<ChatMessage> expected = this.CreateTestMessages(firstAgentUsesCallId, secondAgentUsesCallId, behavior);
HandoffMessagesFilter filter = new(behavior);
// Act
IEnumerable<ChatMessage> filteredMessages = filter.FilterMessages(messages);
// Assert
filteredMessages.Should().BeEquivalentTo(expected);
}
}
+1 -38
View File
@@ -7,44 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.1.0] - 2026-04-21
### Added
- **agent-framework-gemini**: Add `GeminiChatClient` ([#4847](https://github.com/microsoft/agent-framework/pull/4847))
- **agent-framework-core**: Add `context_providers` and `description` to `workflow.as_agent()` ([#4651](https://github.com/microsoft/agent-framework/pull/4651))
- **agent-framework-core**: Add experimental file history provider ([#5248](https://github.com/microsoft/agent-framework/pull/5248))
- **agent-framework-core**: Add OpenAI types to the default checkpoint encoding allow list ([#5297](https://github.com/microsoft/agent-framework/pull/5297))
- **agent-framework-core**: Add `AgentExecutorResponse.with_text()` to preserve conversation history through custom executors ([#5255](https://github.com/microsoft/agent-framework/pull/5255))
- **agent-framework-a2a**: Propagate A2A metadata from `Message`, `Artifact`, `Task`, and event types ([#5256](https://github.com/microsoft/agent-framework/pull/5256))
- **agent-framework-core**: Add `finish_reason` support to `AgentResponse` and `AgentResponseUpdate` ([#5211](https://github.com/microsoft/agent-framework/pull/5211))
- **agent-framework-hyperlight**: Add Hyperlight CodeAct package and docs ([#5185](https://github.com/microsoft/agent-framework/pull/5185))
- **agent-framework-openai**: Add search tool content support for OpenAI responses ([#5302](https://github.com/microsoft/agent-framework/pull/5302))
- **agent-framework-foundry**: Add support for Foundry Toolboxes ([#5346](https://github.com/microsoft/agent-framework/pull/5346))
- **agent-framework-ag-ui**: Expose `forwardedProps` to agents and tools via session metadata ([#5264](https://github.com/microsoft/agent-framework/pull/5264))
- **agent-framework-foundry**: Add hosted agent V2 support ([#5379](https://github.com/microsoft/agent-framework/pull/5379))
### Changed
- **agent-framework-azure-cosmos**: [BREAKING] `CosmosCheckpointStorage` now uses restricted pickle deserialization by default, matching `FileCheckpointStorage` behavior. If your checkpoints contain application-defined types, pass them via `allowed_checkpoint_types=["my_app.models:MyState"]`. ([#5200](https://github.com/microsoft/agent-framework/issues/5200))
- **agent-framework-core**: Improve skill name validation ([#4530](https://github.com/microsoft/agent-framework/pull/4530))
- **agent-framework-azure-cosmos**: Add `allowed_checkpoint_types` support to `CosmosCheckpointStorage` for parity with `FileCheckpointStorage` ([#5202](https://github.com/microsoft/agent-framework/pull/5202))
- **agent-framework-core**: Move `InMemory` history provider injection to first invocation ([#5236](https://github.com/microsoft/agent-framework/pull/5236))
- **agent-framework-github-copilot**: Forward provider config to `SessionConfig` in `GitHubCopilotAgent` ([#5195](https://github.com/microsoft/agent-framework/pull/5195))
- **agent-framework-hyperlight-codeact**: Flatten `execute_code` output ([#5333](https://github.com/microsoft/agent-framework/pull/5333))
- **dependencies**: Bump `pygments` from `2.19.2` to `2.20.0` in `/python` ([#4978](https://github.com/microsoft/agent-framework/pull/4978))
- **tests**: Bump misc integration retry delay to 30s ([#5293](https://github.com/microsoft/agent-framework/pull/5293))
- **tests**: Improve misc integration test robustness ([#5295](https://github.com/microsoft/agent-framework/pull/5295))
- **tests**: Skip hosted tools test on transient upstream MCP errors ([#5296](https://github.com/microsoft/agent-framework/pull/5296))
### Fixed
- **agent-framework-core**: Fix `python-feature-lifecycle` skill YAML frontmatter ([#5226](https://github.com/microsoft/agent-framework/pull/5226))
- **agent-framework-core**: Fix `HandoffBuilder` dropping function-level middleware when cloning agents ([#5220](https://github.com/microsoft/agent-framework/pull/5220))
- **agent-framework-ag-ui**: Fix deterministic state updates from tool results ([#5201](https://github.com/microsoft/agent-framework/pull/5201))
- **agent-framework-devui**: Fix streaming memory growth and add cross-platform regression coverage ([#5221](https://github.com/microsoft/agent-framework/pull/5221))
- **agent-framework-core**: Skip `get_final_response` in `_finalize_stream` when the stream has errored ([#5232](https://github.com/microsoft/agent-framework/pull/5232))
- **agent-framework-openai**: Fix reasoning replay when `store=False` ([#5250](https://github.com/microsoft/agent-framework/pull/5250))
- **agent-framework-foundry**: Handle `url_citation` annotations in `FoundryChatClient` streaming responses ([#5071](https://github.com/microsoft/agent-framework/pull/5071))
- **agent-framework-gemini**: Fix Gemini client support for Gemini API and Vertex AI ([#5258](https://github.com/microsoft/agent-framework/pull/5258))
- **agent-framework-copilotstudio**: Fix `CopilotStudioAgent` to reuse conversation ID from an existing session ([#5299](https://github.com/microsoft/agent-framework/pull/5299))
## [devui-1.0.0b260414] - 2026-04-14
@@ -939,8 +903,7 @@ Release candidate for **agent-framework-core** and **agent-framework-azure-ai**
For more information, see the [announcement blog post](https://devblogs.microsoft.com/foundry/introducing-microsoft-agent-framework-the-open-source-engine-for-agentic-ai-apps/).
[Unreleased]: https://github.com/microsoft/agent-framework/compare/python-1.1.0...HEAD
[1.1.0]: https://github.com/microsoft/agent-framework/compare/python-1.0.1...python-1.1.0
[Unreleased]: https://github.com/microsoft/agent-framework/compare/python-1.0.1...HEAD
[1.0.1]: https://github.com/microsoft/agent-framework/compare/python-1.0.0...python-1.0.1
[1.0.0]: https://github.com/microsoft/agent-framework/compare/python-1.0.0rc6...python-1.0.0
[1.0.0rc6]: https://github.com/microsoft/agent-framework/compare/python-1.0.0rc5...python-1.0.0rc6
+2 -2
View File
@@ -4,7 +4,7 @@ description = "A2A integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"a2a-sdk>=0.3.5,<0.3.24",
]
@@ -69,23 +69,19 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
# Keys that are internal to AG-UI orchestration and should not be passed to chat clients
AG_UI_INTERNAL_METADATA_KEYS = {"ag_ui_thread_id", "ag_ui_run_id", "current_state", "forwarded_props"}
AG_UI_INTERNAL_METADATA_KEYS = {"ag_ui_thread_id", "ag_ui_run_id", "current_state"}
def _build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, Any]:
"""Build metadata dict with string values for Azure compatibility.
"""Build metadata dict with truncated string values for Azure compatibility.
Azure has a 512 character limit per metadata value. String values that
already fit are kept as-is. Non-string values are JSON-serialized. If the
resulting string exceeds 512 characters the key is **dropped** (with a
warning) instead of truncated, because truncation can produce invalid JSON
that downstream consumers cannot decode.
Azure has a 512 character limit per metadata value.
Args:
thread_metadata: Raw metadata dict
Returns:
Metadata with safe string values (each <= 512 chars)
Metadata with string values truncated to 512 chars
"""
if not thread_metadata:
return {}
@@ -93,12 +89,7 @@ def _build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, An
for key, value in thread_metadata.items():
value_str = value if isinstance(value, str) else json.dumps(value)
if len(value_str) > 512:
logger.warning(
"Dropping metadata key %r: serialized value is %d chars (limit 512)",
key,
len(value_str),
)
continue
value_str = value_str[:512]
safe_metadata[key] = value_str
return safe_metadata
@@ -799,10 +790,6 @@ async def run_agent_stream(
"ag_ui_thread_id": thread_id,
"ag_ui_run_id": run_id,
}
if "forwarded_props" in input_data:
base_metadata["forwarded_props"] = input_data["forwarded_props"]
elif "forwardedProps" in input_data:
base_metadata["forwarded_props"] = input_data["forwardedProps"]
if flow.current_state:
base_metadata["current_state"] = flow.current_state
session.metadata = _build_safe_metadata(base_metadata) # type: ignore[attr-defined]
@@ -4,7 +4,6 @@
from __future__ import annotations
import inspect
import json
import logging
import uuid
@@ -582,33 +581,11 @@ async def run_workflow_stream(
flow.accumulated_text = ""
return [TextMessageEndEvent(message_id=current_message_id)]
fwd_kwargs: dict[str, Any] = {}
if "forwarded_props" in input_data:
forwarded_props = input_data["forwarded_props"]
fwd_kwargs["function_invocation_kwargs"] = {"forwarded_props": forwarded_props}
elif "forwardedProps" in input_data:
forwarded_props = input_data["forwardedProps"]
fwd_kwargs["function_invocation_kwargs"] = {"forwarded_props": forwarded_props}
# Only pass function_invocation_kwargs if the workflow.run signature accepts it
if fwd_kwargs:
try:
sig = inspect.signature(workflow.run)
params = sig.parameters
accepts_fwd = "function_invocation_kwargs" in params or any(
p.kind == inspect.Parameter.VAR_KEYWORD for p in params.values()
)
except (ValueError, TypeError):
accepts_fwd = False
if not accepts_fwd:
logger.debug("workflow.run() does not accept function_invocation_kwargs; dropping forwarded_props")
fwd_kwargs = {}
try:
if responses:
event_stream = workflow.run(responses=responses, stream=True, **fwd_kwargs)
event_stream = workflow.run(responses=responses, stream=True)
else:
event_stream = workflow.run(message=messages, stream=True, **fwd_kwargs)
event_stream = workflow.run(message=messages, stream=True)
async for event in event_stream:
event_type = getattr(event, "type", None)
+2 -2
View File
@@ -1,6 +1,6 @@
[project]
name = "agent-framework-ag-ui"
version = "1.0.0b260421"
version = "1.0.0b260409"
description = "AG-UI protocol integration for Agent Framework"
readme = "README.md"
license-files = ["LICENSE"]
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"ag-ui-protocol==0.1.13",
"fastapi>=0.115.0,<0.133.1",
"uvicorn[standard]>=0.30.0,<0.42.0"
@@ -1,83 +0,0 @@
# Copyright (c) Microsoft. All rights reserved.
"""Tests for forwarded_props inclusion in AG-UI session metadata."""
import json
from typing import Any
from agent_framework_ag_ui._agent_run import AG_UI_INTERNAL_METADATA_KEYS, _build_safe_metadata
class TestForwardedPropsInSessionMetadata:
"""Verify that forwarded_props is surfaced in session metadata and filtered from LLM metadata."""
def test_forwarded_props_in_internal_metadata_keys(self):
"""forwarded_props is listed in AG_UI_INTERNAL_METADATA_KEYS to prevent LLM leakage."""
assert "forwarded_props" in AG_UI_INTERNAL_METADATA_KEYS
def test_forwarded_props_filtered_from_client_metadata(self):
"""forwarded_props is filtered out when building LLM-bound client metadata."""
session_metadata: dict[str, Any] = {
"ag_ui_thread_id": "t1",
"ag_ui_run_id": "r1",
"forwarded_props": '{"custom_flag": true}',
}
client_metadata = {k: v for k, v in session_metadata.items() if k not in AG_UI_INTERNAL_METADATA_KEYS}
assert "forwarded_props" not in client_metadata
assert "ag_ui_thread_id" not in client_metadata
class TestBuildSafeMetadata:
"""Verify _build_safe_metadata handles various value types correctly."""
def test_string_value_unchanged(self):
result = _build_safe_metadata({"key": "hello"})
assert result == {"key": "hello"}
def test_dict_value_serialized_to_json(self):
result = _build_safe_metadata({"fp": {"flag": True, "source": "frontend"}})
assert "fp" in result
assert isinstance(result["fp"], str)
# Must be valid, decodable JSON
decoded = json.loads(result["fp"])
assert decoded == {"flag": True, "source": "frontend"}
def test_empty_dict_serialized_to_json(self):
result = _build_safe_metadata({"fp": {}})
assert result["fp"] == "{}"
assert json.loads(result["fp"]) == {}
def test_value_within_limit_kept(self):
value = "x" * 512
result = _build_safe_metadata({"key": value})
assert result["key"] == value
def test_value_exceeding_limit_dropped(self):
"""Values exceeding 512 chars are dropped entirely (not truncated)."""
value = "x" * 513
result = _build_safe_metadata({"key": value})
assert "key" not in result
def test_json_value_exceeding_limit_dropped(self):
"""JSON-serialized dict exceeding 512 chars is dropped, not truncated into invalid JSON."""
big_dict = {f"key_{i}": "v" * 100 for i in range(50)}
result = _build_safe_metadata({"forwarded_props": big_dict})
assert "forwarded_props" not in result
def test_other_keys_preserved_when_one_dropped(self):
"""Dropping one oversized key does not affect other keys."""
result = _build_safe_metadata(
{
"small": "ok",
"big": "x" * 600,
}
)
assert result == {"small": "ok"}
def test_none_input_returns_empty(self):
assert _build_safe_metadata(None) == {}
def test_empty_input_returns_empty(self):
assert _build_safe_metadata({}) == {}
@@ -63,12 +63,12 @@ class TestBuildSafeMetadata:
result = _build_safe_metadata(metadata)
assert result == metadata
def test_drops_long_strings(self):
"""Drops strings over 512 chars instead of truncating."""
def test_truncates_long_strings(self):
"""Truncates strings over 512 chars."""
long_value = "x" * 1000
metadata = {"key": long_value}
result = _build_safe_metadata(metadata)
assert "key" not in result
assert len(result["key"]) == 512
def test_serializes_non_strings(self):
"""Serializes non-string values to JSON."""
@@ -77,12 +77,12 @@ class TestBuildSafeMetadata:
assert result["count"] == "42"
assert result["items"] == "[1, 2, 3]"
def test_drops_oversized_serialized_values(self):
"""Drops serialized values over 512 chars instead of truncating."""
def test_truncates_serialized_values(self):
"""Truncates serialized values over 512 chars."""
long_list = list(range(200))
metadata = {"data": long_list}
result = _build_safe_metadata(metadata)
assert "data" not in result
assert len(result["data"]) == 512
class TestHasOnlyToolCalls:
@@ -1672,210 +1672,3 @@ async def test_workflow_run_non_terminal_status_emits_custom():
custom = [e for e in events if e.type == "CUSTOM" and e.name == "status"]
assert len(custom) == 1
assert custom[0].value == {"state": "running"}
async def test_workflow_run_passes_forwarded_props_as_function_invocation_kwargs() -> None:
"""forwarded_props from input_data is forwarded to workflow.run() via function_invocation_kwargs."""
class CapturingWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, **kwargs: Any):
self.captured_kwargs = dict(kwargs)
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = CapturingWorkflow()
events = [
event
async for event in run_workflow_stream(
{
"messages": [{"role": "user", "content": "hello"}],
"forwarded_props": {"custom_flag": True, "source": "copilotkit"},
},
cast(Any, workflow),
)
]
event_types = [event.type for event in events]
assert "RUN_STARTED" in event_types
assert "RUN_FINISHED" in event_types
assert workflow.captured_kwargs["stream"] is True
assert "function_invocation_kwargs" in workflow.captured_kwargs
assert workflow.captured_kwargs["function_invocation_kwargs"] == {
"forwarded_props": {"custom_flag": True, "source": "copilotkit"},
}
async def test_workflow_run_omits_function_invocation_kwargs_when_no_forwarded_props() -> None:
"""function_invocation_kwargs is not passed when forwarded_props is absent."""
class CapturingWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, **kwargs: Any):
self.captured_kwargs = dict(kwargs)
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = CapturingWorkflow()
events = [
event
async for event in run_workflow_stream(
{"messages": [{"role": "user", "content": "hello"}]},
cast(Any, workflow),
)
]
event_types = [event.type for event in events]
assert "RUN_STARTED" in event_types
assert workflow.captured_kwargs["stream"] is True
assert "function_invocation_kwargs" not in workflow.captured_kwargs
async def test_workflow_run_accepts_camel_case_forwarded_props() -> None:
"""forwardedProps (camelCase) is accepted as an alternative key."""
class CapturingWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, **kwargs: Any):
self.captured_kwargs = dict(kwargs)
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = CapturingWorkflow()
events = [
event
async for event in run_workflow_stream(
{
"messages": [{"role": "user", "content": "hello"}],
"forwardedProps": {"source": "frontend"},
},
cast(Any, workflow),
)
]
event_types = [event.type for event in events]
assert "RUN_STARTED" in event_types
assert workflow.captured_kwargs["stream"] is True
assert "function_invocation_kwargs" in workflow.captured_kwargs
assert workflow.captured_kwargs["function_invocation_kwargs"] == {
"forwarded_props": {"source": "frontend"},
}
async def test_workflow_run_passes_empty_dict_forwarded_props() -> None:
"""An empty dict forwarded_props={} should still be forwarded (not dropped by truthiness)."""
class CapturingWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, **kwargs: Any):
self.captured_kwargs = dict(kwargs)
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = CapturingWorkflow()
events = [
event
async for event in run_workflow_stream(
{
"messages": [{"role": "user", "content": "hello"}],
"forwarded_props": {},
},
cast(Any, workflow),
)
]
event_types = [event.type for event in events]
assert "RUN_STARTED" in event_types
assert "RUN_FINISHED" in event_types
assert workflow.captured_kwargs["stream"] is True
assert "function_invocation_kwargs" in workflow.captured_kwargs
assert workflow.captured_kwargs["function_invocation_kwargs"] == {
"forwarded_props": {},
}
async def test_workflow_run_stream_true_always_passed() -> None:
"""stream=True is always passed to workflow.run()."""
class CapturingWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, **kwargs: Any):
self.captured_kwargs = dict(kwargs)
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = CapturingWorkflow()
_ = [
event
async for event in run_workflow_stream(
{
"messages": [{"role": "user", "content": "hello"}],
"forwarded_props": {"key": "val"},
},
cast(Any, workflow),
)
]
assert workflow.captured_kwargs["stream"] is True
async def test_workflow_run_drops_fwd_kwargs_when_run_lacks_param() -> None:
"""function_invocation_kwargs is silently dropped if workflow.run() does not accept it."""
class StrictWorkflow:
def __init__(self) -> None:
self.captured_kwargs: dict[str, Any] = {}
def run(self, *, message: Any = None, responses: Any = None, stream: bool = False):
self.captured_kwargs = {"message": message, "responses": responses, "stream": stream}
async def _stream():
yield SimpleNamespace(type="started")
return _stream()
workflow = StrictWorkflow()
events = [
event
async for event in run_workflow_stream(
{
"messages": [{"role": "user", "content": "hello"}],
"forwarded_props": {"custom": True},
},
cast(Any, workflow),
)
]
event_types = [event.type for event in events]
assert "RUN_STARTED" in event_types
assert "RUN_FINISHED" in event_types
# No TypeError raised, and function_invocation_kwargs was not passed
assert "function_invocation_kwargs" not in workflow.captured_kwargs
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Anthropic integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"anthropic>=0.80.0,<0.80.1",
]
@@ -4,7 +4,7 @@ description = "Azure AI Search integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"azure-search-documents>=11.7.0b2,<11.7.0b3",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Azure Cosmos DB history provider integration for Microsoft Agent
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"azure-cosmos>=4.3.0,<5",
]
@@ -4,7 +4,7 @@ description = "Azure Functions integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"agent-framework-durabletask",
"azure-functions>=1.24.0,<2",
"azure-functions-durable>=1.3.1,<2",
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Amazon Bedrock integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"boto3>=1.35.0,<2.0.0",
"botocore>=1.35.0,<2.0.0",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "OpenAI ChatKit integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"openai-chatkit>=1.4.1,<2.0.0",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Claude Agent SDK integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"claude-agent-sdk>=0.1.36,<0.1.49",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Copilot Studio integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"microsoft-agents-copilotstudio-client>=0.3.1,<0.3.2",
]
+1 -1
View File
@@ -4,7 +4,7 @@ description = "Microsoft Agent Framework for building AI Agents with Python. Thi
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.1.0"
version = "1.0.1"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -664,21 +664,6 @@ def test_function_approval_serialization_roundtrip():
# The Content union will need to be handled differently when we fully migrate
def test_function_approval_request_function_call_none_guard():
"""Test that accessing function_call attributes is safe when function_call is None."""
# Construct a Content with type "function_approval_request" but no function_call.
# This verifies the None-guard pattern used in samples to prevent AttributeError.
content = Content("function_approval_request", id="req-none")
assert content.function_call is None
# A proper approval request always has function_call set
fc = Content.from_function_call(call_id="call-1", name="do_something", arguments={"a": 1})
req = Content.from_function_approval_request(id="req-1", function_call=fc)
assert req.function_call is not None
assert req.function_call.name == "do_something"
assert req.function_call.arguments == {"a": 1}
def test_function_approval_accepts_mcp_call():
"""Ensure FunctionApprovalRequestContent supports MCP server tool calls."""
mcp_call = Content.from_mcp_server_tool_call(
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Declarative specification support for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"powerfx>=0.0.32,<0.0.35; python_version < '3.14'",
"pyyaml>=6.0,<7.0",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Debug UI for Microsoft Agent Framework with OpenAI-compatible API
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260414"
license-files = ["LICENSE"]
urls.homepage = "https://github.com/microsoft/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"openai>=1.99.0,<3",
"opentelemetry-sdk>=1.39.0,<2",
"fastapi>=0.115.0,<0.133.1",
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Durable Task integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"durabletask>=1.3.0,<2",
"durabletask-azuremanaged>=1.3.0,<2",
"python-dateutil>=2.8.0,<3",
+3 -3
View File
@@ -4,7 +4,7 @@ description = "Microsoft Foundry integrations for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.1.0"
version = "1.0.1"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,8 +23,8 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-openai>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"agent-framework-openai>=1.0.1,<2",
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
"azure-ai-projects>=2.1.0,<3.0",
]
@@ -4,7 +4,7 @@ description = "Foundry Hosting integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0a260421"
version = "1.0.0a260420"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.0,<2",
"azure-ai-agentserver-core==2.0.0b2",
"azure-ai-agentserver-responses==1.0.0b4",
"azure-ai-agentserver-invocations==1.0.0b2",
+3 -3
View File
@@ -4,7 +4,7 @@ description = "Foundry Local integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,8 +23,8 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-openai>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"agent-framework-openai>=1.0.1,<2",
"foundry-local-sdk>=0.5.1,<0.5.2",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Google Gemini integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0a260421"
version = "1.0.0a260410"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -24,7 +24,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2.0",
"agent-framework-core>=1.0.0,<2.0",
"google-genai>=1.0.0,<2.0.0",
]
@@ -4,7 +4,7 @@ description = "GitHub Copilot integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"github-copilot-sdk>=0.2.1,<=0.2.1; python_version >= '3.11'",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Hyperlight CodeAct integrations for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0a260421"
version = "1.0.0a260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.0,<2",
"hyperlight-sandbox>=0.3.0,<0.4",
"hyperlight-sandbox-backend-wasm>=0.3.0,<0.4 ; ((sys_platform == 'linux' and platform_machine == 'x86_64') or (sys_platform == 'win32' and platform_machine == 'AMD64')) and python_version < '3.14'",
"hyperlight-sandbox-python-guest>=0.3.0,<0.4",
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Experimental modules for Microsoft Agent Framework"
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: 3.14",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
]
[project.optional-dependencies]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Mem0 integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"mem0ai>=1.0.0,<2",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Ollama integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://learn.microsoft.com/en-us/agent-framework/"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"ollama>=0.5.3,<0.5.4",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "OpenAI integrations for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.1.0"
version = "1.0.1"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"openai>=1.99.0,<3",
]
@@ -4,7 +4,7 @@ description = "Orchestration patterns for Microsoft Agent Framework. Includes Se
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
]
[tool.uv]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Microsoft Purview (Graph dataSecurityAndGovernance) integration f
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://github.com/microsoft/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -24,7 +24,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"azure-core>=1.30.0,<2",
"httpx>=0.27.0,<0.29",
]
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Redis integration for Microsoft Agent Framework."
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.0.0b260421"
version = "1.0.0b260409"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core>=1.1.0,<2",
"agent-framework-core>=1.0.1,<2",
"redis>=6.4.0,<7.2.1",
"redisvl>=0.11.0,<0.16",
"numpy>=2.2.6,<3"
+2 -2
View File
@@ -4,7 +4,7 @@ description = "Microsoft Agent Framework for building AI Agents with Python. Thi
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
readme = "README.md"
requires-python = ">=3.10"
version = "1.1.0"
version = "1.0.1"
license-files = ["LICENSE"]
urls.homepage = "https://aka.ms/agent-framework"
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
@@ -23,7 +23,7 @@ classifiers = [
"Typing :: Typed",
]
dependencies = [
"agent-framework-core[all]==1.1.0",
"agent-framework-core[all]==1.0.1",
]
[dependency-groups]
@@ -29,19 +29,19 @@ approval will pause the workflow until the human responds.
This sample works as follows:
1. A ConcurrentBuilder workflow is created with two agents running in parallel.
2. Both agents have the same tools, including two requiring approval (execute_trade, set_stop_loss).
2. Both agents have the same tools, including one requiring approval (execute_trade).
3. Both agents receive the same task and work concurrently on their respective stocks.
4. When either agent tries to execute a trade or set a stop-loss, it triggers an approval request.
4. When either agent tries to execute a trade, it triggers an approval request.
5. The sample simulates human approval and the workflow completes.
6. Results from both agents are aggregated and output.
Purpose:
Show how tool call approvals work in parallel execution scenarios where multiple
agents may independently trigger approval requests for different tools.
agents may independently trigger approval requests.
Demonstrate:
- Handling multiple approval requests from different agents in concurrent workflows.
- Handling approval requests for different tools during concurrent agent execution.
- Handling during concurrent agent execution.
- Understanding that approval pauses only the agent that triggered it, not all agents.
Prerequisites:
@@ -89,15 +89,6 @@ def execute_trade(
return f"Trade executed: {action.upper()} {quantity} shares of {symbol.upper()}"
@tool(approval_mode="always_require")
def set_stop_loss(
symbol: Annotated[str, "The stock ticker symbol"],
stop_price: Annotated[float, "The stop-loss price"],
) -> str:
"""Set a stop-loss order for a stock. Requires human approval due to financial impact."""
return f"Stop-loss set for {symbol.upper()} at ${stop_price:.2f}"
@tool(approval_mode="never_require")
def get_portfolio_balance() -> str:
"""Get current portfolio balance and available funds."""
@@ -127,17 +118,14 @@ async def process_event_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str
if event.type == "request_info" and isinstance(event.data, Content):
# We are only expecting tool approval requests in this sample
requests[event.request_id] = event.data
if event.data.type == "function_approval_request" and event.data.function_call is not None:
print(f"\nApproval requested for tool: {event.data.function_call.name}")
print(f"Arguments: {event.data.function_call.arguments}")
elif event.type == "output":
_print_output(event)
responses: dict[str, Content] = {}
if requests:
for request_id, request in requests.items():
if request.type == "function_approval_request" and request.function_call is not None:
print(f"\nSimulating human approval for: {request.function_call.name}")
if request.type == "function_approval_request":
print(f"\nSimulating human approval for: {request.function_call.name}") # type: ignore
# Create approval response
responses[request_id] = request.to_function_approval_response(approved=True)
@@ -157,10 +145,9 @@ async def main() -> None:
name="MicrosoftAgent",
instructions=(
"You are a personal trading assistant focused on Microsoft (MSFT). "
"You manage my portfolio and take actions based on market data. "
"Use stop-loss orders to manage risk."
"You manage my portfolio and take actions based on market data."
),
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade, set_stop_loss],
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade],
)
google_agent = Agent(
@@ -168,10 +155,9 @@ async def main() -> None:
name="GoogleAgent",
instructions=(
"You are a personal trading assistant focused on Google (GOOGL). "
"You manage my trades and portfolio based on market conditions. "
"Use stop-loss orders to manage risk."
"You manage my trades and portfolio based on market conditions."
),
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade, set_stop_loss],
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade],
)
# 4. Build a concurrent workflow with both agents
@@ -186,8 +172,7 @@ async def main() -> None:
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run(
"Manage my portfolio. Use a max of 5000 dollars to adjust my position using "
"your best judgment based on market sentiment. Set stop-loss orders to manage risk. "
"No need to confirm trades with me.",
"your best judgment based on market sentiment. No need to confirm trades with me.",
stream=True,
)
@@ -206,32 +191,22 @@ async def main() -> None:
Approval requested for tool: execute_trade
Arguments: {"symbol":"MSFT","action":"buy","quantity":13}
Approval requested for tool: set_stop_loss
Arguments: {"symbol":"MSFT","stop_price":340.0}
Approval requested for tool: execute_trade
Arguments: {"symbol":"GOOGL","action":"buy","quantity":35}
Approval requested for tool: set_stop_loss
Arguments: {"symbol":"GOOGL","stop_price":126.0}
Simulating human approval for: execute_trade
Simulating human approval for: set_stop_loss
Simulating human approval for: execute_trade
Simulating human approval for: set_stop_loss
------------------------------------------------------------
Workflow completed. Aggregated results from both agents:
- user: Manage my portfolio. Use a max of 5000 dollars to adjust my position using your best judgment based on
market sentiment. Set stop-loss orders to manage risk. No need to confirm trades with me.
- MicrosoftAgent: I have successfully purchased 13 shares of Microsoft (MSFT) and set a stop-loss at $340.00.
This action was based on the positive market sentiment and available funds within the
specified limit. Your portfolio has been adjusted accordingly.
- GoogleAgent: I have successfully purchased 35 shares of GOOGL and set a stop-loss at $126.00. If you need
further assistance or any adjustments, feel free to ask!
market sentiment. No need to confirm trades with me.
- MicrosoftAgent: I have successfully executed the trade, purchasing 13 shares of Microsoft (MSFT). This action
was based on the positive market sentiment and available funds within the specified limit.
Your portfolio has been adjusted accordingly.
- GoogleAgent: I have successfully executed the trade, purchasing 35 shares of GOOGL. If you need further
assistance or any adjustments, feel free to ask!
"""
@@ -121,11 +121,11 @@ async def process_event_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str
responses: dict[str, Content] = {}
if requests:
for request_id, request in requests.items():
if request.type == "function_approval_request" and request.function_call is not None:
if request.type == "function_approval_request":
print("\n[APPROVAL REQUIRED]")
print(f" Tool: {request.function_call.name}")
print(f" Arguments: {request.function_call.arguments}")
print(f"Simulating human approval for: {request.function_call.name}")
print(f" Tool: {request.function_call.name}") # type: ignore
print(f" Arguments: {request.function_call.arguments}") # type: ignore
print(f"Simulating human approval for: {request.function_call.name}") # type: ignore
# Create approval response
responses[request_id] = request.to_function_approval_response(approved=True)
@@ -94,11 +94,11 @@ async def process_event_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str
responses: dict[str, Content] = {}
if requests:
for request_id, request in requests.items():
if request.type == "function_approval_request" and request.function_call is not None:
if request.type == "function_approval_request":
print("\n[APPROVAL REQUIRED]")
print(f" Tool: {request.function_call.name}")
print(f" Arguments: {request.function_call.arguments}")
print(f"Simulating human approval for: {request.function_call.name}")
print(f" Tool: {request.function_call.name}") # type: ignore
print(f" Arguments: {request.function_call.arguments}") # type: ignore
print(f"Simulating human approval for: {request.function_call.name}") # type: ignore
# Create approval response
responses[request_id] = request.to_function_approval_response(approved=True)
+28 -28
View File
@@ -96,7 +96,7 @@ wheels = [
[[package]]
name = "agent-framework"
version = "1.1.0"
version = "1.0.1"
source = { virtual = "." }
dependencies = [
{ name = "agent-framework-core", extra = ["all"], marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -151,7 +151,7 @@ dev = [
[[package]]
name = "agent-framework-a2a"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/a2a" }
dependencies = [
{ name = "a2a-sdk", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -166,7 +166,7 @@ requires-dist = [
[[package]]
name = "agent-framework-ag-ui"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/ag-ui" }
dependencies = [
{ name = "ag-ui-protocol", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -194,7 +194,7 @@ provides-extras = ["dev"]
[[package]]
name = "agent-framework-anthropic"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/anthropic" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -209,7 +209,7 @@ requires-dist = [
[[package]]
name = "agent-framework-azure-ai-search"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/azure-ai-search" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -224,7 +224,7 @@ requires-dist = [
[[package]]
name = "agent-framework-azure-cosmos"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/azure-cosmos" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -239,7 +239,7 @@ requires-dist = [
[[package]]
name = "agent-framework-azurefunctions"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/azurefunctions" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -261,7 +261,7 @@ dev = []
[[package]]
name = "agent-framework-bedrock"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/bedrock" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -278,7 +278,7 @@ requires-dist = [
[[package]]
name = "agent-framework-chatkit"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/chatkit" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -293,7 +293,7 @@ requires-dist = [
[[package]]
name = "agent-framework-claude"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/claude" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -308,7 +308,7 @@ requires-dist = [
[[package]]
name = "agent-framework-copilotstudio"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/copilotstudio" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -323,7 +323,7 @@ requires-dist = [
[[package]]
name = "agent-framework-core"
version = "1.1.0"
version = "1.0.1"
source = { editable = "packages/core" }
dependencies = [
{ name = "opentelemetry-api", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -395,7 +395,7 @@ provides-extras = ["all"]
[[package]]
name = "agent-framework-declarative"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/declarative" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -420,7 +420,7 @@ dev = [{ name = "types-pyyaml", specifier = "==6.0.12.20250915" }]
[[package]]
name = "agent-framework-devui"
version = "1.0.0b260421"
version = "1.0.0b260414"
source = { editable = "packages/devui" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -458,7 +458,7 @@ provides-extras = ["dev", "all"]
[[package]]
name = "agent-framework-durabletask"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/durabletask" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -485,7 +485,7 @@ dev = [{ name = "types-python-dateutil", specifier = "==2.9.0.20260402" }]
[[package]]
name = "agent-framework-foundry"
version = "1.1.0"
version = "1.0.1"
source = { editable = "packages/foundry" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -504,7 +504,7 @@ requires-dist = [
[[package]]
name = "agent-framework-foundry-hosting"
version = "1.0.0a260421"
version = "1.0.0a260420"
source = { editable = "packages/foundry_hosting" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -523,7 +523,7 @@ requires-dist = [
[[package]]
name = "agent-framework-foundry-local"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/foundry_local" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -540,7 +540,7 @@ requires-dist = [
[[package]]
name = "agent-framework-gemini"
version = "1.0.0a260421"
version = "1.0.0a260410"
source = { editable = "packages/gemini" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -555,7 +555,7 @@ requires-dist = [
[[package]]
name = "agent-framework-github-copilot"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/github_copilot" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -570,7 +570,7 @@ requires-dist = [
[[package]]
name = "agent-framework-hyperlight"
version = "1.0.0a260421"
version = "1.0.0a260409"
source = { editable = "packages/hyperlight" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -589,7 +589,7 @@ requires-dist = [
[[package]]
name = "agent-framework-lab"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/lab" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -670,7 +670,7 @@ dev = [
[[package]]
name = "agent-framework-mem0"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/mem0" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -685,7 +685,7 @@ requires-dist = [
[[package]]
name = "agent-framework-ollama"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/ollama" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -700,7 +700,7 @@ requires-dist = [
[[package]]
name = "agent-framework-openai"
version = "1.1.0"
version = "1.0.1"
source = { editable = "packages/openai" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -715,7 +715,7 @@ requires-dist = [
[[package]]
name = "agent-framework-orchestrations"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/orchestrations" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -726,7 +726,7 @@ requires-dist = [{ name = "agent-framework-core", editable = "packages/core" }]
[[package]]
name = "agent-framework-purview"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/purview" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
@@ -743,7 +743,7 @@ requires-dist = [
[[package]]
name = "agent-framework-redis"
version = "1.0.0b260421"
version = "1.0.0b260409"
source = { editable = "packages/redis" }
dependencies = [
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },