main
1231 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a2a8635417 |
.NET: Stabilize Foundry recovery tests (#7817)
* .NET: Fix Foundry recovery test synchronization * .NET: Observe completed recovery checkpoints in test * .NET: Stabilize Foundry crash recovery integration test |
||
|
|
84ac8973ff |
Bump AWSSDK.Extensions.Bedrock.MEAI from 4.0.6.10 to 4.0.101.8 (#7829)
--- updated-dependencies: - dependency-name: AWSSDK.Extensions.Bedrock.MEAI dependency-version: 4.0.101.8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
d9d3fb6252 | .NET: Update version for 1.19.0 release (#7814) | ||
|
|
abe1f629a2 |
.NET: Add support for Resilient long-running and Steerable Foundry Hosted Agents (#7370)
* feat(foundry): add resilient background hosting Enable AgentServer recovery and steering through FoundryResponsesOptions. Persist AgentSession snapshots during long background turns while workflow checkpointing remains owned by the workflow runtime. * feat(foundry): complete resilient and steerable hosting * fix(foundry): address resilience review feedback * feat(foundry): align resilient workflow checkpoints * docs(foundry): update resilience review guidance |
||
|
|
ede605d868 |
.NET: Bump AgentMemory from 1.3.0 to 1.4.1 (#7639)
* Bump AgentMemory from 1.3.0 to 1.4.1 --- updated-dependencies: - dependency-name: AgentMemory dependency-version: 1.4.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> |
||
|
|
eccf47154f |
.NET: Fix ReasoningSummary passthrough in GitHub Copilot resume config (#6441)
* .NET: Fix ReasoningSummary passthrough in GitHub Copilot resume config CopyResumeSessionConfig hand-copies a subset of SessionConfigBase into a new ResumeSessionConfig instead of using Clone(). It was missing ReasoningSummary, so callers that set SessionConfig.ReasoningSummary got readable extended-thinking summaries on the first turn but had it silently dropped on every resumed turn. ContextTier (a sibling model/context knob passed alongside ReasoningEffort/ReasoningSummary) was missing too. Both are now copied, mirroring ReasoningEffort. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * .NET: Assert ReasoningSummary/ContextTier defaults in null-source resume test Addresses PR review: the null-source CopyResumeSessionConfig test now also asserts ReasoningSummary and ContextTier default to null, locking the intended default behavior of the newly copied properties. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> |
||
|
|
8f68f6be5d |
Bump Anthropic from 12.35.1 to 12.42.0 (#7778)
* Bump Anthropic from 12.35.1 to 12.42.0 --- updated-dependencies: - dependency-name: Anthropic dependency-version: 12.42.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update Anthropic test clients for SDK interfaces Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> |
||
|
|
43b3ce6027 |
.NET: Add feature-usage bitmask (#7709)
* Add feature-usage User-Agent telemetr * Removed static keyword from irrelevant methods. * Update method names and fix CI test issue. * Revert irrelevant changes. * Address PR comments. * Fix CI issue from merge conflict resolution. |
||
|
|
96560bbf65 |
.NET: [BREAKING] Migrate MCP long-running task support to the 2026-07-28 Tasks extension (#7774)
* Migrate MCP long-running task support to the 2026-07-28 Tasks extension * Address PR comments. * Address PR comments. * Address PR comments |
||
|
|
ab0f7d5d08 |
.NET: Persist hosted agent state in Foundry (#7649)
* Point the AgentServer packages at the local preview drop The durable state-store API this branch is built on ships in Core beta.28, which is not on nuget.org yet. The local feed is a stopgap for developing against it and must be removed before this branch ships. * Keep hosted agent state on the platform instead of the container disk A hosted agent kept its sessions, and a hosted workflow its checkpoints, in files under the container's own directory. That state is lost when the container is replaced and cannot be read by another instance of the same agent, so a conversation could not survive a restart or be served by more than one instance. Both now go to the Foundry durable state store when the process runs in a Foundry container, and stay on disk everywhere else: - FoundryAgentSessionStore holds the agent sessions, partitioned by agent, conversation and end user. - FoundryJsonCheckpointStore holds the workflow checkpoints, one item per checkpoint plus a per-session index that keeps them in commit order. Retrieving a checkpoint deletes the rest of that session's checkpoints, which is the only point at which nothing can still reach them, and is what stops the index growing past the size the platform accepts for one item. A workflow agent is redirected to that checkpoint store when it is resolved for a request, so nothing changes in how a container registers one. An agent built with a checkpoint manager of its own is left alone and reported by the new foundry-workflow-checkpointing readiness check, because its state would go somewhere hosting does not manage. Workflow agents are recognised through a new WorkflowAgentMetadata returned by GetService, which still finds them behind middleware. * Keep the readiness probe from running the agent's providers The stored-output probe ran the registered agent with its chat client replaced, which still set the agent's chat history provider and context providers running. Those are the parts most likely to reach outside the container and to write state, so every readiness probe could make external calls and add its own empty turn to real conversations. The probe now runs a stand-in built from the agent's own options with both kinds of provider dropped. It keeps what decides the setting, the chat options and the raw request factory, and cannot see a decorator wrapped around the agent, which is accepted for a readiness check. * build: bump AgentServer preview packages Core beta.29 adds the shared local state-store fallback used by hosted sessions and workflow checkpoints. Align its Azure Core and System package dependencies to avoid assembly and downgrade conflicts. * feat(foundry): use AgentServer state fallback Use FoundryStateStore for sessions and workflow checkpoints in every environment. Core beta.29 selects Foundry Storage when hosted and a file-backed local store otherwise, so local runs exercise the production storage shape without requiring Azure credentials. Give the hosted workflow sample stable inner-agent identities so its checkpoints remain compatible after container replacement. * fix(hosting): harden durable state storage Use published AgentServer packages so CI no longer depends on a local package source. * build(hosting): scope AgentServer versions Keep public package versions on their consumers so unrelated projects retain the central versions from main. * build(hosting): use public AgentServer packages Remove project overrides and keep package selection in the central catalog now that the required public releases are available. * fix(hosting): preserve durable state identity Keep keyed and default aliases on one session partition. Reject unstable unnamed direct-store usage and preserve live checkpoint branches during pruning. * refactor(hosting): centralize hosted metadata Carry storage identity through a hosting-specific agent wrapper, keep unknown middleware non-blocking at readiness, and align StateStore constructor parameter order. * refactor(hosting): move session identity into store * docs(hosting): explain session identity resolution * fix(hosting): preserve protocol mismatch status Reject unsupported protocol requests before AgentServer wraps handler failures in ResilientTaskException and converts the intended 501 response into a generic 500. |
||
|
|
e6617c407a |
.NET: Add Azure Blob Storage session persistence (#1893)
* setup azurestorage proj * setup for azure blob as agentthreadstore * add azurite as dependency for dotnet tests * use services * rollback * azurite as a step * move and rename * renames / fixes * rename to unit tests * copilot changes * .NET: Modernize Azure Blob session storage Copilot-Session: 35e63850-1a85-4f7c-ac80-2274534c13b5 * .NET: Test hosted Blob session persistence Copilot-Session: 35e63850-1a85-4f7c-ac80-2274534c13b5 * .NET: Address Azure Blob storage review feedback Copilot-Session: 35e63850-1a85-4f7c-ac80-2274534c13b5 * .NET: Use default test target frameworks Copilot-Session: 35e63850-1a85-4f7c-ac80-2274534c13b5 --------- Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Copilot-Session: 35e63850-1a85-4f7c-ac80-2274534c13b5 |
||
|
|
cabb21a292 |
.NET: Clarify compaction provider and chat reducer choices (#7678)
* Document compaction provider and reducer choices * Clarify chat history provider example --------- Co-authored-by: Ravi Kiran Pagidi <236139898+ravikiranpagidi@users.noreply.github.com> |
||
|
|
f666102d0c |
Python: Harness blog part4 samples (#7698)
* Add harness blog post part 4 samples. * Add harness sample fixes for python * Point FileMemoryStore to home for hosted agents. * Python sample fixes for toolbox Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3a5efc79-5c78-40b8-a1c5-c0f84e0795e1 * Address PR comments * Python blog sample fixes * Address PR comments * Fix formatting --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3a5efc79-5c78-40b8-a1c5-c0f84e0795e1 |
||
|
|
d29e7be7fd |
.NET: Fix A2A streaming artifact updates (#7722)
* .NET: Fix A2A streaming artifact updates Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9 * Flush buffered A2A artifacts on stream failure Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9 * Aggregate A2A message streams incrementally Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9 * Fix duplicate A2A message declaration Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9 --------- Co-authored-by: SergeyMenshykh <SergeMenshikh@outlook.com> Copilot-Session: d07945ad-4b76-48da-a499-a915c076cff9 |
||
|
|
e2938f4531 |
.NET: Remove AGUI history special cases (#7741)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> |
||
|
|
b1377fad52 |
.NET: Suppress Swagger UI CodeQL alert in sample (#7764)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1b565023-c86e-496f-a1a1-be59b4d89cb7 |
||
|
|
064751c5f3 |
.NET: Upgrade AG-UI SDK packages to 0.0.5 (#7742)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 425c405b-1fd3-4ba6-b332-a195598374b4 |
||
|
|
10bf8d7d9e |
.NET: agent-hooks interception contract as a first-class experimental feature (#7564)
* feat(dotnet): agent-hooks interception contract as an experimental package Add Microsoft.Agents.AI.AgentHooks, implementing the AGENT-HOOKS-0.1 control contract on the framework's native decorator seams, mirroring the merged Python feature (#7515) in .NET idiom: - One public factory (CreateAIAgentWithAgentHooks, per-run and host-owned-session overloads) composes agent, chat and function seams as one indivisible unit; the seam decorators are internal, so partial installs are impossible by construction. - All eight interception points: input/output at the agent seam, pre/post_model_call below the function-invocation loop (every model service call bracketed individually), pre/post_tool_call via the function-invocation middleware seam, agent_startup/agent_shutdown bracketing each run. - Fail-closed enforcement throughout: transforms write back into the native messages/arguments/results or throw; rich content is preserved as AIContent objects; interceptor crashes surface as host_error denies; enforcement-layer failures halt the run through FunctionInvocationContext.Terminate (the loop's only loud escape). - Streaming is fully buffered per spec buffered_output semantics: a deny releases zero updates; transformed responses re-derive the released updates so egress never diverges from verdicted content. - Verdict-before-durability: end-of-run history and context-provider writes defer behind the output verdict via gating provider wrappers (flushed post-transform with verdicted-message substitution for streams, dropped on deny); per-service-call persistence sits above the chat seam and is covered by its own post_model_call verdict; per-run history-provider overrides in run options are wrapped too; nested guarded sub-agents persist inline at their own boundaries. - Opt-in dependency: ResponsibleAI.AgentHooks 0.1.0-alpha.4 (bundles native runtimes) referenced only by the new package; no existing framework source is modified. - 58 tests: deny-before-execution and transform write-back per seam, rich-content preservation, streaming ordering with zero egress on deny, error bracketing, concurrency isolation, host-owned sessions, evaluate_only, approval-seam lift, persistence gating, misuse fail-closed paths, and codec units. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(dotnet): close structural bypasses at the ChatClientAgent boundary Address both reviewers' probe-confirmed findings; the runtime enforcement held everywhere, every fix is at the structural boundary: - Gate the implicit default ChatHistoryProvider: with no provider configured, ChatClientAgent creates an InMemoryChatHistoryProvider the factory never saw, so denied output became durable session history and replayed to the model on the zero-config path (both stream modes). The factory now materializes and gates the default, setting the history-conflict flags to mimic implicit-default semantics for service-managed-history agents. - Wrap per-run provider overrides on BOTH dictionaries: base AgentRunOptions.AdditionalProperties is merged into the chat options with precedence, so a base-level override bypassed (and displaced) the wrapped ChatOptions-level entry. Plain AgentRunOptions is covered too, and the wrap is copy-on-write — the caller's options and dictionaries are never mutated. - Reject per-run ChatClientFactory on guarded agents (fail closed): it would replace the guarded chat pipeline and the tool-wrapping stage riding it, silently removing the chat and tool seams. - Reject a supplied client already containing a FunctionInvokingChatClient: it would execute tools below the chat seam, before any post_model_call verdict and outside the tool seam. - Run wire projections inside the guarded blocks at the chat and function seams: a poisoned value whose serialization throws now fails the run closed (function seam: host_error halt; chat seam: gated persistence refused before the failure propagates). - Suppress provider failure notifications once a run-level deny or halt stands, so the denied turn's request messages never reach provider code. - Document the deferred-OpenTelemetry observer channel (request-side spans capture pre-transform content under sensitive-data telemetry). - Rename the factory to AsAIAgentWithAgentHooks per repo convention. 10 new boundary regression tests mined from the review probes (default-provider durability in both stream modes with session-replay assertions, both override dictionaries incl. the displacement shape, plain-run-options override, copy-on-write, factory and supplied-FICC rejections, poisoned-projection fail-closed); 68 total, all green. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(dotnet): redact denied-run failure notifications for both provider kinds The deny/halt handling of provider failure notifications only covered the chat-history wrapper; a context provider still received the denied turn's request messages on its failure notification. Both gating wrappers now REDACT instead of suppress: the notification is forwarded with empty request messages and the original exception, preserving the documented failure-cleanup contract (providers releasing per-run resources on the failure signal keep working) while the denied turn's request messages never reach provider code. Regression tests assert both provider kinds receive the redacted notification (zero request messages) on a denied run and full notifications on ordinary, verdict-free failures. 70 tests total. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(dotnet): address Copilot review on the agent-hooks PR - Run options: always clone chat-typed run options (the framework's function-invocation middleware chains its per-run factory onto the instance it receives, so forwarding the caller's instance leaked that factory into it — reuse tripped the rejection, concurrent reuse raced), and recognize the framework middleware's own factory as legitimate: it wraps the guarded pipeline (tool rewriting), so outer function-middleware composition now works, while its chained factories are walked so a caller-supplied factory cannot ride in unnoticed. - Streaming: re-derived (transformed) updates preserve the response's ContinuationToken (ToAgentResponseUpdates does not project it), so transformed background streaming responses remain resumable; a message-less response releases a metadata-only update carrying it. - Codecs: transformed tool calls are validated for complete shape and uniqueness before reconciliation (non-empty string id and name, object-valued args, distinct ids) — malformed shapes fail closed instead of becoming invalid native calls. Deliberately stricter than the merged Python codec, which coerces added-call shapes. - Role defaulting in message write-backs is confirmed exact Python parity (user/assistant defaults per the merged codecs) and is now locked by tests rather than changed. - ADR 0035 records the seam order, persistence gating, fail-closed behavior, alternatives and known limitations. 14 new tests (options reuse, outer function-middleware composition, smuggled-factory rejection, continuation-token preservation, 8 malformed tool-call shapes, 2 role-default parity); 84 total, green. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * feat(dotnet): project the per-call tool set on pre_model_call emissions Context providers can register additional tools during run preparation, after agent_startup has been emitted, so tools_registered is inherently a run-start snapshot and can be a partial view of the tools eventually offered to the model. - Emit the spec's optional pre_model_call tools field ({name, description?}) from the per-call effective ChatOptions.Tools — the completed set for each call, including provider-added tools. - Document tools_registered as the run-start snapshot on the agent seam (dynamic registrations surface per call and are bracketed by the tool seam when invoked). - Probe-confirm enforcement completeness for provider-added tools: they flow through the guarded pipeline's tool-wrapping stage, emit pre/post_tool_call, and a pre_tool_call deny blocks their invocation exactly like constructor-registered tools. Two new tests (bracketing + audit projections, deny-blocks); 86 total, green. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * refactor(dotnet): one artifact per file; rewrap foreign gating wrappers Per review: - Split the three multi-type files (AgentHooksGatingProviders.cs, AgentHooksRunState.cs, AgentHooksWireCodecs.cs) into one type per file, file name matching the type name, per repo convention. No behavior changes; namespaces and access levels unchanged. - Close a validation asymmetry at the provider gate: the per-run override wrap skipped any gating wrapper, including one owned by a DIFFERENT agent-hooks installation — which runs inline under this run's state (its own gate is not covering here), so a denied run's history could persist straight through it. Overrides are now re-wrapped unless the wrapper belongs to this installation (reference-equal configuration). The provider seam's inline behavior for foreign/absent state is otherwise deliberate: inline is the safe direction there (content of unguarded or differently guarded runs is covered by its own verdicts or none), and throwing would break the legitimate double-wrap flush flow. One new regression test (foreign wrapper as per-run override on a denied run persists nothing); 87 total, green. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * refactor(dotnet): accept params IEnumerable for agent-hooks interceptors Per review: the constructor only iterates the interceptors, so widen the parameter from params IInterceptor[] to the C# 13 params IEnumerable<IInterceptor>. The sequence is enumerated exactly once into the internal registration list (sequences may be single-enumeration); per-item null validation and the factory's at-least-one-interceptor check are unchanged, and an explicit null sequence now throws ArgumentNullException. Params-form call sites are source-compatible. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * build(dotnet): ship Microsoft.Agents.AI.AgentHooks as a preview package Per maintainer review on the PR: - Add the project to agent-framework-release.slnf and import the shared packaging props so the package ships. Version follows the repo default for unmarked packages (preview suffix), matching the package's [Experimental] surface and alpha upstream dependency: 1.17.0-preview.<date>.1. - Package metadata: sibling-style title, fuller description, tags; shared icon and NUGET.md readme via the packaging props. Verified dotnet pack locally: ResponsibleAI.AgentHooks 0.1.0-alpha.4 flows as a normal dependency and the project references become 1.17.0 package dependencies. - Update ADR 0035: shipping as preview per maintainer decision replaces the build-only-pending-maturity stance. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * build(dotnet): version the agent-hooks package as alpha Per maintainer review: the package's maturity marker follows the ResponsibleAI.AgentHooks dependency it is built on (alpha), rather than the repo's default preview suffix. Packs as 1.17.0-alpha.260804.1; ADR 0035 updated. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * refactor(dotnet): group agent-hooks internals into Core and Codecs folders Per review: only the public surface (the factory extensions and options) stays at the project root; the internal seam decorators, run state and gating providers move to Core/, and the wire projection codecs to Codecs/. Pure file moves — namespaces stay flat per the core package's folder convention (ChatClient/, Memory/); no content changes. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * docs(dotnet): clarify session scoping and name the sessionId argument Per review: - Name the AgentContextBuilder arguments at the run-state factory so the GUID reads as what it is (the per-run agent-hooks session id). - Document both branches of CreateRunState: session-scoped means the host owns the emitter/builder and the session boundaries (one session spanning runs, no agent_startup/agent_shutdown emitted by the agent); the default is one session per run with a fresh emitter, fresh sequence and isolated record trail, which is what keeps concurrent runs' emissions from interleaving. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * fix(dotnet): harden agent-hooks factory and input projection per review - Input projection returns (payload, content, role) as one typed result so the emission site never re-reads payload properties by name: the both-fields-exist invariant holds by construction. (The previous reads were fail-closed even hypothetically — JsonObject's indexer yields null, and a null content is rejected by the SDK's envelope validation — but reading back what we just produced was needlessly fragile-looking.) - Reject UseProvidedChatClientAsIs on the factory: it signals a fully custom, do-not-touch client stack, which is incompatible with a factory whose job is to decorate the supplied client and rely on the agent's default pipeline above the chat seam. Honoring it would silently change where (and whether) the seams sit. - Log swallowed agent_shutdown emission failures (logger resolved the same way the agent resolves its own: services, then the chat client, then null) so incomplete session trails are trackable; OutOfMemoryException stays unswallowed. The swallow remains correct: the run's own outcome is already propagating and the trail closure is best-effort by contract. 89th test: UseProvidedChatClientAsIs rejection. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * build(dotnet): attribute the Agent-Hooks protocol in the package identity Per review: - Title per suggestion: 'Microsoft Agent Framework - Responsible AI Agent-Hooks Protocol Support'; description names the protocol precisely (AGENT-HOOKS-0.1, maintained by the Responsible AI project at github.com/responsibleai/agent-hooks) so the package reads as protocol support, not a MAF-owned feature; tags aligned. - Drop the [Experimental] attributes: per repo convention the attribute gates unstable surface inside released packages (Harness, core), while pre-release packages (Valkey and Mcp at alpha, Mem0 and LocalCodeAct at preview) carry none — the version suffix is the maturity signal. - Drop the describing comment on the central package version entry. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> * refactor(dotnet): split agent-hooks test fixtures into Support files Per review: one type per file under Support/ (mock client, guards, recording providers, helpers), matching the src-side convention; pure mechanical split, flat namespace. Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> --------- Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com> |
||
|
|
0f583ec8a3 |
.NET: Migrate remaining Foundry hosted samples to source deployment (#7668)
* .NET: Migrate 6 hosted-agent samples to source (ZIP) deploy Extend the source (ZIP) deploy pattern established for Hosted-ChatClientAgent to Hosted-LocalTools, Hosted-Workflow-Simple, Hosted-TextRag, Hosted-Observability, Hosted-Files and Hosted-FoundryAgent. Each gains an azure.yaml (codeConfiguration/remote_build, ASPNETCORE_URLS, model env) and the canonical .agentignore, a self-contained csproj (single target, CPM opt-out, explicit published package versions, AgentFrameworkVersion), a Program.cs that drops the shared contributor scaffolding for DefaultAzureCredential, an updated .env.example and README, and drops the container-mode files (agent.yaml, agent.manifest.yaml, Dockerfile, Dockerfile.contributor). LocalTools, Workflow-Simple, TextRag, Observability and Files were verified deploying live via remote_build; Workflow-Simple returns a workflow runtime error at invoke that is unrelated to the deploy mode. * .NET: Migrate Hosted-Invocations-EchoAgent and Hosted-LocalCodeAct to source (ZIP) deploy EchoAgent (Invocations protocol) and LocalCodeAct migrated to the zip/code-deploy pattern (azure.yaml, .agentignore, self-contained csproj, README, container files removed). EchoAgent maps /readiness explicitly because the Invocations SDK does not auto-map it. Both verified live via remote_build on a Foundry project; LocalCodeAct's execute_code ran server-side (compute 21+21 -> 42). * .NET: Migrate remaining hosted-agent samples to source (ZIP) deploy Migrate Hosted-McpTools, Hosted-MemoryAgent, Hosted-AgentSkills, Hosted-AzureSearchRag, Hosted-Toolbox, Hosted-Toolbox-AuthPaths and Hosted-ToolboxMcpSkills to the zip/code-deploy pattern (azure.yaml with codeConfiguration + sample-specific env passthrough, canonical .agentignore, self-contained csproj, Program.cs dropping the shared contributor scaffolding for DefaultAzureCredential, updated .env.example and README, container files removed). Also restore the Hosted-Invocations-EchoAgent csproj filename the solution references. McpTools verified live via remote_build against the public Microsoft Learn MCP server; the memory/search/toolbox/skills samples build locally and deploy via remote_build but need their external resources (memory store, search index, toolbox connections, skills) provisioned to exercise end to end. * .NET: Migrate Hosted-Workflow-Handoff to source (ZIP) deploy Migrate the triage handoff workflow sample to the zip/code-deploy pattern (azure.yaml with codeConfiguration and Azure OpenAI env passthrough, canonical .agentignore, self-contained csproj using AgentFrameworkVersion for Foundry/Foundry.Hosting/Hosting, Program.cs dropping the shared contributor scaffolding for DefaultAzureCredential, updated .env.example and README, container files removed). Builds via remote_build; live needs an Azure OpenAI resource (AZURE_OPENAI_ENDPOINT/AZURE_OPENAI_DEPLOYMENT). * .NET: Copy Hosted-AgentSkills skills/ into build output The startup provisioning helper reads SKILL.md files from AppContext.BaseDirectory/skills, but the project did not copy the skills/ folder to the build/publish output, so at runtime the source directory did not exist and provisioning was silently skipped. Add a Content include (PreserveNewest), matching the resources/ pattern already used by Hosted-Files. * .NET: Suppress OPENAI001 in Hosted-Workflow-Handoff for standalone ZIP build The repo-wide Directory.Build.props suppresses OPENAI001, but that file does not travel in the code/ZIP deploy package. The standalone dotnet publish the Foundry code deploy runs then fails with error OPENAI001 on the experimental GetResponsesClient().AsIChatClient() call. Add OPENAI001 to the project NoWarn so the sample builds in the code-deploy pipeline, matching SimpleAgent.csproj. * .NET: Document live-verified idiosyncrasies in Foundry hosted sample READMEs Align every FoundryHostedAgents sample README with the documented azd flow and add the idiosyncrasies found while live-testing each sample on a Foundry project: - All samples: 'azd down' reports success but does not delete the hosted agent; document the explicit REST DELETE needed to remove it. - Hosted-Workflow-Handoff: it builds its own AzureOpenAIClient (data-plane), so the agent identity needs the 'Cognitive Services OpenAI User' role on the Azure OpenAI account. azd only grants 'Foundry User' on the project, so add a step to grant the data-plane role and explain the triage-step failure without it. - Hosted-Toolbox / Toolbox-AuthPaths / ToolboxMcpSkills: the toolbox must already exist and the agent identity must be able to read it; toolboxes with OAuth-gated tools return an oauth_consent_request and response.incomplete on first invoke. * .NET: Address Foundry hosted sample review feedback Make sample configuration reject blank azd substitutions and document every required environment value inside the scaffolded project flow. Separate the hosted endpoint name from the Foundry managed prompt-agent name, fix standalone MemoryAgent diagnostics, and complete the contributor local package feed for Hosting, LocalCodeAct, and MCP. Use azd for agent invocation and az rest for authenticated administration without exposing tokens. Add native MCP approval handling to the toolbox consent client and make its local path target the standard responses endpoint. Validated all changed samples locally, the contributor flow in PowerShell and Bash, and the supported live scenarios on the TAO cace project. * .NET: Fix advanced hosted sample project access Document and validate the Foundry User grant required by hosted version identities that access project data plane APIs. Add the Skills preview feature header and use a writable temporary directory for downloaded skills because source deployments mount the application directory read only. Update AgentSkills, MemoryAgent, FoundryAgent, and ToolboxMcpSkills deployment guides with the post deploy identity grant. All four scenarios passed live on the TAO cace project. |
||
|
|
9917bddc2b |
.NET: Update AG-UI samples for latest MAF + AG-UI SDK and align with docs (#7295)
* Simplify AG-UI Step04 human-in-the-loop sample to idiomatic pattern The Step04 sample previously wrapped both the server and client agents in custom ServerFunctionApproval*Agent middleware (~470 lines across two files) to marshal a bespoke approval protocol over AG-UI. This is no longer needed: MapAGUIServer natively emits the tool-approval interrupt when the model calls an ApprovalRequiredAIFunction, and AGUIChatClient natively transports the client's ToolApprovalResponseContent decision back to resume the run. Changes: - Server: map the ChatClientAgent directly with MapAGUIServer; remove the ServerFunctionApprovalAgent wrapper, the JsonOptions plumbing, and the ApprovalJsonContext registration. - Client: use the AGUIChatClient-backed agent directly; the existing loop already handles ToolApprovalRequestContent -> CreateResponse idiomatically. - Delete ServerFunctionApprovalServerAgent.cs and ServerFunctionApprovalClientAgent.cs. Verified end-to-end (approval request -> approve -> tool executes -> final response) against GitHub Models. Both projects build with 0 warnings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: eeb2168d-2ecc-4f8d-9830-c287072eb7e1 * Update AG-UI Step04 README to describe native approval flow The Step04 human-in-the-loop sample no longer uses the custom ServerFunctionApprovalServerAgent / ServerFunctionApprovalClientAgent wrappers. Update the README so it describes the idiomatic native flow: the server maps a plain agent with MapAGUIServer and relies on ApprovalRequiredAIFunction to raise the approval interrupt, and the client handles ToolApprovalRequestContent and replies with ToolApprovalResponseContent. * Fix AG-UI Step04 README server port to match client default The Step04 client defaults to http://localhost:5100 (and the server launchSettings also uses 5100), but the README told users to run the server on port 8888, so the client could not reach it. Align the Step04 server run command to 5100. Other steps intentionally keep 8888 because their clients default to that port. * Update AG-UI .NET samples for latest MAF + AG-UI SDK and align with docs - Bump AGUI.* packages 0.0.3 to 0.0.4 (Directory.Packages.props) - Step01/02/03: drop AddHttpClient().AddLogging() server noise and simplify the client run-started output to match the getting-started doc (no thread plumbing) - Step04 (HITL): remove HTTP body logging and MEAI001 pragmas, give the approval tool an explicit name, and align the resume decision message with the doc - Step05 (state): replace the custom SharedStateAgent/StatefulAgent DataContent pattern (dropped by released AGUI.Server) with declarative AGUIStreamOptions.MapResultAsStateSnapshot plus a thin RecipeStateAgent that reads RunAgentInput.State, and align the Recipe models with the docs - Refresh README to the shipped API (MapAGUIServer, ApprovalRequiredAIFunction, declarative state) Verified: all 10 sample projects build; Step04 approval/resume and Step05 state snapshot round-trip run end-to-end against GitHub Models. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: eeb2168d-2ecc-4f8d-9830-c287072eb7e1 * Name the Step02 backend tool search_restaurants to match the docs Give the SearchRestaurants tool an explicit "search_restaurants" name so the client displays an accurate tool name (not a compiler-mangled local-function name) and stays aligned with the backend-tool-rendering doc. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: eeb2168d-2ecc-4f8d-9830-c287072eb7e1 * Add UTF-8 BOM to Step05 sample files to satisfy check-format The check-format CI job enforces the repository's utf-8-bom charset rule via dotnet format. The Step05 files added in this PR were saved without a BOM. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: eeb2168d-2ecc-4f8d-9830-c287072eb7e1 * Fix AG-UI sample conversation history Let AgentSession own prior messages so clients send only each new turn, and give the frontend location tool a stable protocol name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Copilot-Session: eeb2168d-2ecc-4f8d-9830-c287072eb7e1 |
||
|
|
1f738cdeb7 |
.NET: Python: Clarify PR review comment resolution (#7746)
* Clarify PR review comment resolution * Sync PR review resolution guidance |
||
|
|
f330457042 |
.NET: Pass IServiceProvider to ChatClientAgent in AddAIAgent overloads (#7737)
All four AddAIAgent overloads in AgentHostingServiceCollectionExtensions created a ChatClientAgent without forwarding the IServiceProvider, so the FunctionInvokingChatClient in the agent's pipeline had no service provider and tools could not resolve their dependencies at invocation time. Fixes #4453 Co-authored-by: Max Montes Soza <max-montes@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
e33e78127f |
.NET: Fix snake_case argument names in Harness file tool descriptions (#7731)
* Initial plan * Fix snake_case argument names in Harness file tool descriptions Co-authored-by: westey-m <164392973+westey-m@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: westey-m <164392973+westey-m@users.noreply.github.com> |
||
|
|
4be584cc53 |
.NET: Add session-persisted chat client routing (#7641)
* Add RoutePersistingRoutingChatClient * Address PR comments * Address PR comments |
||
|
|
4ce2804db0 |
.NET: Fix release build analyzer failures (#7721)
Guard the hosted storage error log before evaluating the agent name and update the SDK to the servicing release containing the net9 ILLink analyzer fix. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e3a6cce8-e1e8-4cf2-9cf4-3c0c8f3ed6d8 |
||
|
|
1b45c15749 |
.NET: Update version for 1.18.0 release (#7713)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0acc90aa-5690-41e6-b546-16083fc1c8b5 |
||
|
|
6001c12cd3 |
.NET: Fix declarative workflows deep research sample (#7674)
* Fix declarative workflows deep research sample * Address PR comments |
||
|
|
c6584ffaad |
.NET: Add Cosmos chat history retrieval API (#7412)
* .NET: Add Cosmos chat history retrieval API * Clarify Cosmos message ordering semantics |
||
|
|
74808cb6c7 |
.NET: Add Foundry hosted session and user identity pass-through (#7648)
* .NET: Add Foundry session and user identity pass-through Let user agents pin hosted agent_session_id on AgentSession and send x-ms-user-identity per call for Foundry hosted agents. * .NET: Add live ITs for Foundry session and user identity Cover service-managed and admin-pinned hosted sandboxes, sticky hosted session id, and per-call x-ms-user-identity isolation with separate AgentSessions sharing one sandbox. Echo container avoids model quota for identity assertions. * .NET: Reject Foundry hosted session switch when sticky Persist sticky id in finally, clone run options before factory wrap, validate whitespace pin on CreateHostedSessionAsync, and throw on unexpected hosted session id change in the response. Docs: distinct AgentSessions per user identity may share one sandbox. * .NET: Clear nested user identity and preserve run options Always assign UserIdentityScope including null so nested runs do not inherit a parent identity. When upgrading plain AgentRunOptions, keep background, format, and additional properties on the specialized clone. * .NET: Clarify previous_response_id user binding in docs Align WithUserIdentity guidance with Foundry Learn multiplex docs: response chains are bound to the creating user even inside a shared hosted sandbox. * refactor(foundry): clarify hosted agent APIs |
||
|
|
047ec7eaff |
.NET: Allow agents to opt into concurrent tool invocation (#7650)
* .NET: allow agents to opt into concurrent tool invocation * .NET: address concurrent invocation review feedback |
||
|
|
12621e0a74 |
.NET: Fix IDE0039 by using local functions in samples (#7666)
Replace Func lambda assignments with local functions so dotnet format --verify-no-changes passes on the agent and RAG samples. |
||
|
|
6d25fb1e9c | Remove clear and package source mapping from nuget.config to allow user level config inheritance (#7646) | ||
|
|
56d13bce4e |
.NET: Add BackgroundAgentsProvider.ReleaseSessionAsync to cancel and release per-session background tasks (#7602)
* Add the abilty for the caller to release and cancel background tasks * Improve param validation * Address PR comments * Address PR comments. * Address PR comments: cancel tasks before publishing the release Set IsReleased and publish the ReleaseCompletion only after the in-flight tasks have actually been cancelled, so a failure to cancel leaves the session un-released instead of flagging it as released while its tasks are still running. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
4ca093371e |
.NET: Add Options for Hosted Agent to Allow Backend Storage (#7572)
* Let the container choose who stores a hosted turn, and say so when it is stored twice Turning storage off downstream was unconditional and silent. It is now a container choice, and a deployment that ends up storing anyway is reported instead of quietly recording the conversation in two places nothing reconciles. FoundryResponsesOptions, passed through AddFoundryResponses, carries two settings. AllowStoredOutputEnabled defaults to false, which is when hosting turns storage off for every run and checks the result. Setting it to true leaves the agent's own configuration exactly as the container built it, and nothing is checked, overridden, or refused. IncludeReasoningEncryptedContent applies while storage is off, asking for the encrypted form of the reasoning tokens so reasoning survives between turns, mirroring AsIChatClientWithStoredOutputDisabled. Two checks replace the 400 that used to refuse a session carrying a conversation id. The readiness probe runs each registered agent with its chat client swapped for one that calls nothing, so the request the agent builds on its own is visible without leaving the container, and an agent asking for its responses to be stored keeps the container out of rotation. Per request, a conversation id on the session after the run means the agent's own service kept the turn, which fails with 501 and leaves the session unsaved so later turns do not resume onto it. A misconfigured container is a server problem, not a bad request, hence 5xx. Only a confirmed "this asks to be stored" fails either check. An agent that is not a ChatClientAgent, a request shape carrying no such setting, and a run that could not be completed all pass: this package cannot tell what those would do. * Rename the stored-session flag to say what it means * Say plainly what server-side storage does to a hosted turn * Read the store gate as an allow, and align the messages The flag that decides whether the session may be saved reads as an allow at every use, while the test it comes from keeps saying what is not allowed, so neither side has to be read inside out. The wording now matches what the readiness probe says: server side storage must be off, because with it on the agent's own service records a conversation and response nothing tracks while the hosted agent records its own for the same request. The message the readiness probe raises no longer travels through a shared constant, since each check says its own thing. * Address the review comments left open on the merged PR Five points raised on #7525 were marked resolved without a code change, and the code they pointed at was still there. A hosted workflow session is now recognised by its full type name, so a session of the same short name from another namespace is not mistaken for one. The test double moves into the namespace it stands in for, otherwise it would no longer exercise the check. The per-run chat history provider is handed over on AgentRunOptions.AdditionalProperties, which ChatClientAgent copies onto the chat options with precedence, rather than being written onto the chat options here. The test that pins down who supplies the history said the agent's own provider is used, while it asserts the opposite, so it is renamed after what it checks. Reading a response back in the hosted integration tests no longer swallows every failure: only "not stored" and "not readable through this endpoint" are, so an expired token or a server fault cannot be mistaken for an absent response and pass the test. Also fills in the readiness message for the case where storing is explicitly allowed. * Address the review on #7572 Four findings, all real, all in code this branch introduced. A container that allows its own service to keep the conversation was still being handed the platform history on every turn. That service replays the earlier turns itself, so the model was getting each of them twice, which is the very thing this work exists to prevent. The history now goes in only while nothing else holds it: the first turn of such a conversation still gets it, and the service takes over from there. A turn that fails for storing downstream was announcing itself as completed first and only then failing, leaving the caller with two different answers for the same turn. The completed event is now held back until the run is wound up and the session can be read, because the id of any conversation the agent's service kept only lands there at the very end. The readiness probe replaced the chat client but left the agent's chat history provider running, so a provider backed by a database was reading and writing on every probe, and adding the probe's empty turn to a real conversation. It is stood down for that run now. The probe also treated any cancellation as the health check's own, so a timeout inside an agent could fail readiness. Only a cancellation of the health check's token is left to propagate. Fixing the completed event turned up a latent problem: the terminal event types are named the same in two namespaces this file pulls in, and the short name binds to the ones the response stream never produces, so vt is ResponseCompletedEvent was quietly always false. The three terminal types are now named explicitly. * Let the chat history provider carry the conversation The handler used to read the hosting service's record of the conversation and prepend it to the input of every run, then work out who should not get it: a resumed workflow by the name of its session type, and a container whose own service already holds the conversation. Two exceptions, a type name matched as a string, and a shape where the same turns could arrive from two directions. An agent that reads its history through a provider is now given one, seeded with that record, for the length of the run. The turns arrive the way the agent expects them rather than as fresh input, so nothing is stored back as if it had just been said, and the provider is dropped when the run ends. Only the new input is passed to the run now. Everything else supplies its own history and is left alone: an agent built with a provider keeps using it, an agent whose service keeps the conversation reads it from there, and an agent that is not a ChatClientAgent, a hosted workflow for instance, carries the conversation in its own session state and wants only the new input. The workflow session type name check is gone with it. The session is saved on every turn again. It was being withheld when the agent's own service had kept the turn, which is a decision about that service, not about the session; nothing this handler adds for a turn reaches the session anyway. * Fail a turn to skip its session, and name the store check after what it detects The session was being withheld from the store on a condition about the agent's own service rather than about the turn, and guarded by an emptiness check on a key that is never empty. A turn that is being failed now says so, and only that skips the save. A turn that ends incomplete, waiting on OAuth consent or interrupted by a shutdown, is not a failure: the caller comes back for it and needs the state built up so far, the tool approval ids among it. The session key is resolved once as a value that always exists, so both the load and the save use it without asking again whether it is there. CheckNotAllowedStoreUsage and notAllowedStoreUsageDetected now read as what they are: a check for an agent storing when it should not, and the flag saying it was seen. * Read a hosted response through the agent client, and only forgive a 404 Reading a response back tried the project-level client first and then the per-agent one, swallowing 403 as well as 404 to get past the first. The project-level client cannot see a hosted agent's responses at all, so that attempt only ever produced the 403 the catch then had to forgive, and any other 403, an authorization failure for instance, was read as "nothing is stored" and passed the test. Only the per-agent client is used now, and only a 404 counts as not stored. Verified against the service: a well-formed id it has no response for answers 404 invalid_request_error "Response '...' not found", the same id through the project-level client answers 403 session_not_accessible, and a malformed id answers 400. Everything but the 404 now surfaces. * Move the store setting next to the code that reads and writes it The two halves of the stored output concern lived in a shared helper: one that installs the factory turning storage off, and one that reads back what a request would have asked for. Each had exactly one caller, so the helper only added a hop. They now sit in the converter that builds the request and in the probe client that inspects it, and the helper keeps just the error the handler throws. The test double standing in for a hosted workflow session is also gone. It was declared inside the Workflows namespace because the handler used to recognise a resumed workflow by the full name of its session type; that comparison no longer exists, so the double only needs to not be a ChatClientAgent. * Say that the stored output setting could not be determined, which is the case being logged |
||
|
|
8a0731ad92 |
.NET: Prevent telemetry serialization failures from failing workflows (#7612)
* Prevent telemetry serialization failures from failing workflows * Address PR comments |
||
|
|
6fff2c9b1f | Fix misleading workflow protocol attribute diagnostics (#7609) | ||
|
|
0d75365331 |
.NET: Add Cosmos NoSQL vector memory sample (#7552)
* .NET: Add Cosmos NoSQL vector memory sample * Address Cosmos memory sample review feedback * Fix Cosmos NoSQL memory sample build --------- Co-authored-by: nos-redacted <nosxredacted@gmail.com> |
||
|
|
5eb3eb745e | Improve string parsing in declarative workflows (#7535) | ||
|
|
c987529df3 |
.NET: [BREAKING] Rename to AgentIsolationKeyProvider (#7567)
* Update store isolation documentation Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 824a2e29-e79c-42aa-b28e-aa6c12ec3292 * Rename store isolation key provider Rename the shared session isolation abstraction to reflect its use for both session and task stores. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 824a2e29-e79c-42aa-b28e-aa6c12ec3292 * Rename to AgentIsolationKeyProvider per review feedback Drops the `Store` qualifier and keeps an `Agent` prefix so the type is not confused with generic isolation-key abstractions from other libraries, while leaving room for future non-store isolation (memory, retrieval). - StoreIsolationKeyProvider -> AgentIsolationKeyProvider - ClaimsIdentityStoreIsolationKeyProvider(+Options) -> ClaimsIdentityAgentIsolationKeyProvider(+Options) - GetStoreIsolationKeyAsync -> GetIsolationKeyAsync - UseClaimsBasedStoreIsolation -> UseClaimsBasedAgentIsolation XML docs now state that the `Agent` prefix identifies the hosting API domain and does not mean agent instances are isolated. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 824a2e29-e79c-42aa-b28e-aa6c12ec3292 * Update hosting spec for AgentIsolationKeyProvider rename Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 824a2e29-e79c-42aa-b28e-aa6c12ec3292 --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 824a2e29-e79c-42aa-b28e-aa6c12ec3292 |
||
|
|
aaaa56bc60 |
.NET: Store executable function calls bypassed by declaration-only tool calls (#7388)
* Allow storing executable functions when mixed with non-executable * Address PR review feedback on executable function bypassing - Guard enumerator acquisition so pending bypassed calls are restored when the inner client throws synchronously, before the first MoveNextAsync. - Always surface buffered streaming updates, even when stripping empties them, so metadata such as ConversationId and ResponseId is not discarded. - Document that the decorator must sit below ApprovalResponseBindingChatClient, which drops approval responses that have no recorded request. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR comments --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
18ceb182b1 |
.NET: Give a hosted agent a single source of conversation history (#7525)
* Read hosted chat history through a provider instead of the request input The handler used to fetch the platform conversation history and prepend it to the input of every turn. For a ChatClientAgent that runs in parallel with its own chat history provider, so the conversation had two sources at once. It also had a hidden cost: platform items carry no chat-history source marker, so the agent's provider stored them again as if this turn had written them, leaving a second copy of the conversation inside the persisted session that then diverges from the platform. Make the chat history provider the single source for a ChatClientAgent: - Add FoundryChatHistoryProvider, which reads the conversation through ResponseContext.GetHistoryAsync (it already resolves previous_response_id and the conversation the request belongs to) and stores nothing, because the platform persists the response items itself. An instance is created per request because it holds that request's context, and it is passed as a run-scoped override so the host does not have to mutate the agent. - Register it only when the agent was created without a chat history provider. When one was supplied at construction, that provider owns the conversation and the platform history is not used at all. - Stop adding the platform history to the input for a ChatClientAgent, since the provider now delivers it. A workflow hosted as an agent is not a ChatClientAgent and has no provider pipeline, so it keeps receiving the platform history from the handler exactly as before. * Add regression tests for the duplicated hosted chat history Cover the three symptoms the previous handler produced, each verified to fail when the handler is reverted to fetching the platform history into the turn input: - the conversation the service already keeps was copied into the persisted agent session by the default in-memory history provider; - a custom history provider was asked to write that same conversation into its own database, because platform items carry no chat-history source marker and so look like content this turn produced; - an agent with its own provider received both that provider's history and the platform's in a single request. Also state precisely, in the provider's remarks, why nothing is written back: for a stored request the response orchestrator hands the finished response to its responses provider, which persists the input and output items that a later turn then reads back through GetHistoryAsync; for a non-stored request nothing is persisted and nothing is readable, so the request is self-contained either way. * Keep unstored turns in the session so mixed conversations stay whole A conversation can mix turns the service stores with turns it does not. History is resolved from previous_response_id or the conversation regardless of the current request's store flag, so an unstored turn still reads the stored ones back, but the service records nothing for it and a later turn would never see it again. Reading the platform history through FoundryChatHistoryProvider alone lost those turns: from the second turn onwards the handler treats the session as a resume and stops feeding history in, and the provider kept nothing of its own, so an unstored turn simply vanished from the conversation. A regression test drives three turns of one conversation, the first stored and the rest not, and without this change the model receives only [second question, ok, third question]: the stored opening turn is gone. Give the provider both halves instead of choosing one: - reading returns what the service serves, followed by the turns kept in the session, which are by definition later than anything the service recorded; - writing keeps a turn only when the service was not asked to store it, so a stored turn is never duplicated and an unstored one is never lost. The turns are held in the agent session under the provider's own state key, so they travel with the session the host already persists. * Refuse a stored turn once a conversation holds unstored ones A conversation can move between stored and unstored turns, and the unstored ones live only in the agent session. Going back to a stored turn after that would have the service record it on top of turns the service never saw, so anyone reading the conversation back from the service would find an answer with no question. Refuse it before the model is called instead of writing that gap. Cover the whole shape with a walkthrough of nine turns over one conversation and three provider instances, each with its own session: - an instance that never took an unstored turn starts from the turn the service last saved, and does not see another instance's unstored turns; - an instance that did keeps reading the saved turns and adds its own on top; - asking such an instance for a stored turn is refused, twice, while unstored turns keep working; - a turn stored from one instance does not appear for another, because it sits on a different branch of the conversation and so is not among the turns leading to what that other instance last saved. * Say plainly that kept turns belong to the session The turns the service was not asked to store are written into the agent session's state bag under this provider's own state key, and a new provider is built for every request, so nothing is held on the provider object itself. The walkthrough named its three threads after provider instances, which read as if the object carried the memory. Name them after the sessions they are, and add a test that pins the behaviour down: a turn kept through one provider object is read back by a different one given the same session, and is absent for one given another session. * Show which half of the conversation each provider decides The session decides what is kept, but the provider still decides two things: which service-side conversation is read, because it holds the request's response context, and whether the turn is kept at all, because it holds the request's store flag. Add two tests that separate those from the session: - two providers reading one session, each built for a request of a different conversation, return the same kept turn behind different served turns; - two providers writing to one session, one for a stored request and one for an unstored one, leave only the unstored turn behind. * Say why a hosted workflow keeps taking history from the handler The comment stated that a workflow hosted as an agent has no provider pipeline without saying what that means. It derives from AIAgent directly, so it never calls a ChatHistoryProvider and does not read the run options' additional properties: the provider could not reach it even if it were registered. * Ask the session store whether a turn is a resume The handler decided that a turn was resuming an existing conversation by looking for state on the session. That reading broke once the handler itself started writing to the session before the check: it records the caller's identity there, so a session created moments earlier already carried state and the very first turn of a conversation looked like a resume. Its history was then never fetched, and the agent answered knowing nothing of a conversation the service was already holding. It only showed up when hosted, because running locally there is no identity to record. Let the store answer the question instead. GetSessionAsync now returns null when nothing is stored rather than quietly handing back a new session, so a non-null result means a prior turn established this session and nothing else has to be inferred. Callers that just want a usable session can use the new GetOrCreateSessionAsync, which is written in terms of GetSessionAsync so a store overriding one gets the other for free. Both store implementations and their tests follow the plain-lookup contract: a miss creates nothing, deserializes nothing, and touches no directory. * Drop the experimental marker from an internal type FoundryChatHistoryProvider is internal, so the attribute reached no caller: the marker exists to warn people consuming the public surface. It also does not follow from the base type, which does not carry one, and most internal types in this package have none either. Removing it leaves two usings behind, so they go as well. * Stand down the agent's second-manager guard for the host's own provider An agent refuses a second history manager once the model reports a conversation id of its own, which happens as soon as the container lets the model keep the conversation. The guard is meant for an application that configured a provider by hand and would otherwise end up with two of them. Here the host is the one supplying the provider, deliberately and for every turn, so the guard was rejecting the arrangement it is hosting: the first turn failed while streaming, and every later one failed before reaching the model at all. Turn the three conflict settings off on the agent the host is serving, and let the provider decide what reaches the model. A test drives two turns of one conversation against a model that reports a conversation id and asserts both complete. * Pass a caller's request not to store on to the chat client A request asking the hosting service not to store the response was honoured there and nowhere else, so the service behind the agent's own chat client kept recording the conversation and reporting an id for it. A caller opting out of storage still ended up with a stored conversation, and the container went on continuing it. Only that direction travels. Carrying store=true across would either force storage on a container whose author turned it off on purpose or change nothing, since storing is already the default. * Hand the conversation to the agent's own provider instead of a host one The host no longer supplies a chat history provider of its own. It writes the turns the service holds into the provider the agent already created for itself, and only when that is the stock in-memory one, so an agent given a provider keeps sole control of its storage and the model receives the conversation once. A conversation the caller stops asking the service to store moves into the session state and stays there. The session's conversation id no longer names anything the service records and cannot be cleared, so the session is cloned without it on that single turn. Asking for a stored turn afterwards is refused: the service would record a turn whose predecessors it does not hold. An agent that does not read history through a provider, a hosted workflow for example, is still given its prior turns as input, now marked as chat history so no provider along the way stores them as new. * Run the agent's own request factory instead of replacing it ChatClientAgent chains a request's raw representation factory with the agent's by taking the agent's only when the request's returns null. The factory added for an unstored turn always answers, so anything the container configured on the agent's ChatOptions was silently dropped for that turn. The agent's factory is now invoked first and its result is what carries the setting. A result that is not a CreateResponseOptions belongs to some other chat client, which has no notion of storing a response, so it is handed back untouched. * Cover a stored conversation that stops being stored and asks again The refusal was only tested on a conversation the service never stored. Reaching it from a stored one goes through the turn that rebuilds the session without its conversation id, so the mark saying the conversation left the service has to survive that rebuild to be found on the next turn. * Leave the conversation to the AgentServer storage provider alone The AgentServer SDK records a hosted turn through its own storage provider, around the handler, and serves the conversation back through ResponseContext.GetHistoryAsync. Anything the container stores of its own is a second conversation that storage provider never sees and no one reconciles. The handler now takes that history as the single source and hands it to the agent as input alongside this turn's messages. The agent's own provider is replaced for the run by one holding its messages in a field, so a run that calls tools still has what its earlier calls produced while nothing survives the request. The service behind the agent's chat client is asked not to store on every turn, whatever the caller asked of the hosting service. A session that still carries a conversation id means that service is recording a second conversation regardless, so the turn is refused with a 400 rather than run against something nobody can reconcile. * Narrow the history skip to a resumed workflow Withholding the conversation from every agent that is not a ChatClientAgent assumed they all carry it in their own session. A hand-written one that keeps nothing would answer with no history from its second turn on, so the check is now on the session type a workflow runs with, which is what actually accumulates the turns. The conversation and previous response id tests went with it: the session key falls back to the partition of a freshly minted response id, which never has a session saved for it, so a loaded session already implies one of the two was sent. Also asks a Chat Completions client not to store, since the setting carries the same name on both OpenAI request shapes. * Add a live test that a hosted turn is not stored twice The AgentServer SDK's storage provider records every hosted turn around the handler, and that record is the conversation the caller reads. The agent's own run inside the container talks to its own service, and when that service is asked to keep the turn it writes a second copy of the same exchange, on a trail of its own that nobody reads and nobody reconciles. The caller's conversation looks clean, so the second copy goes unnoticed. The new downstream-store scenario runs an ordinary Foundry ChatClientAgent, like the first hosted agent sample, wrapped so that after the run it appends DOWNSTREAM_ID=<id> to the reply, carrying whatever its own run left behind. The tests then go looking for that id on the service: finding it means a second copy exists. Verified live against a Foundry project. On main both tests fail, reporting a readable id such as resp_0940e276..., and here the container reports DOWNSTREAM_ID=none and both pass. * Let the session carry the conversation in the downstream store test The run options were setting the conversation on every call, which the session already does. The single turn test now binds the session to the conversation up front, and the multi turn test starts from the agent's own default session and reads back what the hosted agent kept for the caller off ChatClientAgentSession once the first turn returns. Re-verified live: still fails on main, reporting a readable id such as resp_0c07a5e4..., and still passes here. |
||
|
|
ec32e86646 |
.NET: Aggregate usage across looping agents and chat clients (#7539)
* Ensure usage is merged for all looping components * Add max tool approval loop fixes * Fix net472 build break in usage aggregation tests DateTimeOffset.UnixEpoch is not available on .NET Framework 4.7.2, so the WithAggregatedUsage copy tests failed to compile for that target framework. Use an explicit DateTimeOffset instead; the specific instant is irrelevant, the value only needs to be non-default so the copy assertion is meaningful. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR comments --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
94bbfb2ac8 |
.NET: Harden file skill discovery (#7540)
* .NET: Harden file skill discovery Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8ff072fa-42d6-44b0-b226-2182cfc7639c * .NET: Handle inaccessible skill directories Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 8ff072fa-42d6-44b0-b226-2182cfc7639c --------- Copilot-Session: 8ff072fa-42d6-44b0-b226-2182cfc7639c |
||
|
|
74a144085a |
.NET: Bound the tool-approval auto-approval loop (#7472) (#7474)
* .NET: Bound the tool-approval auto-approval loop (#7472) `ToolApprovalAgent` re-invoked the inner agent from two unbounded `while (true)` loops whenever every surfaced approval request was auto-approved. Each pass is a fresh `InnerAgent.RunAsync` / `RunStreamingAsync` call, so a per-request cap such as `FunctionInvokingChatClient.MaximumIterationsPerRequest` restarts every time and cannot bound the chain. Under `AllToolsAutoApprovalRule` a model that keeps requesting an auto-approved tool therefore drives billable model calls indefinitely; the reporter measured 100M+ tokens over three days. Adds `ToolApprovalAgentOptions.MaxAutoApprovalIterations` (default `ToolApprovalAgent.DefaultMaxAutoApprovalIterations`, 10) and bounds both loops. Naming, default and `Throw.IfLessThan` validation follow the existing `LoopAgent.DefaultMaxIterations` / `LoopAgentOptions.MaxIterations` convention in this assembly. On reaching the cap the agent takes one final inner turn without auto-approving again, so a remaining approval request is surfaced to the caller to decide. Returning early instead would hand back an empty response, because `ProcessAndQueueOutboundApprovalRequestsAsync` strips every approval request once they are all auto-approved -- the case the loop exists to avoid. This mirrors the Python behaviour, which logs and issues one final request with tools disabled once its iteration budget is spent (`_tools.py`). Python is not affected: it caps at `DEFAULT_MAX_ITERATIONS` (40) and persists `attempt_count` in the budget state across approval resumes, so a resumed run continues the count rather than restarting it. Tests: the runaway is reproduced on both the streaming and non-streaming paths with an inner agent that never stops requesting an auto-approved tool. Inner invocations equal the cap plus the final turn, and scale with the configured cap, so the assertions fail if the bound is removed. No sample changes: with the loop bounded, Agent_Step01, Agent_Step06, Agent_Step07 and Hosted-AgentSkills are safe as written. * .NET: Add Arrange/Act/Assert comments to the cap constructor test Matches the test convention documented in dotnet/AGENTS.md and used by the surrounding tests in this file. * Increase default max auto approval iterations to 40 * Apply suggestion from @westey-m Co-authored-by: westey <164392973+westey-m@users.noreply.github.com> * Update comments in ToolApprovalAgent.cs --------- Co-authored-by: westey <164392973+westey-m@users.noreply.github.com> |
||
|
|
a4d4eafa5e |
Add CodeQL suppression comment for DevUI proxy validation (#7505)
The proxy target validation in ValidateProxyTarget already ensures requests stay on the configured backend. Add an inline suppression comment following the repo's established pattern. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4363ab44-4d9e-41a0-97d3-4ab0b973f0b2 |
||
|
|
da056275e6 |
.NET: [Experimental] Extend A2A task store with isolation key scoping (#7504)
* .NET: Add tenant-scoped task store isolation for A2A hosting Wrap ITaskStore with IsolationKeyScopedTaskStore when a SessionIsolationKeyProvider is registered, mirroring the existing session store isolation pattern. This ensures task operations are scoped per tenant in multi-user deployments. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: adc30d6c-ce66-40bb-933e-9801c2156cda * fix formatting issue --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: adc30d6c-ce66-40bb-933e-9801c2156cda |
||
|
|
1da571860a | Updating version for dotnet release 1.17.0 (#7514) | ||
|
|
d56e81357e | Fail declarative workflows when an agent returns an error (#7497) | ||
|
|
84d5a5eec1 |
Consolidate Dependabot dependency updates (#7445)
* Bump AgentMemory from 1.2.0 to 1.3.0 --- updated-dependencies: - dependency-name: AgentMemory dependency-version: 1.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * .NET: consolidate #7280 AgentMemory.AgentFramework 1.3.0 * Bump github/codeql-action/init from 4.37.0 to 4.37.3 Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.37.0 to 4.37.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump astral-sh/setup-uv from 8.3.2 to 9.0.0 Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.2 to 9.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/11f9893b081a58869d3b5fccaea48c9e9e46f990...c771a70e6277c0a99b617c7a806ffedaca235ff9) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump github/codeql-action/analyze from 4.37.0 to 4.37.3 Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.37.0 to 4.37.3. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81) --- updated-dependencies: - dependency-name: github/codeql-action/analyze dependency-version: 4.37.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump actions/cache from 5.0.5 to 6.1.0 Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.1.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...55cc8345863c7cc4c66a329aec7e433d2d1c52a9) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump actions/checkout from 6.0.2 to 7.0.1 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/de0fac2e4500dabe0009e67214ff5f5447ce83dd...3d3c42e5aac5ba805825da76410c181273ba90b1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump astral-sh/setup-uv in /.github/actions/python-setup Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 8.3.2 to 9.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/11f9893b081a58869d3b5fccaea48c9e9e46f990...c771a70e6277c0a99b617c7a806ffedaca235ff9) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 9.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * Bump ty from 0.0.60 to 0.0.64 in /python Bumps [ty](https://github.com/astral-sh/ty) from 0.0.60 to 0.0.64. - [Release notes](https://github.com/astral-sh/ty/releases) - [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ty/compare/0.0.60...0.0.64) --- updated-dependencies: - dependency-name: ty dependency-version: 0.0.65 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump prek from 0.4.10 to 0.4.11 in /python Bumps [prek](https://github.com/j178/prek) from 0.4.10 to 0.4.11. - [Release notes](https://github.com/j178/prek/releases) - [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md) - [Commits](https://github.com/j178/prek/compare/v0.4.10...v0.4.11) --- updated-dependencies: - dependency-name: prek dependency-version: 0.4.11 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump uv from 0.11.29 to 0.11.32 in /python Bumps [uv](https://github.com/astral-sh/uv) from 0.11.29 to 0.11.32. - [Release notes](https://github.com/astral-sh/uv/releases) - [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/uv/compare/0.11.29...0.11.32) --- updated-dependencies: - dependency-name: uv dependency-version: 0.12.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Bump ruff from 0.15.22 to 0.16.0 in /python Bumps [ruff](https://github.com/astral-sh/ruff) from 0.15.22 to 0.16.0. - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](https://github.com/astral-sh/ruff/compare/0.15.22...0.16.0) --- updated-dependencies: - dependency-name: ruff dependency-version: 0.16.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * update uv-build requirement in /python --- updated-dependencies: - dependency-name: uv-build dependency-version: 0.12.0 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * Python: align workspace pins for #7436-#7439 * Python: support ty 0.0.64 diagnostics for #7436 * Python: apply Ruff 0.16 formatting for #7439 * Update workflow action version annotations --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
9c8151699a | Fix Handoff orchestration sample not responding to user input (#7442) |