Files
microsoft--agent-framework/python/PACKAGE_STATUS.md
MohammadHaroonAbuomar 7302d0bf23 Python: agent-hooks interception contract as a first-class experimental core feature (#7515)
* feat(python): add agent-hooks middleware as experimental core feature

Implement the AGENT-HOOKS-0.1 interception contract as a first-class
experimental feature in agent_framework core.

- Single public factory agent_hooks_middleware() returning a private
  agent/chat/function middleware trio (one object per middleware
  category); partial or stacked installs fail closed with loud errors.
- All eight interception points: input/output at the agent seam,
  pre/post_model_call at the chat seam, pre/post_tool_call at the
  function seam, agent_startup/agent_shutdown bracketing each run.
- Fail-closed enforcement throughout: transforms write back into the
  native contexts (messages, arguments, results) or raise; content is
  preserved as Content objects; MiddlewareTermination short-circuits
  are guarded at every seam; enforcement-layer failures halt the run;
  interceptor crashes surface as host_error denies.
- Streaming is fully buffered per spec buffered_output semantics: no
  update egresses before the post_model_call/output verdicts; a deny
  at pull time releases zero updates; run state stays active across
  lazy pulls with cleanup on every exit path.
- Session scoping: per-run by default (startup/shutdown bracket each
  run) or host-owned via emitter/builder parameters for one session
  spanning multiple runs.
- agent-hooks-sdk is an opt-in agent-hooks extra (not in all),
  lazy-imported per the _mcp.py pattern; core imports cleanly without
  it and the factory raises a clear ModuleNotFoundError.
- ExperimentalFeature.AGENT_HOOKS + @experimental decorator, lazy root
  export, typing surface, PACKAGE_STATUS.md entry.
- 55 tests built on real Agent/mock-client flows covering deny-before-
  execution, transform write-back, rich-content preservation, complete
  streaming ordering, error cleanup, concurrency isolation, nested
  agents, and importability without the optional SDK.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* style(python): unquote ResponseStream annotation per pyupgrade

The pre-commit pyupgrade hook rewrites the quoted forward reference;
ResponseStream is imported at runtime in this module, so the quotes
were unnecessary.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* refactor(python): address agent-hooks review feedback

Reworks the agent-hooks feature per PR review:

- Verdicts now precede durability: a run-scoped persistence gate
  (_sessions.py) defers per-service-call history persistence and
  after-run provider work until the covering post_model_call/output
  verdict permits; denied content never persists, transforms persist
  post-write-back. Unhooked runs are unchanged (verified against an
  instrumented baseline).
- ResponseStream.buffered_and_gated: a buffered-gate combinator that
  applies the run's pending stream hooks before the gate, then seals
  the stream, so no middleware can rewrite egress after the output
  verdict. Replaces the hand-rolled replay iterator.
- MiddlewareBundle (public, _middleware.py): the factory returns an
  indivisible bundle categorize_middleware splits, making partial
  installs impossible by construction; members are validated at
  construction. Bare (non-sequence) middleware at agent construction
  is now normalized instead of silently dropped, and unrecognized
  middleware logs a warning instead of vanishing.
- Factory split and rename: create_agent_hooks_middleware (per-run
  sessions) and create_agent_hooks_middleware_from_emitter
  (host-owned); the sentinel parameter-diffing is gone.
- Wire conversions live in per-point codec classes owning to_wire and
  write_back. Fixes in that code: tool-call name transforms apply or
  raise; non-object args transforms raise; argument write-back merges
  only changed keys (original values, including bytes, preserved by
  identity); message-list write-back matches by identity, not index.
- function_approval_request objects on the normal return path pass
  through un-emitted, preserving the human approval pause.
- Hosted (service-executed) tool calls surface in the post_model_call
  content projection; the tool-seam limitation is documented.
- Import probe covers the full SDK surface and re-raises as
  missing-extra only for the agent_hooks module; module logger added;
  _json_safe replaced by make_json_safe (which gained bytes support);
  tools_registered uses normalize_tools; dependency-pyright analyzes
  the module again via the test dependency-group.
- Tests: 75 in the feature suite (persistence gating, stream-hook
  sealing, approval passthrough, codec units, bundle validation,
  bare-bundle installs), full core suite green.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* refactor(python): second review round for agent-hooks

Addresses the second review round on the agent-hooks feature:

- Nested-run persistence ownership: RawAgent.run stamps a run identity
  over the run's dynamic extent (including streaming pulls and result
  hooks); the persistence gate binds to its owning run via an
  offer/adopt handshake keyed to the agent instance and accepts only
  its owner's persists — nested runs persist inline regardless of how
  they were started (tool calls, middleware, custom run loops). The
  tool-seam suspension remains for custom-loop sub-agents invoked as
  tools; the one residual case (custom loop nested in a custom loop
  off the tool path) is fail-closed and documented. Fixes a latent
  pre-existing re-deferral: flush() now drains with the gate context
  suspended, so a nested hooked run's permitted after-run persistence
  no longer re-defers into an enclosing gate.
- as_tool stream_callback consumes the released (verdicted) stream;
  observers cannot see denied or pre-transform content. Both
  directions are regression-tested.
- categorize_middleware gained supported_categories: a bundle member
  landing in a category a call site cannot install raises; bare
  middleware warns like _add_middleware. Wired at the chat-client
  sites and the provider seam.
- ResponseStream.buffered_and_gated owns the re-derivation rule via a
  rederive callable (gates cannot choose released updates) and is
  marked experimental.
- Wire codecs compare with bool-aware equality (Python == equates
  1 == True, which made bool/number transforms look untouched and get
  dropped) and _ToolResultCodec.write_back owns the untouched-wire
  rule via the before value.
- middleware parameters accept a bare middleware or bundle everywhere
  the runtime does (constructors, run overloads, as_agent, telemetry
  and harness layers, foundry); the bare-source rule has a single
  owner in categorize_middleware; bare middleware assigned to the
  attribute now executes (documented behavior change).
- MiddlewareBundle is experimental and validates members; approval
  passthrough, typing-check fixes (ty ignores mypy-coded ignore
  comments), logging, and documentation updates per review.

Test count: 85 feature tests plus 12 new this round across sessions,
middleware, agents; full core suite green; typing checked under
mypy, pyrefly, ty, zuban, and pyright.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* docs(python): drop previous-behavior notes from middleware docstrings

Per review: docstrings describe current behavior only. The
bare-middleware behavior change stays recorded in the PR description
and commit history.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* fix(python): gate ownership survives retrying middleware

A retry or fallback middleware issuing a second call_next() gave the
new attempt a fresh run identity that the persistence gate's
first-bind-wins ownership rejected, so the retried attempt's history
persisted inline before the output verdict — a denied response became
durable again. The gate now accumulates every identity adopted
through its own offer ticket: all attempts' persistence stays behind
the one final verdict (deny drops all of it, allow flushes all of
it). Accumulation over rebind-replace is deliberate: rebinding would
flip an earlier attempt's still-running background work from deferred
to inline, which is the fail-open direction. A foreign agent still
cannot bind: tickets are minted only by the covered pipeline's final
handler and adoption is instance-keyed.

Also consolidates the bare-middleware-source rule into a single
_as_middleware_list owner used by every interpretation site (the
harness merge, BaseAgent.__init__, categorize_middleware, both
client-kwargs merges, get_response, SessionContext.extend_middleware),
including the str/bytes exclusion the stray copies missed. The
constructor now stores a copy of the caller's sequence; assign to the
middleware attribute for post-construction changes.

Retry regression tests cover denied and allowed retried runs in both
stream modes and fail with first-bind-wins restored.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* fix(python): streaming seam runs pipeline descent inside the gate

The streaming agent seam ran call_next() outside the persistence
gate (only _consume entered it later), so a retry middleware that
drained a successful attempt with get_final_response() and discarded
it persisted that attempt's exchange before any verdict existed; a
later deny dropped only the retry attempt's deferred work. The
descent is now wrapped in the gate exactly like the non-streaming
seam: attempt identities adopted during descent are accepted owners,
so in-pipeline draining defers, deny drops every attempt, and a
middleware that raises after draining strands the pending persists
unexecuted. The bind_owner docstring now states the actual soundness
invariant covering both bind sites: every bind comes from a run
inside the covered pipeline.

New tests cover drained-and-discarded attempts (deny and allow, both
stream modes) and a sub-agent tool inside a drained attempt; the
streaming deny variant fails with the gate wrap reverted.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

* fix(python): flush deferred persistence on streaming no-result termination

With the pipeline descent now running inside the persistence gate, a
middleware that drains a successful attempt and then terminates
without a result left that attempt's deferred persistence stranded:
the streaming no-result termination path raised before any flush, so
history of exchanges that really happened and passed their own
verdicts quietly vanished (streaming only; non-streaming already
flushes before its re-raise). The path now flushes before re-raising
the termination, with a state.halted guard first so an enforcement
failure during the drained attempt still strands pending fail-closed
and surfaces the halt, mirroring the non-streaming ordering exactly.

The regression test covers both seams; the streaming variant fails
without the fix.

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>

---------

Signed-off-by: MohammadHaroonAbuomar <40180927+MohammadHaroonAbuomar@users.noreply.github.com>
2026-08-07 00:25:09 +00:00

7.5 KiB

Python Package Status

This file tracks the current lifecycle state of the Python packages in this workspace. Some packages at later stages might have features within them that are not ready yet, these have feature stage decorators on the relevant APIs, and for experimental features warnings are raised. See the Feature-level staged APIs section below for details on which features are in which stage and where to find them.

Status is grouped into these buckets:

  • alpha - initial release and early development packages that are not yet ready for general use
  • beta - prerelease packages that are not currently release candidates
  • rc - release candidate packages, these are close to ready for release but may still have some breaking changes before the final release
  • released - stable packages without a prerelease suffix, these are stable packages that should not have breaking changes between versions
  • deprecated - removed or deprecated packages that should not be used for new work

Current packages

Package Path State
agent-framework python/ released
agent-framework-a2a python/packages/a2a beta
agent-framework-ag-ui python/packages/ag-ui released
agent-framework-anthropic python/packages/anthropic beta
agent-framework-azure-contentunderstanding python/packages/azure-contentunderstanding beta
agent-framework-azure-ai-search python/packages/azure-ai-search beta
agent-framework-azure-cosmos python/packages/azure-cosmos beta
agent-framework-azure-cosmos-memory python/packages/azure-cosmos-memory alpha
agent-framework-bedrock python/packages/bedrock beta
agent-framework-chatkit python/packages/chatkit beta
agent-framework-claude python/packages/claude beta
agent-framework-copilotstudio python/packages/copilotstudio beta
agent-framework-core python/packages/core released
agent-framework-declarative python/packages/declarative released
agent-framework-devui python/packages/devui beta
agent-framework-foundry python/packages/foundry released
agent-framework-foundry-hosting python/packages/foundry_hosting beta
agent-framework-foundry-local python/packages/foundry_local beta
agent-framework-gemini python/packages/gemini beta
agent-framework-github-copilot python/packages/github_copilot released
agent-framework-hosting python/packages/hosting alpha
agent-framework-hosting-a2a python/packages/hosting-a2a alpha
agent-framework-hosting-mcp python/packages/hosting-mcp alpha
agent-framework-hosting-responses python/packages/hosting-responses alpha
agent-framework-hosting-telegram python/packages/hosting-telegram alpha
agent-framework-hyperlight python/packages/hyperlight beta
agent-framework-lab python/packages/lab beta
agent-framework-mem0 python/packages/mem0 beta
agent-framework-mistral python/packages/mistral beta
agent-framework-monty python/packages/monty beta
agent-framework-ollama python/packages/ollama beta
agent-framework-openai python/packages/openai released
agent-framework-orchestrations python/packages/orchestrations released
agent-framework-purview python/packages/purview beta
agent-framework-redis python/packages/redis beta
agent-framework-tools python/packages/tools beta

Deprecated / removed packages

Package Previous path State Notes
agent-framework-azure-ai python/packages/azure-ai deprecated The client classes within the azure-ai package were renamed, sometimes changed, and moved to agent-framework-foundry.

Feature-level staged APIs

The following feature IDs have explicit feature-stage decorators on public APIs in the packages listed below.

Experimental features

AGENT_HOOKS

  • agent-framework-core: create_agent_hooks_middleware and create_agent_hooks_middleware_from_emitter from agent_framework/_agent_hooks.py, the AGENT-HOOKS-0.1 enforcement middleware bundle, and the MiddlewareBundle container from agent_framework/_middleware.py that both factories produce (MiddlewareBundle itself needs no extra). Requires the opt-in agent-framework-core[agent-hooks] extra (agent-hooks-sdk), which is deliberately not part of agent-framework-core[all]. Known limitation: service-side (hosted) tool execution never passes through the framework's function-invocation seam, so the pre_tool_call/post_tool_call points cannot intercept it; hosted tool calls and outputs are surfaced in the post_model_call content projection instead.

DECLARATIVE_AGENTS

  • agent-framework-declarative: declarative agent loading APIs from agent_framework_declarative, including AgentFactory, DeclarativeLoaderError, ProviderLookupError, and ProviderTypeMapping from agent_framework_declarative/_loader.py

EVALS

  • agent-framework-core: exported evaluation APIs from agent_framework, including LocalEvaluator, evaluate_agent, evaluate_workflow, and the related evaluation types and helper checks defined in agent_framework/_evaluation.py
  • agent-framework-foundry: FoundryEvals, evaluate_traces, and evaluate_foundry_target

FILE_HISTORY

  • agent-framework-core: FileHistoryProvider from agent_framework/_sessions.py

FIDES

  • agent-framework-core: security labeling, content indirection, policy enforcement, and secure MCP APIs from agent_framework/security.py, including IntegrityLabel, ConfidentialityLabel, ContentLabel, ContentVariableStore, SecureAgentConfig, and SecureMCPToolProxy

FOUNDRY_TOOLS

  • agent-framework-foundry: released-service tool helpers on FoundryChatClient, currently get_bing_grounding_tool and get_azure_ai_search_tool

FOUNDRY_PREVIEW_TOOLS

  • agent-framework-foundry: preview-service tool helpers on FoundryChatClient, including Bing Custom Search, SharePoint, Fabric, Memory Search, Computer Use, Browser Automation, and A2A

FUNCTIONAL_WORKFLOWS

  • agent-framework-core: functional workflow APIs from agent_framework/_workflows/_functional.py, including RunContext, step, FunctionalWorkflow, workflow, and FunctionalWorkflowAgent

HARNESS

  • agent-framework-core: experimental harness APIs for background agents, file access, looping, memory, and file-backed todo storage under agent_framework/_harness/

MCP_LONG_RUNNING_TASKS

  • agent-framework-core: MCPTaskOptions from agent_framework/_mcp.py

MCP_SKILLS

  • agent-framework-core: MCPSkillResource, MCPSkill, and MCPSkillsSource from agent_framework/_skills.py

PROGRESSIVE_TOOLS

  • agent-framework-core: FunctionInvocationContext.add_tools and FunctionInvocationContext.remove_tools from agent_framework/_middleware.py

SESSION_STORE

  • agent-framework-core: SessionStore and FileSessionStore from agent_framework/_sessions.py
  • agent-framework-foundry-hosting: FoundrySessionStore from agent_framework_foundry_hosting/_session_store.py

TO_PROMPT_AGENT

  • agent-framework-foundry: to_prompt_agent from agent_framework_foundry/_to_prompt_agent.py

Release-candidate features

There are currently no feature-level rc APIs.