starweaver_model/message/
response_parts.rs1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6use super::{ProviderPartInfo, ToolCallPart};
7
8#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
10#[serde(tag = "kind", rename_all = "snake_case")]
11pub enum ModelResponsePart {
12 Text {
14 text: String,
16 },
17 ProviderText {
19 text: String,
21 #[serde(default, skip_serializing_if = "ProviderPartInfo::is_empty")]
23 provider: ProviderPartInfo,
24 },
25 Thinking {
27 text: String,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 signature: Option<String>,
32 },
33 ProviderThinking {
35 text: String,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
39 signature: Option<String>,
40 #[serde(default, skip_serializing_if = "ProviderPartInfo::is_empty")]
42 provider: ProviderPartInfo,
43 },
44 ToolCall(ToolCallPart),
46 ProviderToolCall {
48 call: ToolCallPart,
50 #[serde(default, skip_serializing_if = "ProviderPartInfo::is_empty")]
52 provider: ProviderPartInfo,
53 },
54 NativeToolCall {
56 tool_type: String,
58 payload: Value,
60 },
61 NativeToolReturn {
63 tool_type: String,
65 payload: Value,
67 },
68 File {
70 url: String,
72 media_type: String,
74 },
75 Compaction {
77 summary: String,
79 },
80 ProviderOpaque {
82 item_type: String,
84 payload: Value,
86 #[serde(default, skip_serializing_if = "ProviderPartInfo::is_empty")]
88 provider: ProviderPartInfo,
89 },
90}
91
92impl ModelResponsePart {
93 #[must_use]
95 pub const fn text(&self) -> Option<&str> {
96 match self {
97 Self::Text { text } | Self::ProviderText { text, .. } => Some(text.as_str()),
98 Self::Thinking { .. }
99 | Self::ProviderThinking { .. }
100 | Self::ToolCall(_)
101 | Self::ProviderToolCall { .. }
102 | Self::NativeToolCall { .. }
103 | Self::NativeToolReturn { .. }
104 | Self::File { .. }
105 | Self::Compaction { .. }
106 | Self::ProviderOpaque { .. } => None,
107 }
108 }
109
110 #[must_use]
112 pub fn thinking(&self) -> Option<(&str, Option<&str>)> {
113 match self {
114 Self::Thinking { text, signature }
115 | Self::ProviderThinking {
116 text, signature, ..
117 } => Some((text.as_str(), signature.as_deref())),
118 Self::Text { .. }
119 | Self::ProviderText { .. }
120 | Self::ToolCall(_)
121 | Self::ProviderToolCall { .. }
122 | Self::NativeToolCall { .. }
123 | Self::NativeToolReturn { .. }
124 | Self::File { .. }
125 | Self::Compaction { .. }
126 | Self::ProviderOpaque { .. } => None,
127 }
128 }
129
130 #[must_use]
132 pub const fn tool_call(&self) -> Option<&ToolCallPart> {
133 match self {
134 Self::ToolCall(call) | Self::ProviderToolCall { call, .. } => Some(call),
135 Self::Text { .. }
136 | Self::ProviderText { .. }
137 | Self::Thinking { .. }
138 | Self::ProviderThinking { .. }
139 | Self::NativeToolCall { .. }
140 | Self::NativeToolReturn { .. }
141 | Self::File { .. }
142 | Self::Compaction { .. }
143 | Self::ProviderOpaque { .. } => None,
144 }
145 }
146
147 #[must_use]
149 pub const fn provider_part(&self) -> Option<&ProviderPartInfo> {
150 match self {
151 Self::ProviderText { provider, .. }
152 | Self::ProviderThinking { provider, .. }
153 | Self::ProviderToolCall { provider, .. }
154 | Self::ProviderOpaque { provider, .. } => Some(provider),
155 Self::Text { .. }
156 | Self::Thinking { .. }
157 | Self::ToolCall(_)
158 | Self::NativeToolCall { .. }
159 | Self::NativeToolReturn { .. }
160 | Self::File { .. }
161 | Self::Compaction { .. } => None,
162 }
163 }
164
165 #[must_use]
167 pub fn is_compaction(&self) -> bool {
168 match self {
169 Self::Compaction { .. } => true,
170 Self::ProviderOpaque { item_type, .. } => item_type == "compaction",
171 Self::Text { .. }
172 | Self::ProviderText { .. }
173 | Self::Thinking { .. }
174 | Self::ProviderThinking { .. }
175 | Self::ToolCall(_)
176 | Self::ProviderToolCall { .. }
177 | Self::NativeToolCall { .. }
178 | Self::NativeToolReturn { .. }
179 | Self::File { .. } => false,
180 }
181 }
182}