Skip to main content

ds_api/
lib.rs

1/*!
2ds-api — Rust client for DeepSeek
3
4# Quickstart
5
6## Simple non-streaming request
7```no_run
8use ds_api::{ApiClient, ApiRequest};
9use ds_api::raw::request::message::Message;
10
11#[tokio::main]
12async fn main() -> Result<(), Box<dyn std::error::Error>> {
13    // Set DEEPSEEK_API_KEY in your environment before running this example.
14    let token = std::env::var("DEEPSEEK_API_KEY")?;
15    let client = ApiClient::new(token);
16
17    let req = ApiRequest::deepseek_chat(vec![
18        Message::new(ds_api::raw::request::message::Role::User, "Hello from Rust"),
19    ])
20    .max_tokens(150)
21    .json();
22
23    let resp = client.send(req).await?;
24    // Print debug representation of the response; adapt to your needs.
25    println!("Response: {:?}", resp);
26    Ok(())
27}
28```
29
30## DeepseekAgent with a minimal tool
31```no_run
32use ds_api::{AgentEvent, DeepseekAgent, tool};
33use futures::StreamExt;
34use serde::Serialize;
35
36struct EchoTool;
37
38#[derive(Serialize)]
39struct EchoResponse {
40    echo: String,
41}
42
43#[tool]
44impl ds_api::Tool for EchoTool {
45    /// Echo the input back.
46    /// input: the string to echo
47    async fn echo(&self, input: String) -> EchoResponse {
48        EchoResponse { echo: input }
49    }
50}
51
52#[tokio::main]
53async fn main() {
54    // Ensure DEEPSEEK_API_KEY is set in your environment before running this example.
55    let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
56    let agent = DeepseekAgent::new(token).add_tool(EchoTool);
57
58    // The agent returns a stream of `AgentEvent` items. Each variant represents
59    // a distinct event: assistant text, a tool call request, or a tool result.
60    let mut s = agent.chat("Please echo: hello");
61    while let Some(event) = s.next().await {
62        match event {
63            Err(e) => { eprintln!("Error: {e}"); break; }
64            Ok(AgentEvent::Token(text)) => println!("Assistant: {}", text),
65            Ok(AgentEvent::ToolCall(c)) => println!("Tool call: {}({})", c.name, c.args),
66            Ok(AgentEvent::ToolResult(r)) => println!("Result: {} -> {}", r.name, r.result),
67        }
68    }
69}
70```
71
72## Injecting user messages mid-loop
73
74Use [`DeepseekAgent::with_interrupt_channel`] to get an [`InterruptSender`].
75Send messages through it at any time; they are picked up automatically after
76the current tool-execution round and appended to the conversation history as
77`Role::User` before the next API turn.
78
79```no_run
80use ds_api::{AgentEvent, DeepseekAgent, tool};
81use futures::StreamExt;
82use serde_json::{Value, json};
83use tokio::time::{Duration, sleep};
84
85struct SlowTool;
86
87#[tool]
88impl ds_api::Tool for SlowTool {
89    /// Do some slow work and return a result.
90    async fn slow_work(&self) -> Value {
91        sleep(Duration::from_secs(1)).await;
92        json!({ "status": "done" })
93    }
94}
95
96#[tokio::main]
97async fn main() {
98    let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
99
100    // Build the agent and obtain the sender half of the interrupt channel.
101    let (agent, tx) = DeepseekAgent::new(token)
102        .with_streaming()
103        .add_tool(SlowTool)
104        .with_interrupt_channel();
105
106    // Inject a follow-up message from another task while tools are running.
107    tokio::spawn(async move {
108        sleep(Duration::from_millis(500)).await;
109        tx.send("Actually, please summarise the result in one sentence.".into()).unwrap();
110    });
111
112    let mut stream = agent.chat("Please run slow_work.");
113    while let Some(event) = stream.next().await {
114        match event {
115            Err(e) => { eprintln!("Error: {e}"); break; }
116            Ok(AgentEvent::Token(text))   => print!("{text}"),
117            Ok(AgentEvent::ToolCall(c))   => println!("\n[calling {}]", c.name),
118            Ok(AgentEvent::ToolResult(r)) => println!("\n[result] {}", r.result),
119        }
120    }
121}
122```
123
124See the crate README and the `interrupt` example for more details.
125
126## Inspecting conversation history
127
128After recovering the agent from a finished stream you can read the full
129conversation history with [`DeepseekAgent::history`]:
130
131```no_run
132use ds_api::DeepseekAgent;
133use futures::StreamExt;
134
135# #[tokio::main] async fn main() {
136let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
137let mut stream = DeepseekAgent::new(token).chat("Hello!");
138while let Some(_) = stream.next().await {}
139
140if let Some(agent) = stream.into_agent() {
141    for msg in agent.history() {
142        println!("{:?}: {:?}", msg.role, msg.content);
143    }
144}
145# }
146```
147
148See the crate README for more examples and migration notes.
149*/
150
151pub mod agent;
152pub mod api;
153pub mod conversation;
154pub mod error;
155pub mod raw; // raw types remain accessible via `ds_api::raw` but are not the primary public API
156pub mod tool_trait;
157
158pub use agent::{AgentEvent, DeepseekAgent, ToolCallInfo, ToolCallResult};
159pub use api::{ApiClient, ApiRequest};
160pub use conversation::{Conversation, LlmSummarizer, SlidingWindowSummarizer};
161pub use error::ApiError;
162
163pub use tool_trait::Tool;
164
165pub use ds_api_macros::tool;