mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
scope MCP threadId to the current agent
This commit is contained in:
@@ -53,4 +53,16 @@ public sealed class AgentSessionIdTests
|
||||
AgentSessionId sessionId = entityId;
|
||||
});
|
||||
}
|
||||
|
||||
// Ensures the 2-arg constructor treats the key as opaque and never re-interprets
|
||||
// it as a serialized session id, so the resulting Name always comes from the first
|
||||
// argument regardless of the key's shape.
|
||||
[Fact]
|
||||
public void ConstructorTreatsKeyAsOpaqueValue()
|
||||
{
|
||||
AgentSessionId sessionId = new("agentA", "@dafx-agentB@some-key");
|
||||
|
||||
Assert.Equal("agentA", sessionId.Name);
|
||||
Assert.Equal("@dafx-agentB@some-key", sessionId.Key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Microsoft.Agents.AI.DurableTask.UnitTests;
|
||||
|
||||
public sealed class DurableAIAgentProxyTests
|
||||
{
|
||||
// Verifies the proxy rejects a session whose agent name differs from its own,
|
||||
// and that the durable client is never called when this happens.
|
||||
[Fact]
|
||||
public async Task RunAsync_ThrowsWhenSessionBelongsToDifferentAgent()
|
||||
{
|
||||
StubDurableAgentClient client = new();
|
||||
DurableAIAgentProxy proxy = new("agentA", client);
|
||||
DurableAgentSession session = new(new AgentSessionId("agentB", "shared-key"));
|
||||
|
||||
ArgumentException ex = await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
proxy.RunAsync(new ChatMessage(ChatRole.User, "hello"), session));
|
||||
|
||||
Assert.Equal("session", ex.ParamName);
|
||||
Assert.Contains("agentB", ex.Message, StringComparison.Ordinal);
|
||||
Assert.Contains("agentA", ex.Message, StringComparison.Ordinal);
|
||||
Assert.Equal(0, client.CallCount);
|
||||
}
|
||||
|
||||
// Control test: when the session's agent name matches the proxy's name,
|
||||
// the request is forwarded to the durable client.
|
||||
[Fact]
|
||||
public async Task RunAsync_AllowsSessionWhenAgentNameMatches()
|
||||
{
|
||||
AgentSessionId sessionId = new("agentA", "shared-key");
|
||||
InvalidOperationException sentinel = new("reached the client");
|
||||
StubDurableAgentClient client = new() { Throw = sentinel };
|
||||
DurableAIAgentProxy proxy = new("agentA", client);
|
||||
DurableAgentSession session = new(sessionId);
|
||||
|
||||
// Reaching the durable client (and therefore propagating the sentinel) proves the
|
||||
// name-matching guard accepted this session.
|
||||
InvalidOperationException ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
proxy.RunAsync(new ChatMessage(ChatRole.User, "hello"), session));
|
||||
|
||||
Assert.Same(sentinel, ex);
|
||||
Assert.Equal(1, client.CallCount);
|
||||
Assert.Equal(sessionId, client.LastSessionId);
|
||||
}
|
||||
|
||||
// Ensures the agent-name comparison is case-insensitive, so casing differences
|
||||
// are neither a false-positive rejection nor a bypass.
|
||||
[Fact]
|
||||
public async Task RunAsync_AgentNameComparisonIsCaseInsensitive()
|
||||
{
|
||||
AgentSessionId sessionId = new("AGENTA", "shared-key");
|
||||
InvalidOperationException sentinel = new("reached the client");
|
||||
StubDurableAgentClient client = new() { Throw = sentinel };
|
||||
DurableAIAgentProxy proxy = new("agentA", client);
|
||||
DurableAgentSession session = new(sessionId);
|
||||
|
||||
InvalidOperationException ex = await Assert.ThrowsAsync<InvalidOperationException>(() =>
|
||||
proxy.RunAsync(new ChatMessage(ChatRole.User, "hello"), session));
|
||||
|
||||
Assert.Same(sentinel, ex);
|
||||
Assert.Equal(1, client.CallCount);
|
||||
}
|
||||
|
||||
private sealed class StubDurableAgentClient : IDurableAgentClient
|
||||
{
|
||||
public int CallCount { get; private set; }
|
||||
public AgentSessionId LastSessionId { get; private set; }
|
||||
public Exception? Throw { get; set; }
|
||||
|
||||
public Task<AgentRunHandle> RunAgentAsync(
|
||||
AgentSessionId sessionId,
|
||||
RunRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
this.CallCount++;
|
||||
this.LastSessionId = sessionId;
|
||||
if (this.Throw is not null)
|
||||
{
|
||||
return Task.FromException<AgentRunHandle>(this.Throw);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Test did not configure a response.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user