rig_core/providers/moonshot/
extension.rs1use serde::Serialize;
15use serde_json::Value;
16
17use crate::completion::provider_options::reply_field;
18use crate::completion::{ExtensionOptions, ProviderExtension, ReplyExtras};
19use crate::message::Api;
20use crate::providers::anthropic::extension::MessagesStop;
21use crate::providers::anthropic::wire::MESSAGES_API;
22
23#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
25pub struct MoonshotExt;
26
27impl ProviderExtension for MoonshotExt {
28 const PROVIDER: &'static str = super::PROVIDER_NAME;
29 type Options = MoonshotOptions;
30 type Extras = MoonshotExtras;
31}
32
33#[non_exhaustive]
37#[derive(Clone, Debug, Default, PartialEq, Serialize)]
38pub struct MoonshotOptions {
39 #[serde(rename = "openai.chat")]
41 pub chat: MoonshotChat,
42}
43
44impl MoonshotOptions {
45 pub fn new() -> Self {
47 Self::default()
48 }
49
50 pub fn chat(mut self, chat: MoonshotChat) -> Self {
52 self.chat = chat;
53 self
54 }
55
56 pub fn thinking_keep(mut self, keep: ThinkingKeep) -> Self {
59 self.chat = std::mem::take(&mut self.chat).thinking_keep(keep);
60 self
61 }
62
63 pub fn prompt_cache_key(mut self, key: impl Into<String>) -> Self {
66 self.chat = std::mem::take(&mut self.chat).prompt_cache_key(key);
67 self
68 }
69}
70
71impl ExtensionOptions for MoonshotOptions {
72 type Ext = MoonshotExt;
73}
74
75#[non_exhaustive]
77#[derive(Clone, Debug, Default, PartialEq, Serialize)]
78pub struct MoonshotChat {
79 #[serde(skip_serializing_if = "MoonshotThinking::is_empty")]
81 pub thinking: MoonshotThinking,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub prompt_cache_key: Option<String>,
85}
86
87#[non_exhaustive]
90#[derive(Clone, Debug, Default, PartialEq, Serialize)]
91pub struct MoonshotThinking {
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub keep: Option<ThinkingKeep>,
95}
96
97impl MoonshotThinking {
98 fn is_empty(&self) -> bool {
99 self.keep.is_none()
100 }
101}
102
103#[non_exhaustive]
105#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
106#[serde(rename_all = "lowercase")]
107pub enum ThinkingKeep {
108 All,
110}
111
112impl MoonshotChat {
113 pub fn new() -> Self {
115 Self::default()
116 }
117
118 pub fn thinking_keep(mut self, keep: ThinkingKeep) -> Self {
120 self.thinking.keep = Some(keep);
121 self
122 }
123
124 pub fn prompt_cache_key(mut self, key: impl Into<String>) -> Self {
126 self.prompt_cache_key = Some(key.into());
127 self
128 }
129}
130
131#[non_exhaustive]
133#[derive(Clone, Debug, Default, PartialEq)]
134pub struct MoonshotExtras {
135 pub choice_usage: Option<Value>,
137 pub prompt_tokens_details: Option<Value>,
139 pub stop_reason: Option<String>,
141 pub stop_sequence: Option<String>,
143}
144
145impl ReplyExtras for MoonshotExtras {
146 fn from_reply(api: &Api, raw: &Value) -> Result<Self, serde_json::Error> {
147 if api.as_str() == MESSAGES_API {
148 let MessagesStop {
149 stop_reason,
150 stop_sequence,
151 } = MessagesStop::read("Moonshot", api, raw)?;
152 return Ok(Self {
153 stop_reason,
154 stop_sequence,
155 ..Self::default()
156 });
157 }
158 if api.as_str() != "openai.chat" {
159 return Ok(Self::default());
160 }
161 Ok(Self {
162 choice_usage: reply_field(raw, "/choices/0/usage")?,
163 prompt_tokens_details: reply_field(raw, "/usage/prompt_tokens_details")?,
164 ..Self::default()
165 })
166 }
167}
168
169#[cfg(test)]
170mod tests;