Commit Graph

681 Commits

Author SHA1 Message Date
Chris Gillum 43309018be .NET and Python: Extract Durable Task and Azure Functions integrations (#7465)
* Extract Durable Task and Azure Functions integrations

Remove the migrated implementations, samples, tests, documentation, and repository wiring now owned by microsoft/agent-framework-durable-extension. Preserve Python compatibility through the agent_framework.azure shim and agent-framework-core[all], and leave customer-facing redirects to the new repository.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd

* Fix feature registry validation after extraction

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd

* Narrow external feature package paths

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd

---------

Copilot-Session: 6181dcf9-857b-43ea-9fd2-fcd6b175ffdd
2026-08-03 03:02:07 +00:00
Peter Ibekwe 6a3d535204 .NET: Add regression tests and sample guidance for stable agent IDs in checkpointed workflows (#7415)
* Add regression tests and sample guidance for stable agent IDs in checkpointed workflows

* Updated tests to address PR comments

* Improve test for checkpoint state.
2026-07-30 16:21:18 +00:00
Evan Mattson d07edffaed Python: Fix Actions token environment (#7427)
* Fix Copilot Actions token environment

Expose workflow tokens through GITHUB_TOKEN so Copilot CLI uses native Actions authentication, while preserving user-token integration test support.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d9fa4e9c-c32d-42fb-8ee4-4772473e6479

* Gate Copilot integration tests explicitly

Use GitHub Actions authentication only when both GITHUB_ACTIONS and GITHUB_TOKEN are present, and require an explicit local opt-in that relies on stored Copilot login.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d9fa4e9c-c32d-42fb-8ee4-4772473e6479

---------

Copilot-Session: d9fa4e9c-c32d-42fb-8ee4-4772473e6479
2026-07-30 18:57:23 +09:00
Roger Barreto 0ca6a3e652 .NET: Add source (ZIP) deploy oriented hosted agent samples (#7372)
* Add zip/code-deploy POC for Hosted-ChatClientAgent (.NET)

Migrate the sample to Foundry source (ZIP) deployment as the default: add azure.yaml with codeConfiguration (remote_build, dotnet_10) and the tool-generated .agentignore, make the csproj self-contained (single target, CPM off, published PackageReferences), and simplify Program.cs to the pristine end-user hosting path. Container files are kept for now; contributor and remaining samples handled in follow-ups.

* .NET: Auto-bind Foundry hosted port for zip/code deploy; migrate Hosted-ChatClientAgent to source (ZIP)

Foundry.Hosting: AddFoundryResponses now binds Kestrel to FoundryEnvironment.Port (the PORT env var, default 8088) for a plain WebApplication.CreateBuilder (Tier 3) host, mirroring AgentHostBuilder. This lets a source/ZIP-deployed .NET agent pass the readiness probe with no Dockerfile. It respects an explicit ASPNETCORE_URLS override and is idempotent. Adds FoundryListenPortTests plus a serialized env-var collection.

Hosted-ChatClientAgent: migrate to source (ZIP) deploy as the default. Add azure.yaml with codeConfiguration (remote_build, dotnet_10) and the tool-generated .agentignore, make the csproj self-contained (single target, CPM off) with a local Directory.Packages.props, embed the local-dev per-agent route so the Using-Samples REPL can reach the local server, and rewrite the README around the azd flow. Documents AZURE_TOKEN_CREDENTIALS=dev for local runs.

Using-Samples/SimpleAgent: fix the per-agent endpoint scheme rewrite so the local HTTP dev port is preserved (the policy now lives on the per-agent ProjectOpenAIClientOptions that actually serves the request).

* .NET: Bind Foundry hosted port unconditionally; drop container files and the local-only agent route

Zip/code deploy runs the sample as a plain ASP.NET app, so the Foundry readiness
port was never bound and every invoke returned HTTP 424 session_not_ready. The
first attempt skipped the binding when ASPNETCORE_URLS was already set, but the
.NET base image always sets it to port 80, so the skip always tripped. Kestrel
ListenAnyIP overrides ASPNETCORE_URLS, so the binding is now unconditional and
PORT stays the only knob.

Sample cleanup for zip deploy:
* Remove Dockerfile, Dockerfile.contributor, agent.manifest.yaml and agent.yaml.
  Source deploy needs none of them.
* Remove LocalDevEndpoint.cs and the invented per-agent local route. The local
  server already serves the standard POST /responses route, so the client can
  reach it directly.
* Trim .env.example: the port and environment variables are no longer needed.
* Exclude .checkpoints/ from the upload so local session state does not ship.

SimpleAgent now asks at startup whether to chat with the local server or the
deployed agent, the same choice azd ai agent invoke exposes through --local.
Local uses an OpenAI responses client pointed at http://localhost:8088; Foundry
uses the per-agent endpoint.

Add scripts/New-ContributorStage.ps1, which stages a sample to a temp folder with
the local Agent Framework source packed into a feed inside the upload, so
contributors can deploy framework changes through the same azd flow end users run.

* Pin hosted agent listen port in azure.yaml

* Use the documented env map in azure.yaml

* Make the contributor flow an extra step inside the end-user flow

* Keep contributor scaffolding out of the sample project file

* Document the full deploy walkthrough and add a bash contributor script

* Trim troubleshooting detail from the sample README

* Pass the model deployment name to the hosted container

* Add --local and --remote flags to the SimpleAgent REPL

* Use central package management in the hosted sample

* Clarify where the contributor step fits in the deploy walkthrough

* Restore the HTTP scheme rewrite for local AIProjectClient runs

* Keep the sample package versions in the project file

* Drop the sample Directory.Packages.props

* Add a container deploy variant of the hosted chat client agent sample

* Treat a blank model deployment variable as unset

* Let azd prompt for the Foundry project and expand the contributor section

* Document the stale conversation 404 in the hosted agent samples

* Remove using directives already covered by global usings

* Bind the Foundry listen port only inside a hosted container

* Resolve the Foundry listen port from IConfiguration
2026-07-29 15:34:54 +00:00
Peter Ibekwe 5543bc94fc Fix and re-enable flaky InputWaiter timeout test (#7377) 2026-07-29 15:24:54 +00:00
Alexander Nachtmann 8d22bb9177 .NET: Add Anthropic-backed live tests for OpenAI Responses hosting helpers (#7362)
Mirrors OpenAIResponsesHostingLiveTests with the hosted agent backed by an
Anthropic chat client, confirming the app-owned hosting helper surface
(OpenAIResponses + AgentSessionStore) is provider-agnostic end to end.
Skipped unless ANTHROPIC_API_KEY is configured.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 21:12:42 +00:00
Peter Ibekwe aa53182dc0 .NET: Preserve table state across declarative EditTable operations  (#7353)
* Preserve table state across declarative EditTable operations 

* Address PR comments.
2026-07-28 18:44:38 +00:00
Roger Barreto 859f56fb49 .NET: Skip flaky InputWaiterTests timeout test blocking the merge queue (#7361)
InputWaiter_WaitForInputAsync_CompletesWhenTimeoutExpiresAsync races a
300ms SemaphoreSlim timeout against a 5s Task.Delay guard and asserts
which one won by object identity. On the loaded net472/windows-latest
leg, thread pool starvation can delay the 300ms continuation past the
5s guard, so Task.Delay wins and the assertion fails.

It failed in 7 of the last 18 failed dotnet-build-and-test runs, always
on net472/windows-latest and always in merge_group, blocking PRs that
do not touch the workflows code.

Quarantine it following the existing convention used for #5845, and
track the real fix in #7360.

Copilot-Session: 0be6f810-51de-4f49-b9c7-8d1c7efa2c43
2026-07-28 15:50:47 +00:00
SergeyMenshykh 2694120383 Forward A2A MessageSendParams.Configuration in the A2A adapter (#7365)
The A2A hosting layer now forwards the caller-supplied
SendMessageConfiguration from RequestContext.Configuration into
AgentRunOptions.AdditionalProperties under the key
'a2a.configuration'. This covers all three handler paths:
non-streaming, streaming, and task continuation.

The server-configured AgentRunMode remains authoritative for
AllowBackgroundResponses — the caller's ReturnImmediately is
forwarded but does not override the server decision.

Closes microsoft/agent-framework#5869

Co-authored-by: SergeyMenshykh <SergeMenshikh@outlook.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ee820de-3e34-493b-a19c-1db6bc04871d
2026-07-28 15:25:38 +00:00
KXH 0b0dcaa5af fix(dotnet): preserve table after EditTable add (#7324)
Signed-off-by: KXH <shepherdlaurie238@gmail.com>
2026-07-27 18:29:32 +00:00
westey 28e02d4669 Create session for tool approval agent when non-present (#7310) 2026-07-27 11:07:43 +00:00
westey c59a65da5e .NET: fix InMemoryChatHistoryProvider persisting when service stores history (#7284)
* Fix chat history storage bug

* Improve error messaging

* Address PR comment
2026-07-24 10:44:52 +00:00
Peter Ibekwe 0d5c0f8fa0 .NET: Add language and prompt customization to Magentic orchestration (#7263)
* Add language and prompt customization to Magentic orchestration

* Update default prompts formatting
2026-07-23 18:19:12 +00:00
Ben Thomas bfc73a5b14 .NET: Fix declarative autosend output (#7217)
* Fix declarative workflow auto-send output

Restore completed responses for workflow-conversation agents while preventing hosted workflow adapters from materializing streamed responses twice.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Correlate streamed workflow responses by message

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Handle empty streaming message IDs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Restore workflow conversation auto-send

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Address workflow response review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Ignore whitespace workflow message IDs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

* Correlate all content-bearing agent updates

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c2d86826-ead0-40bc-b84b-a513ac4d325f

---------

Co-authored-by: Ben Thomas <25218250+alliscode@users.noreply.github.com>
2026-07-22 15:11:59 +00:00
Roger Barreto 1f1da1bddb .NET: [BREAKING] Hosting OpenAI Responses protocol helpers and optional execution state (#7000)
* .NET: Add OpenAI Responses protocol helpers and optional execution state (ADR-0032)

* Fix netstandard2.0/net472 build; harden helpers and workflow checkpoint key per review

* .NET: Migrate hosting Responses samples to Azure.AI.Projects and fix workflow resume

Migrate HostingResponsesAgent and HostingResponsesWorkflow samples from
Azure.AI.OpenAI to Azure.AI.Projects (AIProjectClient.AsAIAgent), using the
FOUNDRY_PROJECT_ENDPOINT/FOUNDRY_MODEL convention.

Fix HostedWorkflowState.RunOrResumeAsync: on subsequent turns, restore the
session's latest checkpoint and run the workflow forward with the new turn's
input (mirroring the Python hosting host's restore-then-run semantics) instead
of resuming a halted run with no input, which waited on input indefinitely.
Add round-trip resume tests and update ADR-0032/spec-003 wording.

* .NET: Fix HostedWorkflowState resume hang on unserviced external requests

On resume, HostedWorkflowState.RunOrResumeAsync drained the workflow with the
blocking WatchStreamAsync overload, so a workflow that halts at an unserviced
RequestInfoEvent (human-in-the-loop / approval) blocked forever — asymmetric
with the first-turn RunAsync path, which returns at the same halt. Break the
drain when a superstep completes with HasPendingRequests, restoring symmetry
with turn 1. Add a HITL approval-gate workflow and a resume-does-not-block test.

* .NET: Warn when a HostedWorkflowState resume makes no progress

Add an optional ILoggerFactory to HostedWorkflowState and log a warning when a
resumed turn produces no events, mirroring the Python host's zero-event restore
warning (a stale checkpoint or an input that does not match the workflow's
expected type leaves session state unprogressed). Add a non-chat string workflow
helper, a capturing logger, and a red/green test.

* .NET: Resume HostedWorkflowState from durable checkpoint on cursor miss

Add CheckpointManager.GetLatestCheckpointAsync(sessionId) and have
HostedWorkflowState fall back to it when its in-memory head cursor misses, so a
durable CheckpointManager resumes a session across a process restart or a new
holder instead of restarting from the workflow's start executor. Mirrors the
Python host's per-turn get_latest read-through. Add a counting workflow that
proves resume-vs-fresh via accumulated state, plus a red/green test, and update
ADR-0032/spec-003 and the XML remarks.

* .NET: Serialize HostedWorkflowState turns through a workflow lock

A single workflow instance backs the holder and workflow instances do not
support concurrent runs (the runner throws "already owned by another runner"),
so concurrent turns could fault or race the head cursor. Serialize all turns
through one SemaphoreSlim (mirroring the Python host's workflow lock) and make
HostedWorkflowState IDisposable to own it. Add a gated workflow and a
deterministic concurrency red/green test.

* .NET: Cover non-chat resume and multi-turn checkpoint advance

Add tests for HostedWorkflowState resuming a non-chat-protocol workflow (no
TurnToken) and for a third turn continuing to advance the head checkpoint,
closing the coverage gaps the parity review flagged.

* .NET: Add streaming workflow resume path and stream the workflow sample

Add HostedWorkflowState.RunOrResumeStreamingAsync, which yields the turn's
WorkflowEvents as they occur (fresh run or checkpoint resume) under the same
serialization lock and records the head checkpoint after the stream drains,
keeping the blocking and streaming workflow paths in lockstep with the Python
host. Honor stream:true in the HostingResponsesWorkflow sample by projecting
AgentResponseUpdateEvent updates over the Responses SSE wire. Add a streaming
resume test and update the README/spec.

* .NET: Cover Responses input adaptation to a typed workflow start executor

Demonstrate that HostedWorkflowState's generic RunOrResumeAsync<TInput> is the
input-adaptation seam (parity with Python's ResponsesChannel run hook): the app
adapts the Responses input into the workflow start executor's own type at the
call site. Add a typed-brief workflow and a test, and note the seam in spec-003.

* .NET: Drain workflow resume non-blocking to prevent hang and truncation

The resume drain used a SuperStepCompletedEvent{HasPendingRequests} proxy over
the blocking public WatchStreamAsync. That proxy (a) truncated a resumed turn
when a superstep both emitted a request and queued downstream work, and (b)
could fail to fire at all — re-introducing the indefinite hang — when a resume
input drove no superstep (e.g. a rejected non-chat input).

Make StreamingRun.WatchStreamAsync(bool blockOnPendingRequest, CancellationToken)
public and drain both the blocking and streaming resume paths with
blockOnPendingRequest:false, exactly matching the first-turn RunAsync semantics
(Run.RunToNextHaltAsync). Add guard tests: resume with a rejected input does not
hang, and a resume superstep with a request plus downstream work is not
truncated (verified red against the old proxy).

* .NET: Return file-store checkpoint index in commit order

CheckpointManager.GetLatestCheckpointAsync takes the last entry of a store's
index as the head checkpoint. FileSystemJsonCheckpointStore backed its index
with a HashSet, whose enumeration order is not contractual: after a rollback
frees and reuses a slot, enumeration can diverge from commit order, so the
durable read-through could resume a stale checkpoint. Mirror the HashSet with an
insertion-ordered list and enumerate it from RetrieveIndexAsync so 'latest' is
reliable. Add a CheckpointManager.GetLatestCheckpointAsync contract test over the
file store.

Note: the HashSet disorder is only reachable via the internal rollback path, so
the test locks the ordering contract rather than reproducing the rare disorder.

* .NET: Advance cursor when a streaming resume is abandoned

RunOrResumeStreamingAsync recorded the head checkpoint only after the stream was
fully enumerated. If an SSE consumer disconnected mid-turn after supersteps had
committed, the in-memory cursor kept the previous turn's head; because the next
turn is then a cursor hit, durable read-through could not self-heal, so it
resumed pre-disconnect state. Record the run's last committed checkpoint in a
finally so an abandoned stream still advances the cursor. Add a red/green test.

* .NET: Stream only the final agent's updates in the workflow sample

ExtractUpdates streamed every agent's updates, so the sequential Writer->Reviewer
sample streamed the intermediate draft and the final answer over SSE, differing
from the non-streaming response (final message only). Filter the streamed updates
to the final agent so streaming and non-streaming produce the same response.
Live-verified against Foundry: one output item streamed instead of two.

* .NET: Isolate the holder lock in the concurrency test

The concurrency test asserted the second same-session turn did not enter the
workflow, which also passes via the engine's concurrent-run ownership guard
(which faults) rather than the holder lock (which waits). Assert instead that the
second turn is not completed while the first holds the lock: a fault would
complete the task, so a pending task isolates the holder lock from the engine
guard. Verified red with the lock removed.

* Fix IDE1006 naming in tests; address review feedback and add hosting/live tests

* Document commit-order contract for ICheckpointStore.RetrieveIndexAsync

* Restructure hosting samples under af-hosting with client/server split matching Python parity

* Clarify hosting sample README wording and drop Python comparisons

* Make AgentSessionStore.DeleteSessionAsync abstract and rename session id parameter to sessionStoreId

* Rename OpenAIResponses id helpers and parse the request once for id extraction

* Reclaim per-session locks in HostedAgentState and demonstrate session locking in the agent sample

* Internalize per-session locking in HostedAgentState (automatic, on by default) and remove mirroring-Python wording from code and spec

* Remove HostedAgentState; app-owned routes use AgentSessionStore directly

HostedAgentState only bundled an AIAgent with an AgentSessionStore and, after
the per-session lock was removed, its GetOrCreateSessionAsync/SaveSessionAsync/
DeleteSessionAsync were pass-throughs that just bound the agent argument.
Create-on-miss already lives in the store (unlike Python, whose get/set-only
SessionStore justifies its AgentState holder), so the type earned its place
only via the lock.

Each AgentSessionStore.GetSessionAsync now returns an independent session
instance per call, so concurrent gets fork the same stored state (e.g.
branching from previous_response_id or managing several conversation ids)
without sharing an instance. The store does no cross-call locking; serializing
concurrent runs against the same id is the application's concern.

- Delete HostedAgentState and its unit tests.
- Rewire the local_responses sample and the OpenAI hosting unit/integration
  tests to call AgentSessionStore (GetSessionAsync/SaveSessionAsync) directly.
- Update ADR-0032, spec-003, and the af-hosting sample READMEs.

* Isolate hosted session snapshots and distinguish conversation vs response continuation

Mirrors the Python hosted-session isolation work: a hosted session read must be
an independent copy, and the app-owned route must persist under the right
continuation key depending on how the caller continued the thread.

- AgentSessionStore.GetSessionAsync: document the isolation invariant (each
  call returns an independent AgentSession so concurrent branches from one
  previous_response_id do not observe each other's mutations or alter stored
  state); fix the stale "or null if not found" wording (in-box stores return a
  fresh created session on miss). The in-box stores already satisfy this via a
  serialize/deserialize snapshot round-trip.
- local_responses sample + hosting unit-test route: choose the save key by
  channel. A stable conversation id is a mutable head (write back under the
  same id; app owns single-writer coordination). A previous_response_id
  continuation or first turn is an immutable snapshot (save under the new
  response id so branches from the same prior response stay independent).
- Add regression tests: independent get returns a distinct instance
  (InMemoryAgentSessionStore); previous_response_id supports independent
  branches ([1,2,2,3,3]); conversation id advances the mutable head ([1,2]).
- Update the sample README and ADR-0032 wording.

* Add workflow-factory support to HostedWorkflowState for concurrent sessions

HostedWorkflowState backed every session with one shared Workflow instance and
serialized all turns through a lock, so independent sessions could not run
concurrently. Add a workflow-factory constructor and remove the run lock.

- New constructor HostedWorkflowState(Func<CancellationToken, ValueTask<Workflow>>
  workflowFactory, ..., bool cacheWorkflow = false):
  - cacheWorkflow: false (default) builds a fresh instance per run, so independent
    sessions run in parallel. A resume rehydrates a fresh instance from the
    session's checkpoint in the shared store.
  - cacheWorkflow: true builds the workflow once, lazily on first use, and reuses
    it (a deferred, cached target that, like a shared instance, cannot run
    concurrent turns).
- Remove the internal SemaphoreSlim run lock and IDisposable; the instance
  constructor is unchanged in behaviour (one shared instance still cannot run
  concurrent turns). Turns are no longer serialized by the holder; a single
  writer per session is the application's responsibility.
- Switch the local_responses_workflow sample to the factory constructor with an
  explicit cacheWorkflow: false, and document the option.
- Add tests: parallel independent sessions (factory), fresh-instance resume,
  cached factory builds once and reuses, uncached factory builds per run.
- Update ADR-0032, spec-003, and the sample README.

* Clarify in ADR-0032 how .NET covers AgentState factory and async-setup via DI

* Rebuild cached workflow after a faulted build and add checkpoint index dedup tests
2026-07-22 10:32:44 +00:00
Roger Barreto f6a3c43e9a .NET: Add source-type-agnostic consent regression test for a2a_preview (#7229) 2026-07-21 15:08:06 +00:00
westey c033adb1f4 .NET: [BREAKING] Graduate HarnessAgent (#7119)
* Graduate HarnessAgent

* Switch harness project to released and remove unreleased shell dependency

* Address PR comments.
2026-07-21 14:24:19 +00:00
Roger Barreto 09473fa7ed .NET: [BREAKING] Bind tool-approval responses to surfaced approval requests (#7111)
* .NET: Bind tool-approval responses to surfaced approval requests

Harden the tool-approval flow so an approved tool call always matches the
request the framework surfaced for approval.

Add ApprovalResponseBindingChatClient as the outermost decorator above
FunctionInvokingChatClient. It records each model-originated
ToolApprovalRequestContent in the session state and, on the next request,
binds every ToolApprovalResponseContent to its recorded request: the
response tool call is rebound to the recorded call, matched entries are
consumed for one-time use, and only approvals tied to a framework-issued
request take effect.

Apply the same binding in the ToolApprovalAgent harness by tracking the
requests it surfaces and binding collected responses to them during a
queue cycle.

Add ChatClientAgentOptions.DisableApprovalResponseBinding (default off) and
a UseApprovalResponseBinding builder extension for custom chat client stacks.
Includes unit tests for the decorator and the harness.

* .NET: Bind approval responses once per turn and avoid re-enumeration

Address review feedback on the approval-response binding decorator:
consume a matched request from the per-turn lookup so a duplicate response
with the same request id in one turn is honored only once, and return the
materialized message list instead of the original enumerable so a single-use
sequence is not enumerated twice. Rename the local pending list to
pendingRequests for clarity. Adds a duplicate-response regression test.

* .NET: Snapshot recorded approval requests and consume duplicates in the harness

Address review feedback on ToolApprovalAgent:
store a snapshot of each surfaced/pending approval request (cloned tool call
with a copied arguments dictionary) so a later mutation of the caller-visible
instance cannot change the recorded call used to bind the response, and consume
a surfaced request on match so a duplicate response with the same request id in
one pass is honored only once. Apply both symmetrically in the harness and the
ApprovalResponseBindingChatClient decorator. Adds regression tests for the
snapshot and duplicate-response cases.

* .NET: Address review feedback on approval-response binding

- Harness: store surfaced approval requests in a dictionary and consume matches directly, drop the extra hashset and the redundant record-time dedup; replace clear-on-resolution with a debug assert.
- Harness pipeline: add UseApprovalResponseBinding() as the outermost decorator in HarnessAgent (it uses UseProvidedChatClientAsIs) behind a new DisableApprovalResponseBinding option, with tests.
- Decorator: avoid message/content allocations when nothing changes, keep the original content when a response already matches the recorded call, clear pending each inbound turn, and shorten helpers.

* .NET: Compare tool calls by fields instead of serializing

Replace the JSON-serialization comparison in the approval-response binding
decorator with a direct field comparison. Fast-path FunctionCallContent by
comparing CallId, Name, and arguments field by field; any other tool call
shape rebinds. The comparison only skips an allocation (the call is always
rebound to the recorded request otherwise), so a miss just triggers a safe
rebuild. Adds a test that a matching response is forwarded unchanged.

* .NET: Bind approval responses against requests present in history

Fix a merge-queue regression where AG-UI mixed server/client tool invocation
stopped executing the server tool. The binding decorator validated approval
responses only against its own recorded pending state, so a matched approval
request/response pair replayed from conversation history was treated as
unbound and dropped, and the auto-approved server tool never ran.

Treat known requests as the recorded pending state plus any approval requests
already present in the current messages, and stop dropping approval requests
(a request in history is the pairing authority). A response with no known
request anywhere is still dropped, so a forged approval cannot execute.

Also address review feedback: return the mutable contents buffer from a
helper instead of a null-forgiving operator, and use clearer naming
(PrepareMutableContentsBuffer / mutableContentsBuffer). Adds regression tests
for a request in history and a response bound to a history request with empty
pending state.
2026-07-21 14:23:48 +00:00
安妮的心动录 9cf5143321 .NET: Populate AgentResponse metadata in CopilotStudioAgent (#6791)
* .NET: Populate AgentResponse metadata in CopilotStudioAgent

Map CreatedAt, FinishReason, RawRepresentation and AdditionalProperties onto
AgentResponse and AgentResponseUpdate, and map the activity timestamp and
properties onto ChatMessage, so Copilot Studio agents expose the same metadata
surface as other AIAgent implementations. Streaming sets the finish reason on
the terminal update while still emitting already-received content if the source
faults. Add unit tests covering the metadata mapping.

* fix: add Async suffix to async test methods (IDE1006)
2026-07-20 21:38:24 +00:00
Marco Minerva 3ab2630243 .NET: Refactor Workflows MessageMerger to preserve message order and structure (#6826)
* Refactor MessageMerger to preserve message order

Refactored MessageMerger to delegate update grouping and merging to M.E.AI, preserving the correct order and structure of assistant messages, especially for reasoning content without message IDs. Removed per-message bucketing and CreatedAt-based sorting. Added tests to verify message order and correct merging of reasoning and text updates.

* Set CreatedAt from merged responses preservation of original message timestamps during merging.

* Set merged message CreatedAt to current UTC time

Removed logic for tracking unique creation times and now always assign DateTimeOffset.UtcNow to the merged response's CreatedAt property. This simplifies timestamp handling during message merging.

* Refactor MessageMerger id-less folding logic

Refactored MessageMerger to fold identifierless reasoning segments into the following id'd message at the flattened-message level, ensuring correct merging across response buckets (fixes #6329). Updated ComputeMerged to merge id-less messages with the next message of the same role. Removed redundant per-bucket folding logic. Added unit tests to verify correct folding behavior and role matching.

* Remove unused property

 Removed the unused Role property from MessageMergeState for code cleanliness.

* Refactor MessageMerger to iterate backward for merging

Changed MessageMerger to iterate messages in reverse order, ensuring all consecutive messages without IDs preceding a message with an ID are merged correctly. Updated merging logic, index handling, and comments to reflect this new approach.

* Update code comment to better reflect its behavior.

---------

Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
2026-07-17 17:10:14 +00:00
ssccinng d5f2c77b35 .NET: Honor terminal workflow outputs in Workflow.AsAIAgent responses (#6212)
* Fix workflow agent terminal output responses

* Address workflow agent response review feedback

---------

Co-authored-by: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com>
2026-07-17 15:36:26 +00:00
Eduard van Valkenburg 5282c158aa .NET: Fix LocalCodeAct validation and package checks (#7138)
* Fix LocalCodeAct validation and package checks

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: aecf332f-b940-41a7-ac3a-6fbbe9892141

* Address LocalCodeAct alias review feedback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: aecf332f-b940-41a7-ac3a-6fbbe9892141
2026-07-16 15:17:52 +00:00
feiyun0112 dde7635760 .NET: [Feature]: .NET Improve ChatClientAgentSession constructor (#7142)
* .NET: [Feature]: .NET Improve ChatClientAgentSession constructor

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* test: make deserialize test actually reproduce issue #7109

VerifyDeserializeWithWhenWritingNullOptions passed against both the old
and the fixed constructor, so it did not guard against the regression.

The bug only reproduces when required constructor parameters are respected
(the issue uses RespectRequiredConstructorParametersDefault=true). With
WhenWritingNull a null conversationId is omitted from the JSON, and STJ then
throws 'missing required properties including: conversationId' because the
constructor parameter had no default value.

Adding RespectRequiredConstructorParameters = true to the test options makes
the test red against the parameter-without-default constructor and green with
the default-valued constructor parameters, so it now protects the fix.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com>
2026-07-16 15:06:37 +00:00
King Star 85c00fc55b .NET: preserve HeadTailBuffer UTF-8 order (#7128)
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
2026-07-16 10:03:43 +00:00
Peter Ibekwe 05834b56e3 Fix message ordering in workflow-hosted agents (#7123) 2026-07-15 19:40:47 +00:00
westey b3f2e53923 .NET: [BREAKING] Graduate ToolApprovalAgent and add ToolAutoApprovalRuleContext (#7107)
* Graduate ToolApprovalAgent and introduce tool auto approval context

* Address PR comments
2026-07-15 09:21:12 +00:00
Rince Yuan 47cd0a508d docs/.NET: fix typos in XML doc comments, ADR docs, and test comments (#7085)
- Fix double period in AnthropicClientExtensions.cs XML param docs (lines 23, 77)
- Fix double period in IScopedContentProcessor.cs XML param doc (line 20)
- Fix 'similar the the' -> 'similar to the' in ADR 0009 (line 1092)
- Fix 'reponse' -> 'response' in ADR 0001 (line 142)
- Fix 'retreive' -> 'retrieve' in ChatClientAgentTests.cs (line 467)
- Remove leftover template placeholder from ADR 0001 and 0006 frontmatter

Co-authored-by: j-zhangyiyuan <j-zhangyiyuan@microsoft.com>
Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
Co-authored-by: Giles Odigwe <79032838+giles17@users.noreply.github.com>
2026-07-14 17:06:46 +00:00
westey d93fc2dd74 .NET: [BREAKING] Harness: Switch FileAccess to opt-in (#7093)
* Switch FileAcessProvider on Harness to opt-in

* Address PR comment

---------

Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
2026-07-14 07:08:33 +00:00
Nick Brady 54617557e6 Update Foundry branding (#6999)
Replace user-facing Azure AI Foundry branding with Microsoft Foundry across docs, samples, comments, and display text while preserving technical identifiers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
2026-07-14 06:44:26 +00:00
westey e57f046d8a Graduate mode and todo providers (#7052) 2026-07-13 13:47:58 +00:00
westey beb65b21a8 .NET: [BREAKING] Graduate message injection out of experimental (#7044)
* Remove experiemental flags for MessageInjection component

* Improve locking on message injection.
2026-07-13 11:26:01 +00:00
Peter Ibekwe 737042fc93 Fix workflow session bug (#7032) 2026-07-10 16:56:57 +00:00
Patrick Woo-Sam e677ccc3b1 .NET: Fix CompactionMessageIndex.IsSummaryMessage (#7042)
* Fix CompactionMessageIndex.IsSummaryMessage

* Add more robust JsonElement value checking and tests cases
2026-07-10 15:03:26 +00:00
Theo van Kraay d9c0c36379 Fix CosmosChatHistoryProvider: omit ttl when MessageTtlSeconds is null (#6992) (#7030) 2026-07-10 13:01:59 +00:00
Peter Ibekwe 3f4ffc6c2c .NET: Fix declarative InvokeAzureAgent failing on non-object JSON agent output (#7002)
* Fix declarative InvokeAzureAgent failing on non-object JSON agent output

* Fix PR comments.
2026-07-09 17:10:51 +00:00
westey 76f2c1a0c9 .NET: [BREAKING] Graduate per-service-call persistence and approval-not-required function bypassing (#6970)
* Remove experimental flags for RequirePerServiceCallChatHistoryPersistence and DisableApprovalNotRequiredFunctionBypassing

* Address PR comments

* Fix failing test
2026-07-08 09:31:33 +00:00
Evan Mattson 12b029858e Build(deps): consolidate Dependabot dependency updates (#6984)
* Consolidate Dependabot dependency updates

* Restore method assignment suppression
2026-07-08 09:09:03 +00:00
Javier Calvarro Nelson 3d17615b6e .NET: Replace MAF AG-UI abstractions with the AG-UI C# SDK abstractions (#6653)
* .NET: Replace internal AG-UI implementation with external ag-ui packages

Remove the in-tree Microsoft.Agents.AI.AGUI sources and consume the external
AG-UI .NET SDK packages (AGUI.Abstractions, AGUI.Formatting, AGUI.Protobuf,
AGUI.Client, AGUI.Server) at 0.1.0-preview instead.

- Microsoft.Agents.AI.Hosting.AGUI.AspNetCore keeps its own ASP.NET glue
  (MapAGUI / AddAGUI / SSE result) layered over the framework-agnostic
  AGUI.Server primitives (ToChatRequestContext / AsAGUIEventStreamAsync).
- Migrate call sites to the options-based AGUIChatClient constructor and recover
  the originating AG-UI input via ChatOptions.TryGetRunAgentInput.
- Multi-turn continuation flows through parentRunId + threadId on
  RawRepresentationFactory; shared state flows through RunAgentInput.State and is
  surfaced as StateSnapshotEvent raw representations.
- Update samples, hosting/unit/integration tests, and central package versions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add migration README for removed Microsoft.Agents.AI.AGUI package

Keep the package folder in place with a README explaining that the in-tree AG-UI protocol abstractions moved to the external AGUI.* NuGet packages, with a mapping of old namespaces to the new packages and a migration guide.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com>
2026-07-07 20:09:53 +00:00
westey 757a832dbf .NET: Add OpenTelemetry Chat Client to harness stack (#6961)
* Add OpenTelemetry Chat Client to harness stack

* Address PR comments
2026-07-07 14:14:26 +00:00
Tamir Dresher cc20093da1 .NET: fix: bump GitHub.Copilot.SDK to 1.0.5 to resolve strong-naming mismatch (#6949)
* fix: bump GitHub.Copilot.SDK to 1.0.5 to resolve strong-naming mismatch

SDK 1.0.5 introduced strong-naming (PublicKeyToken=cc7b13ffcd2ddd51).
The adapter was compiled against the unsigned SDK (PublicKeyToken=null),
causing CS0012 for any consumer referencing both packages.

Fixes #6948

* fix: update tests and extension for SDK 1.0.5 namespace changes

- Add 'using GitHub.Copilot;' to CopilotClientExtensions.cs
- Change extension namespace to Microsoft.Agents.AI.GitHub.Copilot
- Update test files for new SDK types and removed APIs
- Add #pragma to suppress GHCP001 experimental warnings in tests
- All 45 tests pass across net8.0, net9.0, net10.0

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* style: run dotnet format to fix linting issues

Remove unnecessary using directives (IDE0005) and fix file encoding (CHARSET).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: revert CopilotClientExtensions namespace to GitHub.Copilot

Per reviewer feedback, extension methods should live in the namespace
of the type they extend (CopilotClient). This follows .NET team guidance.
The original namespace was GitHub.Copilot.SDK which was renamed to
GitHub.Copilot in SDK 1.0.5.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* refactor: narrow tools parameter from AITool to AIFunctionDeclaration

Since SessionConfig.Tools only accepts AIFunctionDeclaration, change the
constructor and extension method parameters to accept IList<AIFunctionDeclaration>
instead of the more general IList<AITool>. This makes the API honest about what
it actually uses and avoids silently discarding non-AIFunctionDeclaration tools.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: sync Directory.Packages.props with upstream main

Take upstream's package versions (including MessagePack 3.1.7 pin
that fixes NU1902/NU1903 vulnerability warnings) while keeping
GitHub.Copilot.SDK at 1.0.5 which is the purpose of this PR.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Tamir Dresher <tamirdresher@users.noreply.github.com>
Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-07 14:09:28 +00:00
Tao Chen 5ac5038545 .NET: Add defense-in-depth for MCP cross origin request (#6871)
* Add defense-in-depth for MCP cross origin request

* Address comments
2026-07-06 17:37:36 +00:00
Roger Barreto c09408cbd6 .NET: Fix flaky OpenTelemetryAgentTests via thread-safe activity collector (#6935)
* .NET: Fix flaky OpenTelemetryAgentTests via thread-safe activity collector

The Ctor_NullOrWhitespaceSourceName test subscribed a process-global TracerProvider to the shared default source Experimental.Microsoft.Agents.AI and exported into a plain List<Activity>. That source is also used by CompactionTelemetry, and xUnit runs the Compaction test classes in parallel, so a compaction span could be appended from another thread mid-assertion, throwing 'Collection was modified'.

Add a thread-safe ConcurrentActivityList collector (locked Add plus snapshot enumeration) for all InMemoryExporter collectors in the file, and scope the shared-source test to its own invoke_agent TraceId after ForceFlush so parallel compaction spans cannot affect the count or source-name checks.

* .NET: Assert ForceFlush result in OpenTelemetryAgentTests default-source test

Assert the boolean returned by TracerProvider.ForceFlush(timeout) so a flush timeout surfaces as a clear test failure instead of silently snapshotting incomplete activities.
2026-07-06 16:11:11 +00:00
westey ccba1fbbef .NET: [BREAKING] Align ShellPolicy allow/deny semantics with Python (#6906)
* Align dotnet shell policy with python implementation to support deny if not allowed semantics.

* Address PR comments.

* Address PR comments
2026-07-03 18:09:35 +00:00
Roger Barreto 2c7aadce4e .NET: Validate Foundry toolbox name is a single path segment before building the proxy URL (#6890)
* Validate Foundry toolbox name is a single path segment before building the proxy URL

Reject toolbox name/identifier inputs that carry path separators or relative-path segments (including their percent-encoded forms) before they are interpolated into the toolbox MCP proxy request URL, so a caller-influenced marker cannot alter the request target. Validation runs both at per-request marker resolution and at the shared open choke point, and is covered by red-to-green unit tests.

* Reject residual percent-encoding in toolbox name validation

After the bounded percent-decode loop, also reject a name that still contains a percent sign, so encoding nested deeper than the decode cap cannot survive validation. Dispose the service via await using in the rejection test. Adds a deeply-encoded coverage case.

* Validate toolbox name by request-target effect instead of a character list

Replace the character/decoding checks with an effect-based check: build the proxy URL and confirm the name resolves to a single, intact path segment between 'toolboxes' and 'mcp' with the scheme, authority, path shape, and fragment unchanged, and that the segment round-trips back to the name. This forgives characters that stay inside the segment (for example ':' , '@' , parentheses) while still rejecting names that would move the request target, including '?' and '#' and their percent-encoded forms. Adds coverage for the delimiter cases and for the newly-allowed names.
2026-07-03 17:00:26 +00:00
Roger Barreto 8be157e2a1 Return 404 for a response created against a nonexistent conversation (#6892)
When a create-response request references a conversation id that does not
exist, validate its existence up front and return a clean not-found error
mapped to HTTP 404, consistent with the Conversations API, instead of failing
mid-execution and surfacing a generic server error.

Centralize the responses validation error codes and their HTTP status mapping
in a single ResponseErrorCodes type so handlers translate a code to a 404 or
400 without ad-hoc string comparisons. Add unit and HTTP integration tests.
2026-07-03 17:00:00 +00:00
SergeyMenshykh 331d17c5a1 .NET: fix: Require explicit TokenCredential in AddFoundryToolboxes (#6877)
* fix: require explicit TokenCredential in AddFoundryToolboxes

The AddFoundryToolboxes extension methods now require callers to
pass a TokenCredential explicitly rather than relying on an
internally-created default credential. This makes the credential
choice intentional and avoids non-deterministic credential probing
in production environments.

Breaking change (experimental API):
- AddFoundryToolboxes(IServiceCollection, params string[]) becomes
  AddFoundryToolboxes(IServiceCollection, TokenCredential, params string[])
- AddFoundryToolboxes(IServiceCollection, Action?, params string[]) becomes
  AddFoundryToolboxes(IServiceCollection, TokenCredential, Action?, params string[])
- Azure.Identity package dependency removed from Foundry.Hosting library.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: simplify redundant generic type argument (IDE0001)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: avoid duplicate FoundryToolboxService registration

Inject the AddFoundryToolboxes credential directly into the
FoundryToolboxService factory and fail early if the service was
already registered. This avoids registering TokenCredential in the
host DI container while preserving a single toolbox service instance
for both request handling and hosted startup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-02 15:44:56 +00:00
westey 48436f8ab6 .NET: Make default-approval harness features configurable + customizable shell tool (#6880)
* Dotnet: Allow devs to opt-out of file-access approvals

* Address PR comments
2026-07-02 14:57:59 +00:00
Roger Barreto 551b44f04f .NET: Bump Azure.AI.Projects to 2.1.0-beta.4 (#6795)
* .NET: Bump Azure.AI.Projects to 2.1.0-alpha.20260629.1

Bumps Azure.AI.Projects beta.3 to alpha.20260629.1 and aligns transitive deps (System.ClientModel 1.14.0, Azure.Core 1.59.0, Msal 4.84.2). Adapts to renamed AgentSessionFiles APIs (Upload/GetAll/Delete, scoped GetAgentSessionFiles, SizeInBytes), AgentToolboxes (CreateVersion/Delete), and strongly typed toolbox tools (WebSearchToolboxTool, MCPToolboxTool). Adds azure-sdk public dev feed for prerelease restore.

* Use positional arg for AgentSessionFiles.DeleteAsync cleanup

* Move to Azure.AI.Projects 2.1.0-beta.4 (released beta)

Swaps the alpha daily build for the published 2.1.0-beta.4. Drops the azure-sdk public dev feed since beta.4 and its deps are on nuget.org. Beta.4 requires Azure.Core 1.60.0, which cascades the 10.0.8 servicing packages (Microsoft.Bcl.AsyncInterfaces, System.Diagnostics.DiagnosticSource, System.Text.Json, System.Threading.Channels, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.Logging.Abstractions) to 10.0.9.

* Reconcile Azure.Core 1.60.0 bump with merged main

Reverts the over-eager System.Threading.Channels 10.0.9 bump back to 10.0.8 (it was not part of the Azure.Core 1.60.0 cascade and caused a net472 MSB3277 conflict against the 10.0.8 that Microsoft.Extensions.AI pulls). Drops the now-obsolete Azure.Core VersionOverride=1.59.0 in HostedWorkflowHandoff (added on main to satisfy AgentServer while the central pin was lower); the central pin is now 1.60.0 which already satisfies the >=1.59.0 floor, and the override was downgrading this project below sibling projects (CS1705).
2026-07-02 14:40:03 +00:00
Roger Barreto 62f0024707 .NET: Foundry Hosting gracefully tolerates lacking user identity when run locally (#6870)
* .NET: Make Foundry Hosting resilient to missing user identity in local runs

AgentFrameworkResponseHandler threw InvalidOperationException (surfaced as a
500 on every request) when the isolation-key provider returned null, which
always happens locally because the platform x-agent-user-id header is absent.
Running a hosted image outside Foundry therefore failed out of the box.

The handler now branches on FoundryEnvironment.IsHosted: hosted stays strict
(null identity is still a hard error), but non-hosted (local docker run /
dotnet run) tolerates a null identity - per-user isolation is simply not
triggered, the request proceeds with userId null (no partition), and no
hosted context is stamped or validated.

Because local runs no longer need a fallback, the sample-side
DevTemporaryLocalUserIdProvider and AddDevTemporaryLocalContributorSetup are
removed from Hosted_Shared_Contributor_Setup and all sample Program.cs files.
To simulate distinct users locally, send an x-agent-user-id request header;
the default provider reads it exactly as it reads the platform-injected value.
The Memory sample smoke script now drives alice/bob against one container via
that header. AGENT_NAME defaults added to Hosted-ChatClientAgent and
Hosted-MemoryAgent so a hosted deploy (where AGENT_* is a reserved env var)
does not crash at startup.

Updates the two affected unit tests to assert the local-success path and
amends ADR 0031.

* Address review: correct isolation-guarantee and Memory-sample local docs

- AgentFrameworkResponseHandler: note the null/local case is unscoped/shared,
  not fully partitioned per user.
- HostedSessionIsolationKeyProvider XML docs: phrase the non-null UserId rule as
  a constraint on the returned-context case, since null is now allowed locally.
- Hosted-MemoryAgent: the PerUser() memory scope requires a resolved user, so a
  local run needs an x-agent-user-id header; corrected the Program.cs comment
  and README (removed the inaccurate "shared bucket locally" claim).
- Test: assert absence of any u-* per-user directory via a wildcard search
  rather than checking for a literal "u-" directory.
2026-07-02 09:32:22 +00:00
westey 300dfa7e36 .NET: [BREAKING] Refactor OpenAI Hosting OptionsMapping to disallow passing options by default (#6855)
* Refactor OptionsMapping to disallow passing options by default

* Address PR comments

* Address PR comment
2026-07-01 15:05:53 +00:00