SDK Integration¶
Current Implementation¶
The current implementation uses the Claude CLI in --print mode:
cmd = [
"claude",
"--print",
"--dangerously-skip-permissions",
prompt,
]
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=session.cwd,
)
This approach:
- Uses
--printto get plain text output - Uses
--dangerously-skip-permissionsfor non-interactive use - Streams output line by line back to Telegram
- Uses Claude CLI's own authentication (via
claude login)
Authentication¶
Claude CLI handles its own authentication. Before running voice-agent:
claude login
This stores credentials that the CLI uses automatically.
Future: Claude Agent SDK¶
The plan is to migrate to the official Claude Agent SDK for:
- Structured responses: Native message types instead of text parsing
- Permission callbacks:
canUseToolcallback for approval flow - Session persistence: Resume sessions via
session_id
Planned SDK Usage¶
from claude_code_sdk import ClaudeCodeClient
async def can_use_tool(tool_name: str, input_data: dict) -> bool:
if is_safe_tool_call(tool_name, input_data):
return True
# Queue for user approval
await notify_user(tool_name, input_data)
return await wait_for_approval()
client = ClaudeCodeClient(
cwd="/code/project",
can_use_tool=can_use_tool,
)
async for message in client.query("list files"):
process_message(message)
Benefits of SDK¶
| CLI Approach | SDK Approach |
|---|---|
| Parse text output | Structured message objects |
--dangerously-skip-permissions |
canUseTool callback |
| Text streaming | Typed message objects |
| One process per prompt | Persistent client instance |
Migration Path¶
- Keep CLI implementation as fallback
- Add SDK client alongside CLI
- Switch based on configuration/availability
- Remove CLI fallback once SDK is stable