Skip to content

Python: Add per-tool AgentModeProvider exposure controls - #25

Closed
eavanvalkenburg wants to merge 5 commits into
mainfrom
mode-tool-exposure-controls
Closed

eavanvalkenburg wants to merge 5 commits into
mainfrom
mode-tool-exposure-controls

Conversation

@eavanvalkenburg

Copy link
Copy Markdown
Owner

Motivation & Context

Applications can retain AgentModeProvider state and workflow guidance while supplying their own mode-change UI or tool, but the provider currently always exposes both mode_set and mode_get. This leaves models with duplicate mode authorities when an application provides a replacement setter.

This change allows each built-in mode tool to be omitted independently without disabling mode state, per-turn instructions, or external mode-change notifications.

Description & Review Guide

  • What are the major changes? Add expose_mode_set and expose_mode_get options to AgentModeProvider, both defaulting to True; conditionally contribute each tool; adapt only built-in guidance so it does not advertise hidden tools; document application-controlled mode replacement through the existing provider, tools, and state-helper APIs; add coverage for all exposure combinations, custom guidance, retained state and notifications, and a harness replacement tool.
  • What is the impact of these changes? Existing applications keep identical defaults. Applications can hide either or both provider tools while preserving the mode subsystem and can connect replacement tools to the same session-backed state with get_agent_mode and set_agent_mode.
  • What do you want reviewers to focus on? Whether the exposure-aware built-in guidance remains clear when mode_set is hidden, while custom instructions and mode_instructions remain untouched.

Related Issue

Fixes microsoft#7221

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. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Lubaoshuai and others added 5 commits September 17, 2026 08:15
…unts (microsoft#8354)

* Python: exclude encrypted reasoning payloads from compaction token counts

The compaction token counter serialises each message and tokenises the JSON.
Content.protected_data (OpenAI encrypted_content, Anthropic thinking
signature, Gemini thought_signature, OpenAI reasoning_details) is opaque
ciphertext the model replays but never tokenises, so counting it inflated
every token-aware compaction decision. The same blob can also ride in
additional_properties as encrypted_content.

Both are now excluded from serialised content, matching the existing
exclusions for raw_representation and mirrored items.

Fixes microsoft#8348

* fix(compaction): count clear-text reasoning details and invalidate stale token caches

Review follow-up for the protected-data token exclusion:

- reasoning_details stored in protected_data are JSON-serialised and
  replayed to the provider as clear text (summary, reasoning_text and
  nested reasoning.text), so only opaque members (encrypted_content) are
  excluded from the estimate; non-JSON payloads (Anthropic signature,
  Responses API encrypted blobs) are still dropped entirely.
- group token counts are stamped with a serialization basis version;
  counts cached under an older basis (e.g. sessions annotated before a
  serialization change) are recomputed instead of reused.

* fix(compaction): resolve pyright/mypy typing errors in token estimation

- annotate the recursive reasoning-payload filter with explicit
  dict[Any, Any] / list[Any] casts so iterating the narrowed Any dict
  does not leak Unknown types under pyright strict
- cast additional_properties before the encrypted_content filter
- assert non-None token counts in the clear-text regression test so the
  ordering comparison does not involve optional integers

---------

Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
* Python: fix mixed function-call batch classification

* Python: scope mixed pause correlation

* Python: preserve streaming approval updates

* Python: preserve approval resume context

* Python: address approval resume review feedback

* Python: harden mixed approval replay

* Python: keep stateless mixed approvals inert
…8150) (microsoft#8163)

* Python: include checkpoint_id on AG-UI interrupt metadata (microsoft#8150)

Attach the pause workflow checkpoint id to RUN_FINISHED interrupt
metadata.agent_framework so multi-worker clients can resume via
forwardedProps.checkpoint_id without a side channel.

* Python: Prefer runner pause checkpoint over shared get_latest (microsoft#8150)

* Python: Fix ag-ui lint and ty ignores for microsoft#8150 tests

* Python: Core resolve_pause_checkpoint_id for AG-UI (microsoft#8150)

Move pause-checkpoint selection into Workflow and require a run-scoped
baseline so leftover runner ids are not advertised across runs.

* fix(python): resolve pyright failures in pause checkpoint lookup

Unblocks Package Checks / merge-gatekeeper on PR microsoft#8163.

* fix(ag-ui): address microsoft#8163 review on pause checkpoint ownership (#2)

- Workflow captures run baseline / restored id inside run(); resolve uses them
  so callers need not thread baseline_checkpoint_id.
- Exclude restored checkpoint from pause candidates after resume.
- Drop issue reference in docstring; emit RUN_FINISHED via existing
  _build_run_finished_event after attaching pause id.
- Move core pause-resolve coverage into test_workflow.py (no new test file).

* fix(ag-ui): resume builder-storage pause IDs without AG-UI storage

When checkpoint_id+resume is supplied, load pending requests from the workflow's effective builder/runtime storage if AG-UI was not given an explicit checkpoint_storage, so emitted pause IDs remain round-trippable.

* fix(ag-ui): silence ty invalid-argument-type on builder-storage resume test

Match existing yield_output ignore markers so Test Typing Checks accept the new resume round-trip coverage.

* fix(ag-ui): resume builder storage via AgentFrameworkWorkflow.run()

Allow forwardedProps.checkpoint_id when only WorkflowBuilder storage is configured, so wrapper/endpoint hosts round-trip pause ids without duplicating checkpoint_storage.

---------

Co-authored-by: minelhi <3417378192@qq.com>
Co-authored-by: LI <2484593937@qq.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
* Reject ambiguous skill frontmatter fields in Python and .NET

Validate recognized top-level field casing and uniqueness while preserving existing scalar parsing and nested metadata behavior. Add file and MCP archive regression coverage.

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

* Keep first duplicate skill metadata value in Python and .NET

Warn on duplicate metadata entries without rejecting skills, preserve existing key comparison rules, and expand scalar and archive regression coverage.

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

* Preserve unset optional skill frontmatter fields

Keep bare empty optional fields null while retaining duplicate and casing validation in Python and .NET. Add file and MCP archive regression coverage.

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

* Support quoted skill frontmatter property names

Normalize single- and double-quoted root names before existing field validation in Python and .NET. Support quoted metadata headers and expand scalar and archive regression coverage.

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

* Use PyYAML for Python skill frontmatter parsing

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
@eavanvalkenburg

Copy link
Copy Markdown
Owner Author

Closing because this draft was created against the fork instead of the intended microsoft/agent-framework:main target.

This branch had an error being deployed

2 failed deployments
github-app-auth — e108e1f5 Deployed Sep 17, 2026 by eavanvalkenburg via team_check #32
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.

Python: [Feature]: allow suppressing/replacing individual AgentModeProvider tools

4 participants