Skip to main content

starweaver_model/message/
provider.rs

1//! Provider metadata carried by canonical messages and response parts.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Map;
5
6use super::Metadata;
7
8/// Provider-private replay metadata attached to response parts.
9#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
10pub struct ProviderPartInfo {
11    /// Provider output item identifier, when the provider exposes one separately from call IDs.
12    #[serde(default, skip_serializing_if = "Option::is_none")]
13    pub id: Option<String>,
14    /// Provider that produced the part.
15    #[serde(default, skip_serializing_if = "Option::is_none")]
16    pub provider_name: Option<String>,
17    /// Provider-private fields needed for same-provider replay and diagnostics.
18    #[serde(default, skip_serializing_if = "Map::is_empty")]
19    pub details: Metadata,
20}
21
22impl ProviderPartInfo {
23    /// Build provider metadata for one provider output item.
24    #[must_use]
25    pub fn new(provider_name: impl Into<String>) -> Self {
26        Self {
27            id: None,
28            provider_name: Some(provider_name.into()),
29            details: Metadata::default(),
30        }
31    }
32
33    /// Attach a provider item identifier.
34    #[must_use]
35    pub fn with_id(mut self, id: impl Into<String>) -> Self {
36        let id = id.into();
37        if !id.is_empty() {
38            self.id = Some(id);
39        }
40        self
41    }
42
43    /// Attach provider details.
44    #[must_use]
45    pub fn with_details(mut self, details: Metadata) -> Self {
46        self.details = details;
47        self
48    }
49
50    /// Returns true when this metadata belongs to `provider_name`.
51    #[must_use]
52    pub fn is_provider(&self, provider_name: &str) -> bool {
53        self.provider_name.as_deref() == Some(provider_name)
54    }
55}
56
57/// Provider metadata attached to canonical responses.
58#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
59pub struct ProviderInfo {
60    /// Provider name.
61    pub name: String,
62    /// Provider response identifier.
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub response_id: Option<String>,
65    /// Provider-private response metadata such as conversation IDs, request IDs, and service tiers.
66    #[serde(default, skip_serializing_if = "Map::is_empty")]
67    pub details: Metadata,
68}
69
70/// Provider-neutral finish reason.
71#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
72#[serde(rename_all = "snake_case")]
73pub enum FinishReason {
74    /// Natural stop.
75    Stop,
76    /// Length or token limit.
77    Length,
78    /// Tool calls requested.
79    ToolCalls,
80    /// Content filtered by provider.
81    ContentFilter,
82    /// Unknown provider reason.
83    Unknown,
84}
85
86impl ProviderPartInfo {
87    pub(super) fn is_empty(&self) -> bool {
88        self.id.is_none() && self.provider_name.is_none() && self.details.is_empty()
89    }
90}