Skip to content

Python: Core: add experimental session-mode harness context provider#5611

Merged
eavanvalkenburg merged 5 commits intomicrosoft:mainfrom
eavanvalkenburg:harness/mode
May 5, 2026
Merged

Python: Core: add experimental session-mode harness context provider#5611
eavanvalkenburg merged 5 commits intomicrosoft:mainfrom
eavanvalkenburg:harness/mode

Conversation

@eavanvalkenburg
Copy link
Copy Markdown
Member

@eavanvalkenburg eavanvalkenburg commented May 3, 2026

Motivation and Context

Part of the experimental Agent Harness feature, mirroring the .NET work shipped in PR #5310 (.NET: Harness Feature branch) and follow-ups #5404, #5365, #5540. The harness is a set of context providers that make it easier to build long-running, plan-and-execute agents with persistent session state.

This PR introduces the Python counterpart of AgentModeProvider from dotnet/src/Microsoft.Agents.AI/Harness/AgentMode/.

Description

Adds the experimental _harness namespace and the first context provider in it: AgentModeProvider, with get_agent_mode / set_agent_mode helpers and a DEFAULT_MODE_SOURCE_ID constant. New HARNESS value added to the ExperimentalFeature enum; all new public symbols decorated with @experimental(ExperimentalFeature.HARNESS).

.NET Python (this PR)
AgentModeProvider AgentModeProvider
AgentModeProviderOptions.Modes available_modes / mode_descriptions kwargs
AgentMode_Get / AgentMode_Set tools get_mode / set_mode snake_case tools registered via @tool
GetMode / SetMode helpers get_agent_mode / set_agent_mode module-level helpers

The provider class name now matches .NET exactly as a refinement for cross-language consistency. The remaining differences are deliberate to match each language's conventions:

  • Python keeps kwargs-based construction rather than an options object.
  • Python tool names use snake_case.
  • Default mode list ("plan", "execute") and the default instruction template are aligned with .NET so cross-language behavior matches.

Also folds in a tiny cosmetic refactor of _sessions.py (try/except ImportError: passcontextlib.suppress(ImportError)) that was made while developing the harness.

This PR is the first of three splitting the _harness package work apart for review:

  1. (this PR) agent-mode context provider — mirrors .NET AgentModeProvider
  2. Python: Core: add experimental todo-list harness context provider #5612 — todo-list context provider — mirrors .NET TodoProvider
  3. Python: Core: add experimental memory harness context provider #5613 — memory context provider — related to but semantically distinct from .NET FileMemoryProvider

The three modules are independent. They share only the HARNESS enum entry and the (empty) _harness/__init__.py. Whichever lands first creates those; the others rebase trivially.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? No — gated behind @experimental(ExperimentalFeature.HARNESS).

Copilot AI review requested due to automatic review settings May 3, 2026 13:25
@moonbox3 moonbox3 added the python label May 3, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces the first experimental Python harness context provider in agent_framework: a session-backed mode provider that exposes get_mode / set_mode tools and helper APIs for reading and updating the current session mode. It extends the existing feature-staging system with a new HARNESS experimental feature and wires the new symbols into the package surface.

Changes:

  • Add SessionModeContextProvider plus session-mode helper APIs/constants under the new _harness namespace.
  • Export the new harness symbols from agent_framework.__init__ and add ExperimentalFeature.HARNESS.
  • Add focused tests for helper behavior, provider configuration, and tool-driven session mode updates; also refactor _sessions.py to use contextlib.suppress(ImportError).

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
python/packages/core/tests/core/test_harness_mode.py Adds tests for session-mode helpers, experimental metadata, and provider tools.
python/packages/core/agent_framework/_sessions.py Minor cleanup replacing try/except ImportError with suppress(ImportError).
python/packages/core/agent_framework/_harness/_mode.py Implements the new session-mode helpers and SessionModeContextProvider.
python/packages/core/agent_framework/_harness/__init__.py Creates the new harness package namespace.
python/packages/core/agent_framework/_feature_stage.py Adds the HARNESS experimental feature enum member.
python/packages/core/agent_framework/__init__.py Re-exports the new harness symbols from the public package API.

Comment thread python/packages/core/agent_framework/_harness/_mode.py Outdated
Comment thread python/packages/core/agent_framework/_harness/_mode.py Outdated
Comment thread python/packages/core/agent_framework/_harness/_mode.py
Comment thread python/packages/core/agent_framework/_harness/_mode.py Outdated
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 3 | Confidence: 89% | Result: All clear

Reviewed: Correctness, Security Reliability, Design Approach


Automated review by eavanvalkenburg's agents

@moonbox3
Copy link
Copy Markdown
Contributor

moonbox3 commented May 3, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _sessions.py3873391%102–104, 106–107, 124–125, 127–129, 206–207, 297, 558–562, 604, 607, 641, 690, 694, 704, 837, 853, 986, 1000–1001, 1024, 1046, 1056, 1098
packages/core/agent_framework/_harness
   _mode.py87198%61
TOTAL32200371188% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
6287 30 💤 0 ❌ 0 🔥 1m 44s ⏱️

@eavanvalkenburg eavanvalkenburg enabled auto-merge May 3, 2026 20:16
Comment thread python/packages/core/agent_framework/_harness/_mode.py
Comment thread python/packages/core/agent_framework/_harness/_mode.py Outdated
Comment thread python/packages/core/agent_framework/_harness/_mode.py
Comment thread python/packages/core/agent_framework/_harness/_mode.py
eavanvalkenburg and others added 5 commits May 5, 2026 10:46
Introduces the _harness namespace and the first context provider:
SessionModeContextProvider, with get_session_mode / set_session_mode
helpers and a DEFAULT_MODE_SOURCE_ID constant. Behind
@experimental(ExperimentalFeature.HARNESS).

Also folds in a small _sessions.py cleanup (try/except ImportError
-> contextlib.suppress) touched while developing the harness.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mirror the default mode descriptions and instruction template used
by the .NET AgentModeProvider so the cross-language harness UX is
consistent.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- json.dumps tool outputs to stay valid for arbitrary mode names
- normalize configured mode keys (lower+strip) so custom-cased configs work
- raise TypeError instead of silently replacing non-dict session state
- mark get_session_mode/set_session_mode as @experimental(HARNESS)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Match the .NET AgentModeProvider class name for cross-language
consistency. Helpers renamed accordingly: get_session_mode ->
get_agent_mode, set_session_mode -> set_agent_mode. The default
source_id is now "agent_mode". Construction pattern stays Pythonic
(kwargs, not an options object).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- default_mode now defaults to None and falls back to the first configured
  mode, decoupling the kwarg from the built-in 'plan'/'execute' set.
- get_agent_mode catches ValueError when a previously persisted mode is no
  longer in available_modes and resets to the default mode (matching the
  non-string recovery branch). Added regression coverage for both behaviors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eavanvalkenburg eavanvalkenburg added this pull request to the merge queue May 5, 2026
Merged via the queue into microsoft:main with commit d7ca9c8 May 5, 2026
33 checks passed
@eavanvalkenburg
Copy link
Copy Markdown
Member Author

Addressed reviewer feedback about external mode changes confusing the agent.

When the user changes the mode externally (e.g., via a slash-command), the chat history still shows a prior set_mode tool call from the agent. Updating just the system instructions wasn't enough — the model would anchor on the recent tool call and ignore the new mode.

Aligned with the .NET AgentModeProvider implementation:

  • set_agent_mode (the public helper used by external callers) now records the previous mode in provider state when it actually changes.
  • On the next before_run, AgentModeProvider pops that flag and injects a user-role notification message into the context (Mode changed: ... switched from "X" to "Y". You must now adjust your behavior...), so the most recent context unambiguously reflects the current mode.
  • The agent-driven set_mode tool path bypasses this — it writes current_mode directly so it doesn't trigger a redundant self-notification on its own change.

Tests cover: external change injects exactly one notification and clears the flag; a follow-up run without further changes does not re-inject; the agent's own set_mode tool does not queue a notification; and a no-op set_agent_mode(same_mode) does not queue one either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants