microsoft / microsoft/agent-framework

.NET: run-scoped context with lifecycle hooks for agent decorators

Open
#7,729 0 comments 0 reactions 1 assignee View on GitHub

@westey-m is already working on this.

Since Aug 18, 2026.

.NET
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

## Problem

The framework has no run-scoped context object with lifecycle attach points that an extension can use to carry per-run state and act at well-defined moments of a `ChatClientAgent` run. `AIAgent.CurrentRunContext` is a read-only info object, and there is no hook between "the run's final response exists" and "providers are notified / the response is returned".

The agent-hooks integration (#7564) mimics a run scope with an `AsyncLocal` set by its outermost decorator, which works but produces one genuinely awkward mechanism: end-of-run persistence notifications capture the **inner agent's own message list**, assembled before any outer decorator ran. For a streamed run whose output the enforcement transforms after buffering, the deferred persistence would therefore write pre-transform content — so the gating providers substitute the verdicted messages at flush time via state smuggled through the AsyncLocal (`AgentHooksRunState.VerdictedResponseMessages`, consumed in `AgentHooksGatingChatHistoryProvider`/`AgentHooksGatingAIContextProvider`). It is correct and regression-tested, but it is exactly the kind of coupling a framework-owned run context would eliminate.

## Proposed shape (for discussion)

A framework-owned run scope with lifecycle attach points, e.g.:

- run-start / run-end callbacks with access to a mutable per-run property bag;
- a "response finalized, providers not yet notified" hook where a decorator can observe/replace the response messages that will be persisted (which would make deferral-and-substitution unnecessary: the notification would simply be built after outer decorators finish);
- flowing the scope across the streaming drain the same way `AIAgent.RunStreamingAsync` already re-establishes `CurrentRunContext` after each yield.

## Context

- PR #7564 (concrete mechanism: `AgentHooksRunState` (AsyncLocal), `VerdictedResponseMessages` substitution in the gating providers, `RunPersistenceGate` flush ordering in `AgentHooksAgent`)
- Review thread: https://github.com/microsoft/agent-framework/pull/7564#discussion_r3804862167
- Related: companion issues #7726 (addressable pipeline positions) and #7728 (interceptable providers) and #7718

Not urgent (per the review thread). cc @westey-m

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.