port query() and Client
Two entry points mirroring the Python SDK's surface: - query(prompt, options) returns an impl Stream<Item = Result<Message>> that terminates after the CLI emits its terminal result message. The stream owns the underlying Client and tears down the subprocess via a spawned disconnect task either on Result observation or on Drop. - Client (mirror of ClaudeSDKClient) supports bidirectional multi-turn sessions: connect, send (or send_raw for tool-result frames), drain the messages stream, repeat. Drop is intentionally a no-op for the subprocess — callers should call disconnect() for a clean shutdown that surfaces non-zero exit codes as Error::Process. lib.rs re-exports the public API and carries the crate-level docs + quick-start example. The v0.1 / v0.2 split is documented inline: control protocol (interrupt, set_permission_mode, etc.), can_use_tool, in-process MCP servers, HookMatcher, SessionStore, sandbox, plugins, and the agents dataclass are all deferred.
This commit is contained in:
parent
2f975a190b
commit
6fab3d4581
3 changed files with 492 additions and 0 deletions
132
src/lib.rs
Normal file
132
src/lib.rs
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
//! Async Rust SDK for the Claude Agent CLI.
|
||||
//!
|
||||
//! This crate is a Rust port of the official Python
|
||||
//! [`claude-agent-sdk`](https://github.com/anthropics/claude-agent-sdk-python).
|
||||
//! It wraps the `claude` CLI as a subprocess and exposes its
|
||||
//! newline-delimited JSON stream as ergonomic Rust types.
|
||||
//!
|
||||
//! # Quick start
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use claude_agent_sdk::{query, ClaudeAgentOptions, Message, ContentBlock};
|
||||
//! use tokio_stream::StreamExt;
|
||||
//!
|
||||
//! #[tokio::main]
|
||||
//! async fn main() -> claude_agent_sdk::Result<()> {
|
||||
//! let opts = ClaudeAgentOptions::new()
|
||||
//! .with_system_prompt("You are a helpful assistant.")
|
||||
//! .with_max_turns(1);
|
||||
//!
|
||||
//! let mut stream = query("What is 2 + 2?", opts).await?;
|
||||
//!
|
||||
//! while let Some(msg) = stream.next().await {
|
||||
//! match msg? {
|
||||
//! Message::Assistant(a) => {
|
||||
//! for block in a.message.content {
|
||||
//! if let ContentBlock::Text(t) = block {
|
||||
//! println!("Claude: {}", t.text);
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! Message::Result(r) => {
|
||||
//! if let Some(usd) = r.total_cost_usd {
|
||||
//! println!("Cost: ${:.4}", usd);
|
||||
//! }
|
||||
//! break;
|
||||
//! }
|
||||
//! _ => {}
|
||||
//! }
|
||||
//! }
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! # Two entry points
|
||||
//!
|
||||
//! - [`query`] — one-shot prompts. Returns a stream that ends when the CLI
|
||||
//! emits its terminal `result` message, automatically tearing down the
|
||||
//! subprocess.
|
||||
//! - [`Client`] — bidirectional, multi-turn sessions. Lets you send
|
||||
//! follow-up prompts in response to assistant messages, mirroring the
|
||||
//! Python SDK's `ClaudeSDKClient`.
|
||||
//!
|
||||
//! # Configuration
|
||||
//!
|
||||
//! Configure both entry points via [`ClaudeAgentOptions`]. It uses a builder
|
||||
//! pattern — chain `.with_*()` methods on a default value:
|
||||
//!
|
||||
//! ```
|
||||
//! use claude_agent_sdk::{ClaudeAgentOptions, PermissionMode};
|
||||
//!
|
||||
//! let opts = ClaudeAgentOptions::new()
|
||||
//! .with_model("claude-sonnet-4-5")
|
||||
//! .with_permission_mode(PermissionMode::AcceptEdits)
|
||||
//! .with_allowed_tool("Read")
|
||||
//! .with_allowed_tool("Bash")
|
||||
//! .with_cwd("/tmp/my-project")
|
||||
//! .with_max_turns(5);
|
||||
//! ```
|
||||
//!
|
||||
//! See [`ClaudeAgentOptions`] for the full list of supported fields.
|
||||
//!
|
||||
//! # Field naming
|
||||
//!
|
||||
//! The CLI wire protocol is `snake_case`, so deserialized field names match
|
||||
//! the Python SDK directly (`session_id`, `total_cost_usd`, `tool_use_id`,
|
||||
//! etc.). Where the wire used `camelCase` historically — `modelUsage` — we
|
||||
//! preserve it via `#[serde(rename = "...")]` rather than blanket-renaming
|
||||
//! the container.
|
||||
//!
|
||||
//! # v0.1 scope and known limitations
|
||||
//!
|
||||
//! The v0.1 port covers the core path of the Python SDK:
|
||||
//!
|
||||
//! - Subprocess transport with newline-delimited JSON framing.
|
||||
//! - All message and content-block types parsed faithfully.
|
||||
//! - `query()` + `Client` for one-shot and bidirectional use.
|
||||
//! - The full `ClaudeAgentOptions` flag surface relevant to subprocess args.
|
||||
//!
|
||||
//! Deferred to v0.2 — see the upstream README for the current shape of these
|
||||
//! features in Python:
|
||||
//!
|
||||
//! - **Control protocol over JSON-RPC**: `interrupt()`, `set_permission_mode()`,
|
||||
//! `set_model()`, `get_mcp_status()`, etc. The Rust [`Client`] today only
|
||||
//! speaks the bare user / assistant / result frames.
|
||||
//! - **`can_use_tool` permission callback**: requires the control protocol.
|
||||
//! - **`@tool` decorator / `create_sdk_mcp_server()`**: in-process MCP
|
||||
//! servers — needs a derive macro or trait shape, deferred until
|
||||
//! downstream demand is clearer.
|
||||
//! - **`HookMatcher`** and hook callbacks: the wire format is supported
|
||||
//! (initialize-payload + hook_callback responses) but the Rust callback
|
||||
//! surface is not designed yet.
|
||||
//! - **`SessionStore`** mirroring adapter trait.
|
||||
//! - **`Sandbox` settings**, **plugins**, **agents** dataclass.
|
||||
//!
|
||||
//! These all degrade gracefully — the CLI ignores absent stdin frames, so
|
||||
//! a v0.1 caller using a `claude` build that supports control requests will
|
||||
//! simply see fewer features than the Python SDK exposes.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
|
||||
mod client;
|
||||
mod errors;
|
||||
mod messages;
|
||||
mod options;
|
||||
mod query;
|
||||
mod transport;
|
||||
|
||||
pub use client::Client;
|
||||
pub use errors::{Error, Result};
|
||||
pub use messages::{
|
||||
AssistantMessage, AssistantMessageInner, ContentBlock, Message, ResultMessage,
|
||||
ServerToolResultBlock, ServerToolUseBlock, StreamEventMessage, SystemMessage, TextBlock,
|
||||
ThinkingBlock, ToolResultBlock, ToolUseBlock, UserContent, UserMessage, UserMessageInner,
|
||||
};
|
||||
pub use options::{ClaudeAgentOptions, Effort, McpServersConfig, PermissionMode, SystemPrompt};
|
||||
pub use query::query;
|
||||
pub use transport::SubprocessTransport;
|
||||
|
||||
/// Crate version, as set in `Cargo.toml`. Sent to the CLI as
|
||||
/// `CLAUDE_AGENT_SDK_VERSION` in the subprocess env.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
Loading…
Add table
Add a link
Reference in a new issue