anthropics / anthropics/claude-agent-sdk-python
feat: expose session context to SDK MCP tool handlers
- Ngôn ngữ chính
- Python
- Star
- 8.1k
- Fork
- 1.3k
- Merge trung bình
- 2 ngày 31 phút
- Pull request đã merge (30 ngày)
- 1
Mô tả
## Summary
Tool handlers registered via the `@tool` decorator currently only receive the tool's input arguments. There's no way for a tool to know which session it's running in, or to see the conversation that's happened so far. This issue proposes an opt-in `ToolContext` parameter that gives tool handlers read access to that information.
## Current behavior
The `@tool` decorator wraps a handler with this signature:
```python
@tool("my_tool", "description", {"arg": str})
async def my_tool(args: dict[str, Any]) -> dict[str, Any]:
...
```
The handler receives `args` and nothing else. If a tool needs to know:
- which session it's in (for logging, caching, deduplication keyed on session)
- what the user has already said or what other tools have returned in this session
The only workaround is to pass that information in as explicit tool arguments. That means Claude has to serialize parts of the conversation back into the tool call itself, which is awkward, token-expensive, and easy to get wrong.
## Use cases
A few concrete examples of tools that need this:
1. **Summarization tool** that produces a summary of the conversation so far. It needs to read the actual messages, not have them re-serialized into its arguments.
2. **Deduplication tool** that checks whether similar work was already done earlier in the same session before kicking off an expensive operation.
3. **Session-scoped logging or tracing tool** that wants to tag emitted events with the session ID.
4. **Tools that branch on prior tool results** (e.g., "if the linter already ran and passed, skip this step").
## Proposed API
Add an opt-in `ToolContext` dataclass that tool handlers can optionally declare as a second parameter:
```python
from claude_agent_sdk import tool, ToolContext
@tool("summarize", "Summarize the conversation so far", {})
async def summarize(args: dict[str, Any], context: ToolContext) -> dict[str, Any]:
history = context.get_conversation_history()
summary = produce_summary(history)
return {"content": [{"type": "text", "text": summary}]}
```
`ToolContext` would carry:
- `session_id: str` - the current session identifier
- `transcript_path: Path | None` - path to the session transcript on disk (for tools that want to do their own parsing)
- `get_conversation_history() -> list[dict]` - explicit method (not a property) that lazy-loads and parses the existing JSONL transcript
The history method is explicit (not a property) on purpose, so that the cost of reading and parsing the transcript is visible at the call site. Tools that only need `session_id` pay nothing for history they don't read.
## Detection and backward compatibility
Detection uses signature inspection: at registration time, check whether the handler declares a second parameter. Handlers that don't are wrapped exactly as today and see no behavior change.
```python
# Existing tools keep working unchanged.
@tool("old_style", "description", {})
async def old_style(args):
return {"content": [{"type": "text", "text": "ok"}]}
# New opt-in form.
@tool("new_style", "description", {})
async def new_style(args, context: ToolContext):
return {"content": [{"type": "text", "text": context.session_id}]}
```
No new dependencies. No changes to existing tool registration call sites. No changes to the MCP wire format.
## Implementation notes
- Plumbing uses a `contextvars.ContextVar` set just before the tool handler is invoked and reset afterward. This avoids threading a parameter through every call site in `query.py` and keeps the change additive.
- `get_conversation_history()` reads from the existing JSONL session transcript that the SDK already writes. No new storage mechanism.
- Returns `None` if called before any hooks have populated the context (best-effort API rather than a hard error).
## Related work
- #311 discusses a write-side context API (slots, redaction, mid-session prompt update). This proposal is the complementary read-only side and does not overlap. They can land independently.
## Status
Implementation is up as PR #824 for review.
Hướng dẫn đóng góp
Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này
Đánh giá
Issue này chưa được đánh giá.