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## Agent with a tool
31```no_run
32use ds_api::{AgentEvent, DeepseekAgent, tool};
33use futures::StreamExt;
34use serde_json::{Value, json};
35
36struct EchoTool;
37
38#[tool]
39impl ds_api::Tool for EchoTool {
40 /// Echo the input back.
41 /// input: the string to echo
42 async fn echo(&self, input: String) -> Value {
43 json!({ "echo": input })
44 }
45}
46
47#[tokio::main]
48async fn main() {
49 let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
50 let mut stream = DeepseekAgent::new(token).add_tool(EchoTool).chat("Please echo: hello");
51 while let Some(event) = stream.next().await {
52 match event {
53 Err(e) => { eprintln!("Error: {e}"); break; }
54 Ok(AgentEvent::Token(text)) => println!("Assistant: {text}"),
55 Ok(AgentEvent::ToolCall(c)) => println!("calling {}({})", c.name, c.delta),
56 Ok(AgentEvent::ToolResult(r)) => println!("result: {} -> {}", r.name, r.result),
57 Ok(_) => {}
58 }
59 }
60}
61```
62
63## Injecting messages mid-run
64
65[`DeepseekAgent::with_interrupt_channel`] returns a sender you can use to push
66messages into the agent while it's still running. Messages are picked up after
67the current tool-execution round and added to the conversation before the next
68API turn.
69
70```no_run
71use ds_api::{AgentEvent, DeepseekAgent, tool};
72use futures::StreamExt;
73use serde_json::{Value, json};
74use tokio::time::{Duration, sleep};
75
76struct SlowTool;
77
78#[tool]
79impl ds_api::Tool for SlowTool {
80 /// Do some slow work and return a result.
81 async fn slow_work(&self) -> Value {
82 sleep(Duration::from_secs(1)).await;
83 json!({ "status": "done" })
84 }
85}
86
87#[tokio::main]
88async fn main() {
89 let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
90
91 // Build the agent and obtain the sender half of the interrupt channel.
92 let (agent, tx) = DeepseekAgent::new(token)
93 .with_streaming()
94 .add_tool(SlowTool)
95 .with_interrupt_channel();
96
97 // Inject a follow-up message from another task while tools are running.
98 tokio::spawn(async move {
99 sleep(Duration::from_millis(500)).await;
100 tx.send("Actually, please summarise the result in one sentence.".into()).unwrap();
101 });
102
103 let mut stream = agent.chat("Please run slow_work.");
104 while let Some(event) = stream.next().await {
105 match event {
106 Err(e) => { eprintln!("Error: {e}"); break; }
107 Ok(AgentEvent::Token(text)) => print!("{text}"),
108 Ok(AgentEvent::ToolCall(c)) => { if c.delta.is_empty() { println!("\n[calling {}]", c.name) } }
109 Ok(AgentEvent::ToolResult(r)) => println!("\n[result] {}", r.result),
110 Ok(_) => {}
111 }
112 }
113}
114```
115
116See the crate README and the `interrupt` example for more details.
117
118## Inspecting conversation history
119
120After recovering the agent from a finished stream you can read the full
121conversation history with [`DeepseekAgent::history`]:
122
123```no_run
124use ds_api::DeepseekAgent;
125use futures::StreamExt;
126
127# #[tokio::main] async fn main() {
128let token = std::env::var("DEEPSEEK_API_KEY").expect("DEEPSEEK_API_KEY must be set");
129let mut stream = DeepseekAgent::new(token).chat("Hello!");
130while let Some(_) = stream.next().await {}
131
132if let Some(agent) = stream.into_agent() {
133 for msg in agent.history() {
134 println!("{:?}: {:?}", msg.role, msg.content);
135 }
136}
137# }
138```
139
140See the crate README for more examples and migration notes.
141*/
142
143pub mod agent;
144pub mod api;
145pub mod conversation;
146pub mod error;
147#[cfg(feature = "mcp")]
148pub mod mcp;
149pub mod raw; // raw types remain accessible via `ds_api::raw` but are not the primary public API
150pub mod tool_trait;
151
152pub use agent::{AgentEvent, DeepseekAgent, ToolCallChunk, ToolCallResult};
153pub use api::{ApiClient, ApiRequest};
154pub use conversation::{Conversation, LlmSummarizer, SlidingWindowSummarizer};
155pub use error::ApiError;
156
157pub use tool_trait::Tool;
158
159pub use ds_api_macros::tool;
160
161#[cfg(feature = "mcp")]
162pub use mcp::McpTool;