mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5777bc546 | ||
|
|
b6b191ad9c | ||
|
|
2c8036779c | ||
|
|
ce8b6305d8 | ||
|
|
07f4c8a8d6 |
@@ -426,7 +426,7 @@ internal sealed class HandoffAgentExecutor :
|
|||||||
{
|
{
|
||||||
AgentId = this._agent.Id,
|
AgentId = this._agent.Id,
|
||||||
AuthorName = this._agent.Name ?? this._agent.Id,
|
AuthorName = this._agent.Name ?? this._agent.Id,
|
||||||
Contents = [new FunctionResultContent(handoffRequest.CallId, "Transferred.")],
|
Contents = [CreateHandoffResult(handoffRequest.CallId)],
|
||||||
CreatedAt = DateTimeOffset.UtcNow,
|
CreatedAt = DateTimeOffset.UtcNow,
|
||||||
MessageId = Guid.NewGuid().ToString("N"),
|
MessageId = Guid.NewGuid().ToString("N"),
|
||||||
Role = ChatRole.Tool,
|
Role = ChatRole.Tool,
|
||||||
@@ -459,4 +459,6 @@ internal sealed class HandoffAgentExecutor :
|
|||||||
? this._handoffFunctionToAgentId.TryGetValue(requestedHandoff, out string? targetId) ? targetId : null
|
? this._handoffFunctionToAgentId.TryGetValue(requestedHandoff, out string? targetId) ? targetId : null
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static FunctionResultContent CreateHandoffResult(string requestCallId) => new(requestCallId, "Transferred.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.Extensions.AI;
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
namespace Microsoft.Agents.AI.Workflows.Specialized;
|
namespace Microsoft.Agents.AI.Workflows.Specialized;
|
||||||
@@ -31,113 +30,78 @@ internal sealed class HandoffMessagesFilter
|
|||||||
return messages;
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, FilterCandidateState> filteringCandidates = new();
|
HashSet<string> filteredCallsWithoutResponses = new();
|
||||||
List<ChatMessage> filteredMessages = [];
|
List<ChatMessage> retainedMessages = [];
|
||||||
HashSet<int> messagesToRemove = [];
|
|
||||||
|
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.
|
||||||
|
|
||||||
bool filterHandoffOnly = this._filteringBehavior == HandoffToolCallFilteringBehavior.HandoffOnly;
|
|
||||||
foreach (ChatMessage unfilteredMessage in messages)
|
foreach (ChatMessage unfilteredMessage in messages)
|
||||||
{
|
{
|
||||||
ChatMessage filteredMessage = unfilteredMessage.Clone();
|
if (unfilteredMessage.Contents is null || unfilteredMessage.Contents.Count == 0)
|
||||||
|
|
||||||
// .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;
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < unfilteredMessage.Contents!.Count; i++)
|
retainedMessages.Add(unfilteredMessage);
|
||||||
{
|
continue;
|
||||||
AIContent content = unfilteredMessage.Contents[i];
|
|
||||||
if (content is not FunctionCallContent fcc || (filterHandoffOnly && !IsHandoffFunctionName(fcc.Name)))
|
|
||||||
{
|
|
||||||
filteredMessage.Contents.Add(content);
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
foreach (AIContent content in unfilteredMessage.Contents)
|
||||||
{
|
{
|
||||||
if (!filterHandoffOnly)
|
if (content is FunctionCallContent fcc
|
||||||
|
&& (filterAllToolCalls || IsHandoffFunctionName(fcc.Name)))
|
||||||
{
|
{
|
||||||
|
// 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))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Duplicate FunctionCallContent with CallId '{fcc.CallId}' without corresponding FunctionResultContent.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (content is FunctionResultContent frc)
|
||||||
for (int i = 0; i < unfilteredMessage.Contents!.Count; i++)
|
|
||||||
{
|
{
|
||||||
AIContent content = unfilteredMessage.Contents[i];
|
// We rely on the corresponding FCC to have already been processed, so check if it is in the candidate dictionary.
|
||||||
if (content is not FunctionResultContent frc
|
// If it is, we can filter out the FRC, but we need to remove the candidate from the dictionary, since a future FCC can
|
||||||
|| (filteringCandidates.TryGetValue(frc.CallId, out FilterCandidateState? candidateState)
|
// come in with the same CallId, and should be considered a new call that may need to be filtered.
|
||||||
&& candidateState.IsHandoffFunction is false))
|
if (filteredCallsWithoutResponses.Remove(frc.CallId))
|
||||||
{
|
{
|
||||||
// Either this is not a function result content, so we should let it through, or it is a FRC that
|
continue;
|
||||||
// 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 (filteredMessage.Contents.Count > 0)
|
if (retainedContents.Count == 0)
|
||||||
{
|
{
|
||||||
filteredMessages.Add(filteredMessage);
|
// message was fully filtered, skip it
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChatMessage filteredMessage = unfilteredMessage.Clone();
|
||||||
|
filteredMessage.Contents = retainedContents;
|
||||||
|
retainedMessages.Add(filteredMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredMessages.Where((_, index) => !messagesToRemove.Contains(index));
|
return retainedMessages;
|
||||||
}
|
|
||||||
|
|
||||||
private class FilterCandidateState(string callId)
|
|
||||||
{
|
|
||||||
public (int MessageIndex, int ContentIndex)? FunctionCallResultLocation { get; set; }
|
|
||||||
|
|
||||||
public string CallId => callId;
|
|
||||||
|
|
||||||
public bool? IsHandoffFunction { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
-1
@@ -7,8 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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
|
### 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-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
|
## [devui-1.0.0b260414] - 2026-04-14
|
||||||
|
|
||||||
@@ -903,7 +939,8 @@ 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/).
|
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.0.1...HEAD
|
[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
|
||||||
[1.0.1]: https://github.com/microsoft/agent-framework/compare/python-1.0.0...python-1.0.1
|
[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.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
|
[1.0.0rc6]: https://github.com/microsoft/agent-framework/compare/python-1.0.0rc5...python-1.0.0rc6
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "A2A integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"a2a-sdk>=0.3.5,<0.3.24",
|
"a2a-sdk>=0.3.5,<0.3.24",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -69,19 +69,23 @@ if TYPE_CHECKING:
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Keys that are internal to AG-UI orchestration and should not be passed to chat clients
|
# 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"}
|
AG_UI_INTERNAL_METADATA_KEYS = {"ag_ui_thread_id", "ag_ui_run_id", "current_state", "forwarded_props"}
|
||||||
|
|
||||||
|
|
||||||
def _build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, Any]:
|
def _build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, Any]:
|
||||||
"""Build metadata dict with truncated string values for Azure compatibility.
|
"""Build metadata dict with string values for Azure compatibility.
|
||||||
|
|
||||||
Azure has a 512 character limit per metadata value.
|
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.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
thread_metadata: Raw metadata dict
|
thread_metadata: Raw metadata dict
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Metadata with string values truncated to 512 chars
|
Metadata with safe string values (each <= 512 chars)
|
||||||
"""
|
"""
|
||||||
if not thread_metadata:
|
if not thread_metadata:
|
||||||
return {}
|
return {}
|
||||||
@@ -89,7 +93,12 @@ def _build_safe_metadata(thread_metadata: dict[str, Any] | None) -> dict[str, An
|
|||||||
for key, value in thread_metadata.items():
|
for key, value in thread_metadata.items():
|
||||||
value_str = value if isinstance(value, str) else json.dumps(value)
|
value_str = value if isinstance(value, str) else json.dumps(value)
|
||||||
if len(value_str) > 512:
|
if len(value_str) > 512:
|
||||||
value_str = value_str[:512]
|
logger.warning(
|
||||||
|
"Dropping metadata key %r: serialized value is %d chars (limit 512)",
|
||||||
|
key,
|
||||||
|
len(value_str),
|
||||||
|
)
|
||||||
|
continue
|
||||||
safe_metadata[key] = value_str
|
safe_metadata[key] = value_str
|
||||||
return safe_metadata
|
return safe_metadata
|
||||||
|
|
||||||
@@ -790,6 +799,10 @@ async def run_agent_stream(
|
|||||||
"ag_ui_thread_id": thread_id,
|
"ag_ui_thread_id": thread_id,
|
||||||
"ag_ui_run_id": run_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:
|
if flow.current_state:
|
||||||
base_metadata["current_state"] = flow.current_state
|
base_metadata["current_state"] = flow.current_state
|
||||||
session.metadata = _build_safe_metadata(base_metadata) # type: ignore[attr-defined]
|
session.metadata = _build_safe_metadata(base_metadata) # type: ignore[attr-defined]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import uuid
|
import uuid
|
||||||
@@ -581,11 +582,33 @@ async def run_workflow_stream(
|
|||||||
flow.accumulated_text = ""
|
flow.accumulated_text = ""
|
||||||
return [TextMessageEndEvent(message_id=current_message_id)]
|
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:
|
try:
|
||||||
if responses:
|
if responses:
|
||||||
event_stream = workflow.run(responses=responses, stream=True)
|
event_stream = workflow.run(responses=responses, stream=True, **fwd_kwargs)
|
||||||
else:
|
else:
|
||||||
event_stream = workflow.run(message=messages, stream=True)
|
event_stream = workflow.run(message=messages, stream=True, **fwd_kwargs)
|
||||||
|
|
||||||
async for event in event_stream:
|
async for event in event_stream:
|
||||||
event_type = getattr(event, "type", None)
|
event_type = getattr(event, "type", None)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "agent-framework-ag-ui"
|
name = "agent-framework-ag-ui"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
description = "AG-UI protocol integration for Agent Framework"
|
description = "AG-UI protocol integration for Agent Framework"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"ag-ui-protocol==0.1.13",
|
"ag-ui-protocol==0.1.13",
|
||||||
"fastapi>=0.115.0,<0.133.1",
|
"fastapi>=0.115.0,<0.133.1",
|
||||||
"uvicorn[standard]>=0.30.0,<0.42.0"
|
"uvicorn[standard]>=0.30.0,<0.42.0"
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# 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)
|
result = _build_safe_metadata(metadata)
|
||||||
assert result == metadata
|
assert result == metadata
|
||||||
|
|
||||||
def test_truncates_long_strings(self):
|
def test_drops_long_strings(self):
|
||||||
"""Truncates strings over 512 chars."""
|
"""Drops strings over 512 chars instead of truncating."""
|
||||||
long_value = "x" * 1000
|
long_value = "x" * 1000
|
||||||
metadata = {"key": long_value}
|
metadata = {"key": long_value}
|
||||||
result = _build_safe_metadata(metadata)
|
result = _build_safe_metadata(metadata)
|
||||||
assert len(result["key"]) == 512
|
assert "key" not in result
|
||||||
|
|
||||||
def test_serializes_non_strings(self):
|
def test_serializes_non_strings(self):
|
||||||
"""Serializes non-string values to JSON."""
|
"""Serializes non-string values to JSON."""
|
||||||
@@ -77,12 +77,12 @@ class TestBuildSafeMetadata:
|
|||||||
assert result["count"] == "42"
|
assert result["count"] == "42"
|
||||||
assert result["items"] == "[1, 2, 3]"
|
assert result["items"] == "[1, 2, 3]"
|
||||||
|
|
||||||
def test_truncates_serialized_values(self):
|
def test_drops_oversized_serialized_values(self):
|
||||||
"""Truncates serialized values over 512 chars."""
|
"""Drops serialized values over 512 chars instead of truncating."""
|
||||||
long_list = list(range(200))
|
long_list = list(range(200))
|
||||||
metadata = {"data": long_list}
|
metadata = {"data": long_list}
|
||||||
result = _build_safe_metadata(metadata)
|
result = _build_safe_metadata(metadata)
|
||||||
assert len(result["data"]) == 512
|
assert "data" not in result
|
||||||
|
|
||||||
|
|
||||||
class TestHasOnlyToolCalls:
|
class TestHasOnlyToolCalls:
|
||||||
|
|||||||
@@ -1672,3 +1672,210 @@ async def test_workflow_run_non_terminal_status_emits_custom():
|
|||||||
custom = [e for e in events if e.type == "CUSTOM" and e.name == "status"]
|
custom = [e for e in events if e.type == "CUSTOM" and e.name == "status"]
|
||||||
assert len(custom) == 1
|
assert len(custom) == 1
|
||||||
assert custom[0].value == {"state": "running"}
|
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
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Anthropic integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"anthropic>=0.80.0,<0.80.1",
|
"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"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"azure-search-documents>=11.7.0b2,<11.7.0b3",
|
"azure-search-documents>=11.7.0b2,<11.7.0b3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Azure Cosmos DB history provider integration for Microsoft Agent
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"azure-cosmos>=4.3.0,<5",
|
"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"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"agent-framework-durabletask",
|
"agent-framework-durabletask",
|
||||||
"azure-functions>=1.24.0,<2",
|
"azure-functions>=1.24.0,<2",
|
||||||
"azure-functions-durable>=1.3.1,<2",
|
"azure-functions-durable>=1.3.1,<2",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Amazon Bedrock integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"boto3>=1.35.0,<2.0.0",
|
"boto3>=1.35.0,<2.0.0",
|
||||||
"botocore>=1.35.0,<2.0.0",
|
"botocore>=1.35.0,<2.0.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "OpenAI ChatKit integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"openai-chatkit>=1.4.1,<2.0.0",
|
"openai-chatkit>=1.4.1,<2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Claude Agent SDK integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"claude-agent-sdk>=0.1.36,<0.1.49",
|
"claude-agent-sdk>=0.1.36,<0.1.49",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Copilot Studio integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"microsoft-agents-copilotstudio-client>=0.3.1,<0.3.2",
|
"microsoft-agents-copilotstudio-client>=0.3.1,<0.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Microsoft Agent Framework for building AI Agents with Python. Thi
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
|
|||||||
@@ -664,6 +664,21 @@ def test_function_approval_serialization_roundtrip():
|
|||||||
# The Content union will need to be handled differently when we fully migrate
|
# 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():
|
def test_function_approval_accepts_mcp_call():
|
||||||
"""Ensure FunctionApprovalRequestContent supports MCP server tool calls."""
|
"""Ensure FunctionApprovalRequestContent supports MCP server tool calls."""
|
||||||
mcp_call = Content.from_mcp_server_tool_call(
|
mcp_call = Content.from_mcp_server_tool_call(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Declarative specification support for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"powerfx>=0.0.32,<0.0.35; python_version < '3.14'",
|
"powerfx>=0.0.32,<0.0.35; python_version < '3.14'",
|
||||||
"pyyaml>=6.0,<7.0",
|
"pyyaml>=6.0,<7.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Debug UI for Microsoft Agent Framework with OpenAI-compatible API
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260414"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://github.com/microsoft/agent-framework"
|
urls.homepage = "https://github.com/microsoft/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"openai>=1.99.0,<3",
|
"openai>=1.99.0,<3",
|
||||||
"opentelemetry-sdk>=1.39.0,<2",
|
"opentelemetry-sdk>=1.39.0,<2",
|
||||||
"fastapi>=0.115.0,<0.133.1",
|
"fastapi>=0.115.0,<0.133.1",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Durable Task integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"durabletask>=1.3.0,<2",
|
"durabletask>=1.3.0,<2",
|
||||||
"durabletask-azuremanaged>=1.3.0,<2",
|
"durabletask-azuremanaged>=1.3.0,<2",
|
||||||
"python-dateutil>=2.8.0,<3",
|
"python-dateutil>=2.8.0,<3",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Microsoft Foundry integrations for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,8 +23,8 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"agent-framework-openai>=1.0.1,<2",
|
"agent-framework-openai>=1.1.0,<2",
|
||||||
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
|
"azure-ai-inference>=1.0.0b9,<1.0.0b10",
|
||||||
"azure-ai-projects>=2.1.0,<3.0",
|
"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"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0a260420"
|
version = "1.0.0a260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.0,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"azure-ai-agentserver-core==2.0.0b2",
|
"azure-ai-agentserver-core==2.0.0b2",
|
||||||
"azure-ai-agentserver-responses==1.0.0b4",
|
"azure-ai-agentserver-responses==1.0.0b4",
|
||||||
"azure-ai-agentserver-invocations==1.0.0b2",
|
"azure-ai-agentserver-invocations==1.0.0b2",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Foundry Local integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,8 +23,8 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"agent-framework-openai>=1.0.1,<2",
|
"agent-framework-openai>=1.1.0,<2",
|
||||||
"foundry-local-sdk>=0.5.1,<0.5.2",
|
"foundry-local-sdk>=0.5.1,<0.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Google Gemini integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0a260410"
|
version = "1.0.0a260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -24,7 +24,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.0,<2.0",
|
"agent-framework-core>=1.1.0,<2.0",
|
||||||
"google-genai>=1.0.0,<2.0.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"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"github-copilot-sdk>=0.2.1,<=0.2.1; python_version >= '3.11'",
|
"github-copilot-sdk>=0.2.1,<=0.2.1; python_version >= '3.11'",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Hyperlight CodeAct integrations for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0a260409"
|
version = "1.0.0a260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.0,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"hyperlight-sandbox>=0.3.0,<0.4",
|
"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-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",
|
"hyperlight-sandbox-python-guest>=0.3.0,<0.4",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Experimental modules for Microsoft Agent Framework"
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -22,7 +22,7 @@ classifiers = [
|
|||||||
"Programming Language :: Python :: 3.14",
|
"Programming Language :: Python :: 3.14",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Mem0 integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"mem0ai>=1.0.0,<2",
|
"mem0ai>=1.0.0,<2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Ollama integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://learn.microsoft.com/en-us/agent-framework/"
|
urls.homepage = "https://learn.microsoft.com/en-us/agent-framework/"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"ollama>=0.5.3,<0.5.4",
|
"ollama>=0.5.3,<0.5.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "OpenAI integrations for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"openai>=1.99.0,<3",
|
"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"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Microsoft Purview (Graph dataSecurityAndGovernance) integration f
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://github.com/microsoft/agent-framework"
|
urls.homepage = "https://github.com/microsoft/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -24,7 +24,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"azure-core>=1.30.0,<2",
|
"azure-core>=1.30.0,<2",
|
||||||
"httpx>=0.27.0,<0.29",
|
"httpx>=0.27.0,<0.29",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Redis integration for Microsoft Agent Framework."
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core>=1.0.1,<2",
|
"agent-framework-core>=1.1.0,<2",
|
||||||
"redis>=6.4.0,<7.2.1",
|
"redis>=6.4.0,<7.2.1",
|
||||||
"redisvl>=0.11.0,<0.16",
|
"redisvl>=0.11.0,<0.16",
|
||||||
"numpy>=2.2.6,<3"
|
"numpy>=2.2.6,<3"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description = "Microsoft Agent Framework for building AI Agents with Python. Thi
|
|||||||
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
authors = [{ name = "Microsoft", email = "af-support@microsoft.com"}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
urls.homepage = "https://aka.ms/agent-framework"
|
urls.homepage = "https://aka.ms/agent-framework"
|
||||||
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
urls.source = "https://github.com/microsoft/agent-framework/tree/main/python"
|
||||||
@@ -23,7 +23,7 @@ classifiers = [
|
|||||||
"Typing :: Typed",
|
"Typing :: Typed",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"agent-framework-core[all]==1.0.1",
|
"agent-framework-core[all]==1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ approval will pause the workflow until the human responds.
|
|||||||
|
|
||||||
This sample works as follows:
|
This sample works as follows:
|
||||||
1. A ConcurrentBuilder workflow is created with two agents running in parallel.
|
1. A ConcurrentBuilder workflow is created with two agents running in parallel.
|
||||||
2. Both agents have the same tools, including one requiring approval (execute_trade).
|
2. Both agents have the same tools, including two requiring approval (execute_trade, set_stop_loss).
|
||||||
3. Both agents receive the same task and work concurrently on their respective stocks.
|
3. Both agents receive the same task and work concurrently on their respective stocks.
|
||||||
4. When either agent tries to execute a trade, it triggers an approval request.
|
4. When either agent tries to execute a trade or set a stop-loss, it triggers an approval request.
|
||||||
5. The sample simulates human approval and the workflow completes.
|
5. The sample simulates human approval and the workflow completes.
|
||||||
6. Results from both agents are aggregated and output.
|
6. Results from both agents are aggregated and output.
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
Show how tool call approvals work in parallel execution scenarios where multiple
|
Show how tool call approvals work in parallel execution scenarios where multiple
|
||||||
agents may independently trigger approval requests.
|
agents may independently trigger approval requests for different tools.
|
||||||
|
|
||||||
Demonstrate:
|
Demonstrate:
|
||||||
- Handling multiple approval requests from different agents in concurrent workflows.
|
- Handling multiple approval requests from different agents in concurrent workflows.
|
||||||
- Handling during concurrent agent execution.
|
- Handling approval requests for different tools during concurrent agent execution.
|
||||||
- Understanding that approval pauses only the agent that triggered it, not all agents.
|
- Understanding that approval pauses only the agent that triggered it, not all agents.
|
||||||
|
|
||||||
Prerequisites:
|
Prerequisites:
|
||||||
@@ -89,6 +89,15 @@ def execute_trade(
|
|||||||
return f"Trade executed: {action.upper()} {quantity} shares of {symbol.upper()}"
|
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")
|
@tool(approval_mode="never_require")
|
||||||
def get_portfolio_balance() -> str:
|
def get_portfolio_balance() -> str:
|
||||||
"""Get current portfolio balance and available funds."""
|
"""Get current portfolio balance and available funds."""
|
||||||
@@ -118,14 +127,17 @@ async def process_event_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str
|
|||||||
if event.type == "request_info" and isinstance(event.data, Content):
|
if event.type == "request_info" and isinstance(event.data, Content):
|
||||||
# We are only expecting tool approval requests in this sample
|
# We are only expecting tool approval requests in this sample
|
||||||
requests[event.request_id] = event.data
|
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":
|
elif event.type == "output":
|
||||||
_print_output(event)
|
_print_output(event)
|
||||||
|
|
||||||
responses: dict[str, Content] = {}
|
responses: dict[str, Content] = {}
|
||||||
if requests:
|
if requests:
|
||||||
for request_id, request in requests.items():
|
for request_id, request in requests.items():
|
||||||
if request.type == "function_approval_request":
|
if request.type == "function_approval_request" and request.function_call is not None:
|
||||||
print(f"\nSimulating human approval for: {request.function_call.name}") # type: ignore
|
print(f"\nSimulating human approval for: {request.function_call.name}")
|
||||||
# Create approval response
|
# Create approval response
|
||||||
responses[request_id] = request.to_function_approval_response(approved=True)
|
responses[request_id] = request.to_function_approval_response(approved=True)
|
||||||
|
|
||||||
@@ -145,9 +157,10 @@ async def main() -> None:
|
|||||||
name="MicrosoftAgent",
|
name="MicrosoftAgent",
|
||||||
instructions=(
|
instructions=(
|
||||||
"You are a personal trading assistant focused on Microsoft (MSFT). "
|
"You are a personal trading assistant focused on Microsoft (MSFT). "
|
||||||
"You manage my portfolio and take actions based on market data."
|
"You manage my portfolio and take actions based on market data. "
|
||||||
|
"Use stop-loss orders to manage risk."
|
||||||
),
|
),
|
||||||
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade],
|
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade, set_stop_loss],
|
||||||
)
|
)
|
||||||
|
|
||||||
google_agent = Agent(
|
google_agent = Agent(
|
||||||
@@ -155,9 +168,10 @@ async def main() -> None:
|
|||||||
name="GoogleAgent",
|
name="GoogleAgent",
|
||||||
instructions=(
|
instructions=(
|
||||||
"You are a personal trading assistant focused on Google (GOOGL). "
|
"You are a personal trading assistant focused on Google (GOOGL). "
|
||||||
"You manage my trades and portfolio based on market conditions."
|
"You manage my trades and portfolio based on market conditions. "
|
||||||
|
"Use stop-loss orders to manage risk."
|
||||||
),
|
),
|
||||||
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade],
|
tools=[get_stock_price, get_market_sentiment, get_portfolio_balance, execute_trade, set_stop_loss],
|
||||||
)
|
)
|
||||||
|
|
||||||
# 4. Build a concurrent workflow with both agents
|
# 4. Build a concurrent workflow with both agents
|
||||||
@@ -172,7 +186,8 @@ async def main() -> None:
|
|||||||
# Runs are not isolated; state is preserved across multiple calls to run.
|
# Runs are not isolated; state is preserved across multiple calls to run.
|
||||||
stream = workflow.run(
|
stream = workflow.run(
|
||||||
"Manage my portfolio. Use a max of 5000 dollars to adjust my position using "
|
"Manage my portfolio. Use a max of 5000 dollars to adjust my position using "
|
||||||
"your best judgment based on market sentiment. No need to confirm trades with me.",
|
"your best judgment based on market sentiment. Set stop-loss orders to manage risk. "
|
||||||
|
"No need to confirm trades with me.",
|
||||||
stream=True,
|
stream=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -191,22 +206,32 @@ async def main() -> None:
|
|||||||
Approval requested for tool: execute_trade
|
Approval requested for tool: execute_trade
|
||||||
Arguments: {"symbol":"MSFT","action":"buy","quantity":13}
|
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
|
Approval requested for tool: execute_trade
|
||||||
Arguments: {"symbol":"GOOGL","action":"buy","quantity":35}
|
Arguments: {"symbol":"GOOGL","action":"buy","quantity":35}
|
||||||
|
|
||||||
Simulating human approval for: execute_trade
|
Approval requested for tool: set_stop_loss
|
||||||
|
Arguments: {"symbol":"GOOGL","stop_price":126.0}
|
||||||
|
|
||||||
Simulating human approval for: execute_trade
|
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:
|
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
|
- user: Manage my portfolio. Use a max of 5000 dollars to adjust my position using your best judgment based on
|
||||||
market sentiment. No need to confirm trades with me.
|
market sentiment. Set stop-loss orders to manage risk. No need to confirm trades with me.
|
||||||
- MicrosoftAgent: I have successfully executed the trade, purchasing 13 shares of Microsoft (MSFT). This action
|
- MicrosoftAgent: I have successfully purchased 13 shares of Microsoft (MSFT) and set a stop-loss at $340.00.
|
||||||
was based on the positive market sentiment and available funds within the specified limit.
|
This action was based on the positive market sentiment and available funds within the
|
||||||
Your portfolio has been adjusted accordingly.
|
specified limit. Your portfolio has been adjusted accordingly.
|
||||||
- GoogleAgent: I have successfully executed the trade, purchasing 35 shares of GOOGL. If you need further
|
- GoogleAgent: I have successfully purchased 35 shares of GOOGL and set a stop-loss at $126.00. If you need
|
||||||
assistance or any adjustments, feel free to ask!
|
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] = {}
|
responses: dict[str, Content] = {}
|
||||||
if requests:
|
if requests:
|
||||||
for request_id, request in requests.items():
|
for request_id, request in requests.items():
|
||||||
if request.type == "function_approval_request":
|
if request.type == "function_approval_request" and request.function_call is not None:
|
||||||
print("\n[APPROVAL REQUIRED]")
|
print("\n[APPROVAL REQUIRED]")
|
||||||
print(f" Tool: {request.function_call.name}") # type: ignore
|
print(f" Tool: {request.function_call.name}")
|
||||||
print(f" Arguments: {request.function_call.arguments}") # type: ignore
|
print(f" Arguments: {request.function_call.arguments}")
|
||||||
print(f"Simulating human approval for: {request.function_call.name}") # type: ignore
|
print(f"Simulating human approval for: {request.function_call.name}")
|
||||||
# Create approval response
|
# Create approval response
|
||||||
responses[request_id] = request.to_function_approval_response(approved=True)
|
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] = {}
|
responses: dict[str, Content] = {}
|
||||||
if requests:
|
if requests:
|
||||||
for request_id, request in requests.items():
|
for request_id, request in requests.items():
|
||||||
if request.type == "function_approval_request":
|
if request.type == "function_approval_request" and request.function_call is not None:
|
||||||
print("\n[APPROVAL REQUIRED]")
|
print("\n[APPROVAL REQUIRED]")
|
||||||
print(f" Tool: {request.function_call.name}") # type: ignore
|
print(f" Tool: {request.function_call.name}")
|
||||||
print(f" Arguments: {request.function_call.arguments}") # type: ignore
|
print(f" Arguments: {request.function_call.arguments}")
|
||||||
print(f"Simulating human approval for: {request.function_call.name}") # type: ignore
|
print(f"Simulating human approval for: {request.function_call.name}")
|
||||||
# Create approval response
|
# Create approval response
|
||||||
responses[request_id] = request.to_function_approval_response(approved=True)
|
responses[request_id] = request.to_function_approval_response(approved=True)
|
||||||
|
|
||||||
|
|||||||
Generated
+28
-28
@@ -96,7 +96,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework"
|
name = "agent-framework"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", extra = ["all"], marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", extra = ["all"], marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -151,7 +151,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-a2a"
|
name = "agent-framework-a2a"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/a2a" }
|
source = { editable = "packages/a2a" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "a2a-sdk", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "a2a-sdk", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -166,7 +166,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-ag-ui"
|
name = "agent-framework-ag-ui"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/ag-ui" }
|
source = { editable = "packages/ag-ui" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "ag-ui-protocol", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "ag-ui-protocol", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -194,7 +194,7 @@ provides-extras = ["dev"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-anthropic"
|
name = "agent-framework-anthropic"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/anthropic" }
|
source = { editable = "packages/anthropic" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -209,7 +209,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-azure-ai-search"
|
name = "agent-framework-azure-ai-search"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/azure-ai-search" }
|
source = { editable = "packages/azure-ai-search" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -224,7 +224,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-azure-cosmos"
|
name = "agent-framework-azure-cosmos"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/azure-cosmos" }
|
source = { editable = "packages/azure-cosmos" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -239,7 +239,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-azurefunctions"
|
name = "agent-framework-azurefunctions"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/azurefunctions" }
|
source = { editable = "packages/azurefunctions" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -261,7 +261,7 @@ dev = []
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-bedrock"
|
name = "agent-framework-bedrock"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/bedrock" }
|
source = { editable = "packages/bedrock" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -278,7 +278,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-chatkit"
|
name = "agent-framework-chatkit"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/chatkit" }
|
source = { editable = "packages/chatkit" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -293,7 +293,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-claude"
|
name = "agent-framework-claude"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/claude" }
|
source = { editable = "packages/claude" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -308,7 +308,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-copilotstudio"
|
name = "agent-framework-copilotstudio"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/copilotstudio" }
|
source = { editable = "packages/copilotstudio" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -323,7 +323,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-core"
|
name = "agent-framework-core"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = { editable = "packages/core" }
|
source = { editable = "packages/core" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "opentelemetry-api", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "opentelemetry-api", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -395,7 +395,7 @@ provides-extras = ["all"]
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-declarative"
|
name = "agent-framework-declarative"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/declarative" }
|
source = { editable = "packages/declarative" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ 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]]
|
[[package]]
|
||||||
name = "agent-framework-devui"
|
name = "agent-framework-devui"
|
||||||
version = "1.0.0b260414"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/devui" }
|
source = { editable = "packages/devui" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ 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]]
|
[[package]]
|
||||||
name = "agent-framework-durabletask"
|
name = "agent-framework-durabletask"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/durabletask" }
|
source = { editable = "packages/durabletask" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ 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]]
|
[[package]]
|
||||||
name = "agent-framework-foundry"
|
name = "agent-framework-foundry"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = { editable = "packages/foundry" }
|
source = { editable = "packages/foundry" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -504,7 +504,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-foundry-hosting"
|
name = "agent-framework-foundry-hosting"
|
||||||
version = "1.0.0a260420"
|
version = "1.0.0a260421"
|
||||||
source = { editable = "packages/foundry_hosting" }
|
source = { editable = "packages/foundry_hosting" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -523,7 +523,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-foundry-local"
|
name = "agent-framework-foundry-local"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/foundry_local" }
|
source = { editable = "packages/foundry_local" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -540,7 +540,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-gemini"
|
name = "agent-framework-gemini"
|
||||||
version = "1.0.0a260410"
|
version = "1.0.0a260421"
|
||||||
source = { editable = "packages/gemini" }
|
source = { editable = "packages/gemini" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -555,7 +555,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-github-copilot"
|
name = "agent-framework-github-copilot"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/github_copilot" }
|
source = { editable = "packages/github_copilot" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -570,7 +570,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-hyperlight"
|
name = "agent-framework-hyperlight"
|
||||||
version = "1.0.0a260409"
|
version = "1.0.0a260421"
|
||||||
source = { editable = "packages/hyperlight" }
|
source = { editable = "packages/hyperlight" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -589,7 +589,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-lab"
|
name = "agent-framework-lab"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/lab" }
|
source = { editable = "packages/lab" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -670,7 +670,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-mem0"
|
name = "agent-framework-mem0"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/mem0" }
|
source = { editable = "packages/mem0" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -685,7 +685,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-ollama"
|
name = "agent-framework-ollama"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/ollama" }
|
source = { editable = "packages/ollama" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -700,7 +700,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-openai"
|
name = "agent-framework-openai"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = { editable = "packages/openai" }
|
source = { editable = "packages/openai" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -715,7 +715,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-orchestrations"
|
name = "agent-framework-orchestrations"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/orchestrations" }
|
source = { editable = "packages/orchestrations" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ 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]]
|
[[package]]
|
||||||
name = "agent-framework-purview"
|
name = "agent-framework-purview"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/purview" }
|
source = { editable = "packages/purview" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
@@ -743,7 +743,7 @@ requires-dist = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "agent-framework-redis"
|
name = "agent-framework-redis"
|
||||||
version = "1.0.0b260409"
|
version = "1.0.0b260421"
|
||||||
source = { editable = "packages/redis" }
|
source = { editable = "packages/redis" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
{ name = "agent-framework-core", marker = "sys_platform == 'darwin' or sys_platform == 'linux' or sys_platform == 'win32'" },
|
||||||
|
|||||||
Reference in New Issue
Block a user