Files
Ben Taylor e6d3629445 fix(sdk-python): emit tool call events for middleware-intercepted SDK Actions (#5372)
## Summary

Frontend SDK Actions intercepted by `CopilotKitMiddleware` could
disappear before the client received a tool-call lifecycle, leaving the
handler uncalled and the conversation without a tool result or follow-up
answer. The bridge now consumes the middleware's authoritative
intercepted-call state and publishes each call through the AG-UI adapter
at most once. The focused intercepted file has 8 tests and the manual
AG-UI file has 30 tests; the combined run is 38 tests, with the
supported-version matrix remaining CI-owned.

## Root cause

`CopilotKitMiddleware.after_model()` removes frontend calls before
LangChain's backend tool node and records those exact calls for
final-message restoration. The previous adapter fallback ignored that
state and reconstructed frontend ownership from `on_chat_model_end` plus
the run's action catalog. That duplicated classification, failed when an
action carried `function: None`, and never ran on Python 3.10 because
the async LangChain path emitted no model callbacks there.

## Changes

- `sdk-python/copilotkit/langgraph_agui_agent.py`
- publish middleware-classified calls from the existing chain-state
event path
- reuse one lifecycle materializer and the parent adapter's per-run ID
ledger
- remove raw model-end/action-schema reconstruction and the duplicate
logger assignment
- `sdk-python/tests/test_intercepted_tool_call_events.py`
- exercise the real `create_agent(..., tools=[])` middleware and AG-UI
path in streaming and non-streaming modes
- cover exactly-once identity, Python 3.10 restoration, multiple IDs,
metadata opt-out, backend negative space, and malformed action/state
shapes

## What is not changed

- backend tools still use LangChain's normal tool node
- `after_agent` still restores intercepted calls into the final
assistant snapshot
- tool-call emission metadata still controls streamed lifecycle
visibility
- explicit `copilotkit_emit_tool_call()` calls keep their existing
caller-controlled semantics

## Related PRs and Issues

Closes #4342.

## Test plan

- [x] Focused intercepted SDK Action regression file, 8 passed on Python
3.12. Covers the real `create_agent(..., tools=[])` path, streaming,
restoration, mixed ownership, chain metadata suppression, malformed
state, and action-shape isolation.
- [x] Existing manual tool-call materialization file, 30 passed on
Python 3.12.
- [x] Combined focused selection, 38 passed on Python 3.12, counted once
rather than adding a second 38-test total.
- [x] Ruff check and format check on both changed files, both passed.
- [ ] Python SDK CI matrix green on Python 3.10, 3.11, 3.12, 3.13, and
3.14
2026-08-17 12:58:37 -05:00
..
2025-02-28 12:21:54 +01:00
2026-05-28 14:39:07 -07:00

CopilotKit Python SDK

PyPI version License: MIT

The official Python SDK for CopilotKit - build AI copilots and agents into your applications.

Features

  • 🚀 Easy integration with LangGraph and LangChain
  • 🔄 Built-in support for stateful conversations
  • 🛠 Extensible agent framework
  • 🔌 FastAPI-ready endpoints
  • 🤝 Optional CrewAI integration

Installation

pip install copilotkit

With CrewAI support:

pip install "copilotkit[crewai]"

Quick Start

from copilotkit import Copilot

# Initialize a copilot
copilot = Copilot()

# Add your tools and configure the copilot
copilot.add_tool(my_custom_tool)

# Run the copilot
response = copilot.run("Your task description here")

Documentation

For detailed documentation and examples, visit copilotkit.ai

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support


Built with ❤️ by the CopilotKit team