Skip to main content

deepseek/agent/
pricing.rs

1//! Per-model USD pricing for cost reporting.
2//!
3//! Values in $ per 1M tokens. Returns `None` for unknown models so that the
4//! caller can set `total_cost_usd = None`. Public DeepSeek list pricing as of
5//! late 2025 — adjust as needed.
6
7pub struct ModelPricing {
8    pub input_per_mtok: f64,
9    pub output_per_mtok: f64,
10}
11
12pub fn model_pricing(model: &str) -> Option<ModelPricing> {
13    let m = model.to_lowercase();
14    let p = match m.as_str() {
15        "deepseek-v4-pro" | "deepseek-v4" => (0.55, 2.19),
16        "deepseek-v4-flash" => (0.14, 0.55),
17        "deepseek-reasoner" | "deepseek-r1" => (0.55, 2.19),
18        "deepseek-chat" | "deepseek-v3" => (0.27, 1.10),
19        _ => return None,
20    };
21    Some(ModelPricing {
22        input_per_mtok: p.0,
23        output_per_mtok: p.1,
24    })
25}
26
27/// Convert a turn's `UsageInfo` into a USD cost given the model. Returns
28/// `None` if pricing is unknown.
29pub fn turn_cost_usd(model: &str, prompt_tokens: u32, completion_tokens: u32) -> Option<f64> {
30    let p = model_pricing(model)?;
31    let cost = (prompt_tokens as f64 / 1_000_000.0) * p.input_per_mtok
32        + (completion_tokens as f64 / 1_000_000.0) * p.output_per_mtok;
33    Some(cost)
34}
35
36/// Map OpenAI `finish_reason` to a Claude-style `stop_reason`.
37pub fn map_stop_reason(finish_reason: &str) -> Option<String> {
38    let r = match finish_reason {
39        "stop" => "end_turn",
40        "tool_calls" => "tool_use",
41        "length" => "max_tokens",
42        "content_filter" => "refusal",
43        _ => return Some(finish_reason.to_string()),
44    };
45    Some(r.to_string())
46}