Skip to content

Python: Protect custom AG-UI approval state namespaces - #32

Closed
eavanvalkenburg wants to merge 42 commits into
mainfrom
custom-approval-namespace
Closed

eavanvalkenburg wants to merge 42 commits into
mainfrom
custom-approval-namespace

Conversation

@eavanvalkenburg

Copy link
Copy Markdown
Owner

Motivation & Context

Keep configured tool-approval state namespaces server-owned when AG-UI merges Shared State into an agent session.

Description & Review Guide

  • What are the major changes? Include all configured ToolApprovalMiddleware.source_id values in the existing protected-key set, using categorize_middleware to support middleware bundles.
  • What is the impact of these changes? Request and restored Shared State leave custom approval state untouched, while ordinary Shared State and trusted session continuation remain available.
  • What do you want reviewers to focus on? The three-line production change and parameterized endpoint coverage for direct, bundled, and forwarding middleware, multiple and updated namespaces, request and snapshot state, and trusted approval rules.

Related Issue

None.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change.

dependabot Bot and others added 30 commits September 22, 2026 12:12
microsoft#8612)

Bumps the basics group in /python/packages/lab with 1 update: [prek](https://github.com/j178/prek).


Updates `prek` from 0.5.2 to 0.5.3
- [Release notes](https://github.com/j178/prek/releases)
- [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md)
- [Commits](j178/prek@v0.5.2...v0.5.3)

---
updated-dependencies:
- dependency-name: prek
  dependency-version: 0.5.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: basics
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the basics group with 1 update in the /python/packages/lab directory: [prek](https://github.com/j178/prek).


Updates `prek` from 0.5.2 to 0.5.3
- [Release notes](https://github.com/j178/prek/releases)
- [Changelog](https://github.com/j178/prek/blob/master/CHANGELOG.md)
- [Commits](j178/prek@v0.5.2...v0.5.3)

---
updated-dependencies:
- dependency-name: prek
  dependency-version: 0.5.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: basics
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ft#8589)

* Python: [BREAKING] Preserve MCP runtime and approval context

* Docs: shorten MCP approval compatibility note

* Docs: keep approval compatibility details out of package overview
…soft#8524)

Only None short-circuited before; an instructions value of "" (the
usual unset-options default) still injected a system message with empty
content ahead of the conversation. Empty and all-whitespace entries are
dropped, and a real instruction prepends verbatim.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
…n error tests (microsoft#8611)

In test_cmc_with_invalid_data_content_media_type and test_cmc_with_invalid_content_type, the entire test setup including message creation and client instantiation was enclosed inside the with pytest.raises block. If any setup statement failed with ChatClientInvalidRequestException, the test would pass falsely. Moving the fixture setup outside the context manager ensures that only the actual get_response call is asserted to raise the exception.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
…ictionary (microsoft#8604)

When response_format is configured as a json schema dict rather than a Pydantic BaseModel, skip_text was previously set to True, which suppressed text content events. This change ensures skip_text is only enabled for Pydantic models whose fields map directly to state or message fields. Non-model formats keep emitting text content events as expected.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
…ts consistently (microsoft#8613)

In add_usage_details, passing None for one of the arguments previously returned the other argument dictionary directly by reference, and early return copies bypassed boolean and non-integer filtering. Normalizing None operands to empty UsageDetails and routing all combinations through the common merge path ensures returned dictionaries are always new copies and that booleans and non-integer values are consistently skipped and logged.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
…64 docstrings (microsoft#8614)

The function signature of detect_media_type_from_base64 uses keyword only arguments (*). The code examples in the docstrings of detect_media_type_from_base64 and Content.from_data passed string variables positionally, which raises a TypeError when executed directly. Updating the examples to pass data_str and data_uri keyword arguments ensures the documentation samples run cleanly.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
…microsoft#8609)

When a tool call has truly absent arguments such as None or an empty string, _extract_tool_calls now represents the arguments as an empty dictionary. Invalid JSON or non-object payloads continue to yield None to signal a parse failure, ensuring ExpectedToolCall with empty arguments does not match malformed inputs. Added unit tests for absent, malformed JSON, and non-object payloads.

Signed-off-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Manohar Paturi <186662190+ManoharPaturi@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
…crosoft#8403)

* fix: a bug where invoke function tool could bypass approval

* Filter forged approval results from side effects

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Restrict approval replay fallback

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Fix netstandard approval build

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Stabilize concurrent checkpoint smoke tests

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* fix: makes approval sequence consistent across snapshots

* fix: avoid duplicating approval keys across snapshots

* fix: mis correlation of concurrent execution in different modes

* chore: linting

* Fix external response correlation

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* chore: formatting

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

* fix: wrap the external request to make the id accessible

* fix: safe port lookup

* fix: removes extraneous interface

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: use uppermost parent type where the properties are defined

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: registered results

---------

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* ci: selects the slnf file for the symbol server in vscode
ci: use the slnf file for dotnet build tasks

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* ci: adds test projects in the slnf file

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* Fix build task configuration in tasks.json

Updated build task to reference the correct solution file and change the working directory.

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

* Rename source and test solution filter

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

---------

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
* Support short flags in docker command

* Address PR comments
* fix(hosting): resume trusted function approvals

Recognize DevUI function approval responses, persist agent sessions across response continuations, and reject approval responses when no session store is configured.

Refs microsoft#6006

* fix(hosting): reject invalid approval continuations

Track approval request IDs emitted by Responses and reject unknown or cross-session approval responses before agent execution.

Refs microsoft#6006

* fix(hosting): require explicit approval decisions

Reject function approval responses that omit the required approved Boolean instead of interpreting the missing value as a rejection.

Refs microsoft#6006

* fix(hosting): reject malformed approval arguments

Require function approval arguments to be a JSON object, return request binding errors for invalid shapes, and emit an empty object for no-argument calls.

Refs microsoft#6006

* fix(hosting): preserve background session isolation

Capture the trusted caller isolation key before response execution detaches from the HTTP request and bind background session operations to that value.

Refs microsoft#6006

* fix(hosting): persist transient agent sessions

Separate session storage identity from agent instance identity so request-routed transient agents can restore sessions without changing AIAgent.Id or AIAgent.Name.

Refs microsoft#6006

* fix(hosting): honor scoped response execution

* test(hosting): define streaming approval continuation

* fix(hosting): preserve nested session isolation
…osoft#8641)

* .NET: Enforce approval response binding consistently

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

* .NET: Document approval response binding scope

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

---------

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

* Add function replace support for function middleware

* Address PR comments.

* Fix build errors

* Address PR comments
* Require established sessions for A2A continuations

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

* Keep A2A streaming session state current

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

* Align A2A continuation context validation

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

* Preserve task-only A2A continuations and streaming state

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

* Simplify A2A streaming context validation

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

* Validate A2A streaming context before yielding

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Use the workflow token for fix-ci evidence

* Tighten fix-ci token permissions
… path (microsoft#7418) (microsoft#8548)

* Python: Preserve structured output on streaming harness tool-approval path

Forward response_format through ToolApprovalMiddleware's stream finalizer
so AgentResponse.value is parsed the same way as the non-streaming path.

* Python: Keep terminal structured value after auto-approved tool preamble

Return the last inner AgentResponse from the streaming tool-approval
finalizer so coalesced preamble text cannot clobber response.value.

* Potential fix for pull request finding 'Preserve terminal JSON value before checking lazy parse state'

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

* Python: Address review on streaming structured-output finalizer

Follow-up to microsoft#8548 review feedback:

- Forward the terminal inner response's structured value through the public
  AgentResponse.from_updates(value=...) contract instead of mutating the
  private _value/_value_parsed fields. Those fields were only copied when the
  inner response had already parsed its value, so the normal lazy-parse case
  still reparsed the coalesced preamble and JSON as one invalid string.
- Resolve final.value eagerly (which completes the lazy parse) and suppress
  the expected parse failures (ValueError/TypeError) so a parse error still
  surfaces lazily on value access, matching a middleware-free streaming run.
- Cast default_options to Mapping[str, Any] in _structured_response_format so
  strict pyright no longer reports reportUnknownMemberType and
  reportUnknownVariableType (Package Checks).
- Keep the parametrized regression test's option dicts out of Agent's generic
  client/options inference so mypy, pyrefly, ty, zuban, and pyright all pass
  (Test Typing Checks).

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
* Python: scope executor activity message IDs to workflow runs

* Python: disambiguate run and executor activity ID components

* Python: narrow activity snapshots in workflow regression tests
…icrosoft#8654)

Portable in/not_in membership never matches a null field, but the
DocumentDB filter compiler kept None in the $in operands behind an
$exists guard, so Filter("x", "in", [None, "a"]) also returned
documents whose field is null. Drop None operands like the MongoDB,
Redis and Postgres connectors do.

Fixes microsoft#8653
… directory with 2 updates (microsoft#8650)

* Build(deps-dev): Bump the python-type-checkers group across 1 directory with 2 updates

Bumps the python-type-checkers group with 2 updates in the /python directory: [pyrefly](https://github.com/facebook/pyrefly) and [ty](https://github.com/astral-sh/ty).


Updates `pyrefly` from 1.3.0 to 1.3.1
- [Release notes](https://github.com/facebook/pyrefly/releases)
- [Commits](meta/pyrefly@1.3.0...1.3.1)

Updates `ty` from 0.0.80 to 0.0.81
- [Release notes](https://github.com/astral-sh/ty/releases)
- [Changelog](https://github.com/astral-sh/ty/blob/main/CHANGELOG.md)
- [Commits](astral-sh/ty@0.0.80...0.0.81)

---
updated-dependencies:
- dependency-name: pyrefly
  dependency-version: 1.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-type-checkers
- dependency-name: ty
  dependency-version: 0.0.81
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: python-type-checkers
...

Signed-off-by: dependabot[bot] <support@github.com>

* Regenerate python/uv.lock for pyrefly 1.3.1 and ty 0.0.81

Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@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: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
…8660)

is_type_compatible() only handled Any as a target, so an executor declaring WorkflowContext[Any] could not be connected to a typed executor and workflow build failed with TypeCompatibilityError.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7ed91283-cb21-49a7-98f4-b1c088d0b6b6
baywet and others added 12 commits September 23, 2026 13:20
* fix(dotnet): validate forwarded request port types

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

Copilot-Session: 7ed91283-cb21-49a7-98f4-b1c088d0b6b6

* fix(dotnet): preserve request type assignability

Validate wrapped request forwarding against the original declared CLR type before deserializing the payload, preserving derived-to-base forwarding while rejecting unrelated types.

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

Copilot-Session: 560f0ccd-0091-485e-87fc-d55bf3f2bb45

* chore: Potential fix for pull request finding 'Missed opportunity to use Where'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Fix request port duplicate type resolution

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

Copilot-Session: 09e0df64-ceeb-4096-8811-964b3f2dddbe

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Copilot-Session: 7ed91283-cb21-49a7-98f4-b1c088d0b6b6
Copilot-Session: 560f0ccd-0091-485e-87fc-d55bf3f2bb45
Copilot-Session: 09e0df64-ceeb-4096-8811-964b3f2dddbe
…t#8200)

* fix: use allow list for configuration keys

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* Apply batched suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* chore: formatting

* Potential fix for pull request finding 'Missed opportunity to use Select'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Address declarative workflow review feedback

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* .NET: address workflow sensitivity review comments

Persist workflow sensitivity metadata for checkpoint restore, propagate sensitive default question values, and derive expression sensitivity from Power Fx syntax rather than raw text scanning.

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

* .NET: fix ChatClient factory options validation

Validate factory options before the base constructor initializer uses them so null handling remains explicit without nullable dereferences.

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

Copilot-Session: 668ac22f-5312-4df7-b470-55ca8535862d

* chore: formatting

* fix review feedback on declarative sensitivity APIs

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* fix declarative review feedback

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* fix: context forwarding

* Fix declarative sensitivity review comments

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Fix declarative review feedback

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Merge main and resolve conflicts

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Revert "Merge main and resolve conflicts"

This reverts commit 8a23310.

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Address declarative review feedback

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Update dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/DeclarativeWorkflowBuilder.cs

* Update dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/IWorkflowContextExtensions.cs

* Remove unusable Power Fx Set opt-in

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

* Update dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Kit/IWorkflowContextExtensions.cs

* fix: pass the env var allow list down the prompt

* fix: missing sensitivity for state

* tests: adds additional tests to cover edge scenarios

* chore: Change ReadStateWithSensitivityAsync to use PortableValue

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

* tests: fixes build failure because of copilot suggestion

* fix: pass the sensitivity through the foreach loop

* tests: fixes build failure for netfx

* tests: fixes bound validation

* chore: moves new class to dedicated file

* tests: fixes netfx build issues

* fix: adds missing netfx conditional compilation directive

* chore: removes noisy additional options

* chore: restore missing defensive programming

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: refactors duplicated constructor

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: Initialize Sensitivities dictionary with case-insensitive comparer

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

* fix: null reference exception

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: formatting

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* tests: adds missing test to cover the fallback scenario

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: removes back compat allow list

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* tests: updates assertions to account for non back compat behaviour

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* tests: inspect the inner exception to avoid debounce differences between net and netfx

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: makes comparison case sensitive

* chore: makes comparison case sensitive

* fix: avoid calling sync over async to potentially cause deadlocks

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: adds compatibility deprecated method

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: binary compatibility

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* fix: missing constructor

* chore: removes extraneous constructor

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* tests: aligns with constructor changes

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: removes outdated methods

Signed-off-by: Vincent Biret <vibiret@microsoft.com>

* chore: formatting

---------

Signed-off-by: Vincent Biret <vibiret@microsoft.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: 668ac22f-5312-4df7-b470-55ca8535862d
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7ed91283-cb21-49a7-98f4-b1c088d0b6b6
…soft#8692)

* Only consume stored approvals on success

* Address PR comments
* Set better expecations for contributors

* Address PR comments
…rosoft#8639)

* Python: make handoff reply routing configurable

* Test handoff start-agent response context
…#8596)

* Python: Scope workflow invocation kwargs by executor graph

* Python: Address workflow kwargs review feedback

* Python: Preserve legacy nested kwargs validation

* Python: Preserve transparent agent-name routing

* Python: Preserve plain workflow kwargs semantics
* Python: fix Foundry background stateless tool replay

* Python: harden stateless reasoning replay validation
…hods (microsoft#8709)

* fix(python): validate settings and expose agent lifecycle methods

* fix(python): preserve settings coercion compatibility
* Python: preserve compaction through middleware rewrites

* Python: harden replacement summary reconciliation

* Python: snapshot fallback reconciliation messages

This branch had an error being deployed

1 failed and 1 inactive deployments
github-app-auth — 17a733bc Deployed Sep 24, 2026 by eavanvalkenburg via team_check #44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.