feat: vibed out some slop over here also
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
"""Minimal end-to-end example: one turn against a real `claude` CLI.
|
||||
|
||||
Prerequisites:
|
||||
1. `claude` is on PATH and the user is logged in (`claude /login` once).
|
||||
2. Your subscription is healthy (no rate limit, no auth block).
|
||||
|
||||
Run:
|
||||
python examples/basic_usage.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from claude_code_api import (
|
||||
AssistantMessage,
|
||||
BackendOptions,
|
||||
ClaudeCodeBackend,
|
||||
ResultMessage,
|
||||
TextBlock,
|
||||
)
|
||||
|
||||
CWD = Path(os.environ.get("CLAUDE_CODE_CWD", Path.cwd())).resolve()
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
opts = BackendOptions(cwd=str(CWD), dangerously_skip_permissions=True)
|
||||
async with ClaudeCodeBackend(opts) as backend:
|
||||
async for event in backend.complete(
|
||||
[{"role": "user", "content": "Reply with the single word: OK"}]
|
||||
):
|
||||
if isinstance(event, AssistantMessage):
|
||||
for block in event.content:
|
||||
if isinstance(block, TextBlock):
|
||||
print(f"[assistant] {block.text.strip()}")
|
||||
elif isinstance(event, ResultMessage):
|
||||
print(
|
||||
f"[result] stop_reason={event.stop_reason} "
|
||||
f"duration_ms={event.duration_ms}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Tool calling via a stdio MCP server.
|
||||
|
||||
`BackendOptions.mcp_servers` materializes into a temp `--mcp-config` JSON
|
||||
file under the hood. The model decides when to invoke the tool, claude's
|
||||
TUI runs the round-trip, and the events stream surfaces a `ToolUseBlock`
|
||||
plus its `ToolResultBlock`.
|
||||
|
||||
This example wires the bundled echo server at `scripts/echo_mcp_server.py`
|
||||
— same one the smoke test uses.
|
||||
|
||||
Run:
|
||||
python examples/mcp_tool.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from claude_code_api import (
|
||||
AssistantMessage,
|
||||
BackendOptions,
|
||||
ClaudeCodeBackend,
|
||||
ResultMessage,
|
||||
TextBlock,
|
||||
ToolResultBlock,
|
||||
ToolUseBlock,
|
||||
UserMessage,
|
||||
)
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
ECHO_SCRIPT = REPO_ROOT / "scripts" / "echo_mcp_server.py"
|
||||
CWD = Path(os.environ.get("CLAUDE_CODE_CWD", Path.cwd())).resolve()
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
opts = BackendOptions(
|
||||
cwd=str(CWD),
|
||||
dangerously_skip_permissions=True,
|
||||
mcp_servers={
|
||||
"echo": {"command": sys.executable, "args": [str(ECHO_SCRIPT)]},
|
||||
},
|
||||
)
|
||||
async with ClaudeCodeBackend(opts) as backend:
|
||||
prompt = (
|
||||
"Call the `mcp__echo__echo` tool with text='ping' and then "
|
||||
"tell me what it returned. Reply with one short sentence."
|
||||
)
|
||||
async for event in backend.complete([{"role": "user", "content": prompt}]):
|
||||
if isinstance(event, AssistantMessage):
|
||||
for block in event.content:
|
||||
if isinstance(block, TextBlock) and block.text.strip():
|
||||
print(f"[assistant] {block.text.strip()}")
|
||||
elif isinstance(block, ToolUseBlock):
|
||||
print(f"[tool_use] {block.name}({block.input})")
|
||||
elif isinstance(event, UserMessage) and isinstance(event.content, list):
|
||||
for block in event.content:
|
||||
if isinstance(block, ToolResultBlock):
|
||||
print(f"[tool_res] {block.content!r}")
|
||||
elif isinstance(event, ResultMessage):
|
||||
print(f"[result] stop_reason={event.stop_reason}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,69 @@
|
||||
"""Multi-turn: same backend, two turns, context persists across the pair.
|
||||
|
||||
The backend fingerprints `messages[:-1]` against its pool of live PTYs.
|
||||
After turn 1 finishes, we re-send the conversation with the assistant's
|
||||
reply appended and one new user message — fingerprint matches, the same
|
||||
process is reused, and the server-side prompt cache keeps the context
|
||||
without us paying a fresh-spawn tax.
|
||||
|
||||
Run:
|
||||
python examples/multi_turn.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from claude_code_api import (
|
||||
AssistantMessage,
|
||||
BackendOptions,
|
||||
ClaudeCodeBackend,
|
||||
ResultMessage,
|
||||
TextBlock,
|
||||
)
|
||||
|
||||
CWD = Path(os.environ.get("CLAUDE_CODE_CWD", Path.cwd())).resolve()
|
||||
|
||||
|
||||
def assistant_text(events: list[Any]) -> str:
|
||||
for ev in reversed(events):
|
||||
if isinstance(ev, AssistantMessage):
|
||||
return "".join(b.text for b in ev.content if isinstance(b, TextBlock)).strip()
|
||||
return ""
|
||||
|
||||
|
||||
async def run_turn(
|
||||
backend: ClaudeCodeBackend, history: list[dict[str, Any]]
|
||||
) -> str:
|
||||
events: list[Any] = []
|
||||
async for event in backend.complete(history):
|
||||
events.append(event)
|
||||
if isinstance(event, ResultMessage):
|
||||
print(f" → stop_reason={event.stop_reason} duration_ms={event.duration_ms}")
|
||||
return assistant_text(events)
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
opts = BackendOptions(cwd=str(CWD), dangerously_skip_permissions=True)
|
||||
async with ClaudeCodeBackend(opts) as backend:
|
||||
history: list[dict[str, Any]] = [
|
||||
{"role": "user", "content": "Remember the codeword: Beaver. Reply OK."}
|
||||
]
|
||||
print("[turn 1]")
|
||||
reply1 = await run_turn(backend, history)
|
||||
print(f" [assistant] {reply1}")
|
||||
|
||||
history += [
|
||||
{"role": "assistant", "content": [{"type": "text", "text": reply1}]},
|
||||
{"role": "user", "content": "What was the codeword? Reply with one word."},
|
||||
]
|
||||
print("[turn 2]")
|
||||
reply2 = await run_turn(backend, history)
|
||||
print(f" [assistant] {reply2}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user