Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
276 changes: 276 additions & 0 deletions docs/decisions/0033-python-session-store-serialization.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions python/.github/skills/agent-framework-py-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ If the user states target versions or a date explicitly, use exactly what they s

## Non-negotiable rules

- **Release workflow owns the CHANGELOG**: individual feature/fix PRs do not edit
`python/CHANGELOG.md`; this workflow creates the entries centrally from merged changes.
- **CHANGELOG-driven bumps**: only packages mentioned in the new CHANGELOG section get version bumps. Exceptions: root follows core (==pin); user-opted cohort bump on betas.
- **Follow `python-package-management` for package lifecycle and versioning rules** — do not duplicate those
rules in this release workflow.
Expand Down Expand Up @@ -136,6 +138,9 @@ Root `agent-framework` is touched when `python/pyproject.toml`, `python/agent_fr

### 4. Draft CHANGELOG entries (THIS DRIVES THE BUMP LIST)

Individual feature/fix PRs intentionally do not add CHANGELOG entries. During release preparation, derive this section
centrally from the merged PRs since the last released tag.

Locate `## [Unreleased]` and the top existing release header. INSERT a new section between them.

**New section structure:**
Expand Down
7 changes: 7 additions & 0 deletions python/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ team norms from a single conversation without explicit confirmation.
match the feature-lifecycle stages documented in the
`python-feature-lifecycle` skill.

## Changelog Ownership

- Individual feature, fix, documentation, and dependency PRs must not update
`python/CHANGELOG.md`.
- CHANGELOG entries and release sections are assembled centrally during the
Python release-preparation workflow.

## Pull Request Description Guidance

When preparing a PR description:
Expand Down
55 changes: 52 additions & 3 deletions python/PACKAGE_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,61 @@ listed below.
helper checks defined in `agent_framework/_evaluation.py`
- `agent-framework-foundry`: `FoundryEvals`, `evaluate_traces`, and `evaluate_foundry_target`

#### `SKILLS`
#### `FILE_HISTORY`

- `agent-framework-core`: exported skills APIs from `agent_framework`, including `Skill`,
`SkillResource`, `SkillScript`, `SkillScriptRunner`, and `SkillsProvider` from
- `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`

#### `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.
5 changes: 4 additions & 1 deletion python/packages/core/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,16 @@ agent_framework/
### Sessions (`_sessions.py`)

- **`AgentSession`** - Manages conversation state and session metadata
- **`SessionStore`** - Experimental in-memory opaque `session_id -> AgentSession` snapshot store; reads return independent copies
- **`FileSessionStore`** - Experimental msgspec file-backed session snapshot store with atomic last-writer-wins updates; JSON is the default, `serialization_format="msgpack"` enables binary MessagePack, file keys use a restricted portable shape, and corrupt snapshots are quarantined before an error is raised
- **`register_state_type`** - Registers custom `AgentSession.state` classes with stable type IDs and optional mapping codecs. Implicit Pydantic registration remains temporarily with `DeprecationWarning`, but module-level registration is needed to guarantee cold-start restoration.
- **`ServiceSessionId`** - Mapping alias for structured service-owned continuation handles used in `AgentSession.service_session_id`
- **`SessionContext`** - Context object for session-scoped data during agent runs. `extend_messages(...)` can attach
ordered, deduplicated `origin_session_ids` attribution when a provider injects content from other sessions.
- **`ContextProvider`** - Base class for context providers (RAG, memory systems)
- **`HistoryProvider`** - Base class for conversation history storage
- **`InMemoryHistoryProvider`** - Built-in session-state history provider for local runs
- **`FileHistoryProvider`** - JSON Lines file-backed history provider storing one file per session with one message record per line
- **`FileHistoryProvider`** - Experimental append-only file-backed history provider; msgspec JSON Lines is the default and `serialization_format="msgpack"` uses length-prefixed binary MessagePack records. Custom `dumps`/`loads` remain as deprecated JSON-only compatibility hooks and emit `DeprecationWarning` when supplied.

### Skills (`_skills.py`)

Expand Down
4 changes: 4 additions & 0 deletions python/packages/core/agent_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,13 @@
"AgentSession",
"ContextProvider",
"FileHistoryProvider",
"FileSessionStore",
"HistoryProvider",
"InMemoryHistoryProvider",
"MESSAGE_INJECTION_PENDING_MESSAGES_STATE_KEY",
"MessageInjectionMiddleware",
"ServiceSessionId",
"SessionStore",
"SessionContext",
"enqueue_messages",
"register_state_type",
Expand Down Expand Up @@ -451,6 +453,7 @@
"FileMemoryProvider",
"FileSearchMatch",
"FileSearchResult",
"FileSessionStore",
"FileSkill",
"FileSkillScript",
"FileSkillsSource",
Expand Down Expand Up @@ -516,6 +519,7 @@
"SelectiveToolCallCompactionStrategy",
"ServiceSessionId",
"SessionContext",
"SessionStore",
"SingleEdgeGroup",
"Skill",
"SkillFrontmatter",
Expand Down
4 changes: 4 additions & 0 deletions python/packages/core/agent_framework/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,13 @@ from ._sessions import (
AgentSession,
ContextProvider,
FileHistoryProvider,
FileSessionStore,
HistoryProvider,
InMemoryHistoryProvider,
MessageInjectionMiddleware,
ServiceSessionId,
SessionContext,
SessionStore,
enqueue_messages,
register_state_type,
)
Expand Down Expand Up @@ -418,6 +420,7 @@ __all__ = [
"FileMemoryProvider",
"FileSearchMatch",
"FileSearchResult",
"FileSessionStore",
"FileSkill",
"FileSkillScript",
"FileSkillsSource",
Expand Down Expand Up @@ -483,6 +486,7 @@ __all__ = [
"SelectiveToolCallCompactionStrategy",
"ServiceSessionId",
"SessionContext",
"SessionStore",
"SingleEdgeGroup",
"Skill",
"SkillFrontmatter",
Expand Down
40 changes: 26 additions & 14 deletions python/packages/core/agent_framework/_feature_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class ExperimentalFeature(str, Enum):
MCP_LONG_RUNNING_TASKS = "MCP_LONG_RUNNING_TASKS"
MCP_SKILLS = "MCP_SKILLS"
PROGRESSIVE_TOOLS = "PROGRESSIVE_TOOLS"
SESSION_STORE = "SESSION_STORE"
TO_PROMPT_AGENT = "TO_PROMPT_AGENT"


Expand Down Expand Up @@ -140,6 +141,15 @@ def _get_descriptor_callable(obj: Any) -> Callable[..., Any]:
return cast(Callable[..., Any], obj.__func__)


def _is_internal_framework_subclass(args: tuple[Any, ...]) -> bool:
"""Return whether an experimental subclass is defined inside an Agent Framework package."""
subclass = next((arg for arg in args if isinstance(arg, type)), None)
if subclass is None:
return False
module = subclass.__module__
return module == "agent_framework" or module.startswith(("agent_framework.", "agent_framework_"))


def _is_protocol_class(obj: Any) -> bool:
return isinstance(obj, type) and bool(getattr(obj, "_is_protocol", False))

Expand Down Expand Up @@ -326,28 +336,30 @@ def __new__(cls: type[Any], /, *args: Any, **kwargs: Any) -> Any:

@functools.wraps(original_init_subclass_func)
def bound_init_subclass_wrapper(*args: Any, **kwargs: Any) -> Any:
_warn_on_feature_use(
stage=stage,
feature_id=feature_id,
object_name=object_name,
category=category,
)
if not _is_internal_framework_subclass(args):
_warn_on_feature_use(
stage=stage,
feature_id=feature_id,
object_name=object_name,
category=category,
)
return original_init_subclass_func(*args, **kwargs)

experimental_class.__init_subclass__ = classmethod(bound_init_subclass_wrapper) # type: ignore[assignment]
else:

@functools.wraps(original_init_subclass)
def init_subclass_wrapper(*args: Any, **kwargs: Any) -> Any:
_warn_on_feature_use(
stage=stage,
feature_id=feature_id,
object_name=object_name,
category=category,
)
def init_subclass_wrapper(subclass: type[Any], /, *args: Any, **kwargs: Any) -> Any:
if not _is_internal_framework_subclass((subclass, *args)):
_warn_on_feature_use(
stage=stage,
feature_id=feature_id,
object_name=object_name,
category=category,
)
return original_init_subclass(*args, **kwargs)

experimental_class.__init_subclass__ = init_subclass_wrapper
experimental_class.__init_subclass__ = classmethod(init_subclass_wrapper) # type: ignore[assignment]

return cast(FeatureStageT, experimental_class)

Expand Down
6 changes: 4 additions & 2 deletions python/packages/core/agent_framework/_harness/_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -976,8 +976,10 @@ def __init__(
consolidation_client: Optional chat client override used only for consolidation so the
cleanup pass can use a cheaper or faster model than the main agent client.
history_message_filter: Optional callback that can rewrite or drop messages before transcript save.
history_dumps: Callable used to serialize transcript JSONL.
history_loads: Callable used to deserialize transcript JSONL and state JSON.
history_dumps: Deprecated callback forwarded to ``FileHistoryProvider.dumps``.
Omit it to use msgspec JSON.
history_loads: Deprecated callback forwarded to ``FileHistoryProvider.loads``.
Omit it to use msgspec JSON.
"""
super().__init__(
source_id=source_id,
Expand Down
Loading
Loading