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}