Skip to content

Python: Add tool concurrency groups and sequential execution order for same-message calls - #7523

Open
PratikWayase wants to merge 2 commits into
microsoft:mainfrom
PratikWayase:feat/serialize-same-message-function-calls
Open

Python: Add tool concurrency groups and sequential execution order for same-message calls#7523
PratikWayase wants to merge 2 commits into
microsoft:mainfrom
PratikWayase:feat/serialize-same-message-function-calls

Conversation

@PratikWayase

Copy link
Copy Markdown
Contributor

Motivation & Context

Currently, the framework executes all tool calls requested in a single assistant message concurrently. While this is a great default for independent calls (like parallel document lookups), models routinely emit dependent calls in one batch (e.g., "write the file, then read it"). Because the tool author has no way to serialize these calls, dependent reads race the still-running writes, leading to "not found" errors and contradictory agent states.

This PR closes that gap by providing declarative, framework-level control over tool execution order, preventing stateful tool race conditions without relying on fragile, tool-side asyncio.Lock workarounds.

Fixes #7386

Description & Review Guide

  • What are the major changes?

    1. Per-Tool Serialization Group: Added an optional concurrency_group: str parameter to FunctionTool and the @tool decorator. Tools sharing the same concurrency_group execute sequentially in call order within a message batch, while ungrouped tools remain fully concurrent.
    2. Run-Level Sequential Execution: Added tool_execution_order: Literal["parallel", "sequential"] to _ChatOptionsBase and FunctionInvocationConfiguration. Setting this to "sequential" forces all tool calls in a batch to execute one-by-one.
    3. API Wiring: Wired the user-facing tool_execution_order chat option through the FunctionInvocationLayer down to the execution engine so the setting actually takes effect at runtime.
    4. Serialization & Docs: Updated FunctionTool.to_dict() to ensure concurrency_group survives serialization, and added docstrings documenting the ordering guarantee (specifically requested in the issue).
  • What is the impact of these changes?
    This is fully backward compatible. The default behavior remains "parallel" with no concurrency_group set, ensuring existing agents behave exactly as before. It provides tool authors a safe, declarative way to handle stateful dependencies.

  • What do you want reviewers to focus on?
    Please review the grouping algorithm in _try_execute_function_call_groups (_tools.py). Specifically, verify that the ordered_results array correctly maps indices to ensure results are returned in the exact order the model requested them, and that contextvars.copy_context() is still applied correctly per-call to preserve agent span observability.

Related Issue

Fixes #7386

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.

Copilot AI lite review requested due to automatic review settings August 5, 2026 10:27
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Aug 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 adds framework-level controls to prevent same-message tool-call race conditions in the Python core by allowing (a) per-tool serialization via concurrency groups and (b) run-level sequential execution of all tool calls in a batch.

Changes:

  • Added concurrency_group: str | None to FunctionTool and the @tool decorator, enabling sequential execution for tools sharing a group within a single message batch.
  • Added tool_execution_order: Literal["parallel","sequential"] to chat options and function invocation configuration, and wired it through to the function-call execution layer.
  • Added unit tests covering concurrency-group serialization and sequential execution behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
python/packages/core/agent_framework/_tools.py Adds concurrency-group metadata, serializes it, and implements grouped/sequential function-call execution and option wiring.
python/packages/core/agent_framework/_types.py Extends chat options with tool_execution_order to expose the configuration at the API surface.
python/packages/core/tests/core/test_tools.py Adds tests validating concurrency-group handling and sequential tool execution order.

Comment thread python/packages/core/agent_framework/_tools.py
Comment thread python/packages/core/agent_framework/_tools.py Outdated
Comment thread python/packages/core/agent_framework/_tools.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Feature]: No way to serialize (or order) same-message function calls — stateful tools with write→read dependencies race

2 participants