Skip to main content

claude_code/
query_fn.rs

1//! Convenience function for one-off Claude Code queries.
2//!
3//! This module provides the [`query()`] function, which is the simplest way to
4//! send a prompt to Claude Code and receive all response messages. Each call
5//! creates a new session, sends the prompt, collects all messages, and closes
6//! the connection automatically.
7//!
8//! For multi-turn conversations, use [`ClaudeSdkClient`](crate::ClaudeSdkClient) instead.
9
10use crate::client::InputPrompt;
11use crate::errors::Result;
12use crate::internal_client::InternalClient;
13use crate::transport::Transport;
14use crate::types::{ClaudeAgentOptions, Message};
15use futures::Stream;
16use futures::stream::BoxStream;
17use serde_json::Value;
18
19/// Sends a one-off query to Claude Code and returns all response messages.
20///
21/// This is the simplest entry point for interacting with Claude Code. It handles
22/// the full lifecycle: connecting, initializing, sending the prompt, collecting
23/// all messages, and disconnecting.
24///
25/// # Arguments
26///
27/// * `prompt` — The input prompt (text or structured messages).
28/// * `options` — Optional [`ClaudeAgentOptions`] for configuration. Defaults to
29///   [`ClaudeAgentOptions::default()`] if `None`.
30/// * `transport` — Optional custom [`Transport`] implementation. If `None`,
31///   the default [`SubprocessCliTransport`](crate::SubprocessCliTransport) is used.
32///
33/// # Returns
34///
35/// A `Vec<Message>` containing all messages from the interaction, including
36/// user echoes, assistant responses, system messages, and the final result.
37///
38/// # Example
39///
40/// ```rust,no_run
41/// # use claude_code::{query, ClaudeAgentOptions, InputPrompt, Message, PermissionMode};
42/// # async fn example() -> claude_code::Result<()> {
43///     let messages = query(
44///     InputPrompt::Text("Explain Rust ownership".to_string()),
45///     Some(ClaudeAgentOptions {
46///         permission_mode: Some(PermissionMode::BypassPermissions),
47///         max_turns: Some(1),
48///         ..Default::default()
49///     }),
50///     None,
51///     ).await?;
52///
53///     for msg in &messages {
54///     if let Message::Result(result) = msg {
55///         println!("Cost: ${:.4}", result.total_cost_usd.unwrap_or(0.0));
56///     }
57///     }
58/// # Ok(())
59/// # }
60/// ```
61pub async fn query(
62    prompt: InputPrompt,
63    options: Option<ClaudeAgentOptions>,
64    transport: Option<Box<dyn Transport>>,
65) -> Result<Vec<Message>> {
66    let options = options.unwrap_or_default();
67    let client = InternalClient::new();
68    client.process_query(prompt, options, transport).await
69}
70
71/// Sends a one-off query using streamed JSON input messages.
72///
73/// This is a Rust-idiomatic equivalent of Python's `AsyncIterable` prompt mode.
74///
75/// # Example
76///
77/// ```rust,no_run
78/// use claude_code::{query_from_stream, ClaudeAgentOptions};
79/// use futures::stream;
80/// use serde_json::json;
81///
82/// # async fn example() -> claude_code::Result<()> {
83///     let messages = query_from_stream(
84///     stream::iter(vec![json!({"type":"user","message":{"role":"user","content":"hello"}})]),
85///     Some(ClaudeAgentOptions::default()),
86///     None,
87///     )
88///     .await?;
89///
90///     assert!(!messages.is_empty());
91/// # Ok(())
92/// # }
93/// ```
94pub async fn query_from_stream<S>(
95    prompt: S,
96    options: Option<ClaudeAgentOptions>,
97    transport: Option<Box<dyn Transport>>,
98) -> Result<Vec<Message>>
99where
100    S: Stream<Item = Value> + Unpin,
101{
102    let options = options.unwrap_or_default();
103    let client = InternalClient::new();
104    client
105        .process_query_from_stream(prompt, options, transport)
106        .await
107}
108
109/// Sends a one-off query and returns responses as a stream.
110///
111/// The returned stream yields parsed [`Message`] values as they arrive.
112///
113/// The stream is `Send` and can be consumed from any tokio task.
114///
115/// # Example
116///
117/// ```rust,no_run
118/// use claude_code::{query_stream, InputPrompt};
119/// use futures::StreamExt;
120///
121/// # async fn example() -> claude_code::Result<()> {
122///     let mut stream = query_stream(
123///     InputPrompt::Text("Summarize Rust ownership".to_string()),
124///     None,
125///     None,
126///     )
127///     .await?;
128///
129///     let _ = stream.next().await;
130/// # Ok(())
131/// # }
132/// ```
133pub async fn query_stream(
134    prompt: InputPrompt,
135    options: Option<ClaudeAgentOptions>,
136    transport: Option<Box<dyn Transport>>,
137) -> Result<BoxStream<'static, Result<Message>>> {
138    let options = options.unwrap_or_default();
139    let client = InternalClient::new();
140    client
141        .process_query_as_stream(prompt, options, transport)
142        .await
143}
144
145/// Sends a one-off query with streamed input and streamed output.
146///
147/// The returned stream is `Send` and can be consumed from any tokio task.
148///
149/// # Example
150///
151/// ```rust,no_run
152/// use claude_code::query_stream_from_stream;
153/// use futures::{stream, StreamExt};
154/// use serde_json::json;
155///
156/// # async fn example() -> claude_code::Result<()> {
157///     let mut output = query_stream_from_stream(
158///     stream::iter(vec![json!({"type":"user","message":{"role":"user","content":"hello"}})]),
159///     None,
160///     None,
161///     )
162///     .await?;
163///
164///     let _ = output.next().await;
165/// # Ok(())
166/// # }
167/// ```
168pub async fn query_stream_from_stream<S>(
169    prompt: S,
170    options: Option<ClaudeAgentOptions>,
171    transport: Option<Box<dyn Transport>>,
172) -> Result<BoxStream<'static, Result<Message>>>
173where
174    S: Stream<Item = Value> + Unpin,
175{
176    let options = options.unwrap_or_default();
177    let client = InternalClient::new();
178    client
179        .process_query_from_stream_as_stream(prompt, options, transport)
180        .await
181}