llmsdk_provider/shared.rs
1//! Shared types reused by language / embedding / image models.
2//!
3//! Maps to `@ai-sdk/provider`'s `shared/v4/*`.
4// Rust guideline compliant 2026-02-21
5
6use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9
10use crate::json::{JsonObject, JsonValue};
11
12/// Provider-specific options, keyed by provider id.
13///
14/// Mirrors `SharedV4ProviderOptions`. Outer key is the provider name
15/// (e.g. `"openai"`), inner object is provider-defined.
16///
17/// # Examples
18///
19/// ```
20/// use llmsdk_provider::shared::ProviderOptions;
21/// use serde_json::json;
22///
23/// let mut opts = ProviderOptions::default();
24/// opts.insert(
25/// "openai".into(),
26/// json!({ "reasoningEffort": "high" }).as_object().cloned().unwrap(),
27/// );
28/// ```
29pub type ProviderOptions = HashMap<String, JsonObject>;
30
31/// Provider-specific metadata returned by a provider, keyed by provider id.
32///
33/// Mirrors `SharedV4ProviderMetadata`.
34pub type ProviderMetadata = HashMap<String, JsonObject>;
35
36/// Mapping of provider names to provider-specific file / skill identifiers.
37///
38/// Mirrors `SharedV4ProviderReference`. Lets the same logical file or skill
39/// be referenced across multiple providers without re-uploading.
40///
41/// # Examples
42///
43/// ```
44/// use llmsdk_provider::shared::ProviderReference;
45///
46/// let mut r = ProviderReference::new();
47/// r.insert("anthropic".into(), "file-abc123".into());
48/// assert_eq!(r.get("anthropic"), Some(&"file-abc123".to_owned()));
49/// ```
50pub type ProviderReference = HashMap<String, String>;
51
52/// HTTP headers attached to a request or response.
53///
54/// Mirrors `SharedV4Headers`. Value may be `None` when the caller wants the
55/// provider to drop a default header.
56pub type Headers = HashMap<String, Option<String>>;
57
58/// Provider-emitted warning about a model call.
59///
60/// Mirrors `SharedV4Warning` (ai-sdk
61/// `packages/provider/src/shared/v4/shared-v4-warning.ts`). The four
62/// variants are wire-compatible with the upstream `type` tag:
63/// `unsupported` / `compatibility` / `deprecated` / `other`.
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
65#[serde(tag = "type", rename_all = "kebab-case")]
66pub enum Warning {
67 /// A feature is not supported by the model — the request was sent
68 /// without it and the result may differ from the caller's intent.
69 /// Mirrors upstream `{ type: 'unsupported', feature, details? }`.
70 Unsupported {
71 /// Name of the feature / setting / tool that was unsupported.
72 /// Matches upstream `feature` field (`snake_case` wire name).
73 feature: String,
74 /// Optional human-readable details.
75 #[serde(default, skip_serializing_if = "Option::is_none")]
76 details: Option<String>,
77 },
78
79 /// A compatibility-mode feature is in use that may produce suboptimal
80 /// results (the request still went through but with a coerced or
81 /// downgraded shape). Mirrors upstream
82 /// `{ type: 'compatibility', feature, details? }`.
83 Compatibility {
84 /// Name of the feature operating in compatibility mode.
85 feature: String,
86 /// Optional human-readable details.
87 #[serde(default, skip_serializing_if = "Option::is_none")]
88 details: Option<String>,
89 },
90
91 /// A deprecated setting / feature is being used; the message explains
92 /// the recommended replacement. Mirrors upstream
93 /// `{ type: 'deprecated', setting, message }`.
94 Deprecated {
95 /// Name of the deprecated setting / feature.
96 setting: String,
97 /// Human-readable message explaining what to use instead.
98 message: String,
99 },
100
101 /// Generic warning for cases that don't fit the structured variants.
102 /// Mirrors upstream `{ type: 'other', message }`.
103 Other {
104 /// Human-readable message.
105 message: String,
106 },
107}
108
109/// File data carried in prompts or tool results.
110///
111/// Mirrors `SharedV4FileData`. A tagged union over inline bytes, URL,
112/// provider reference, or inline text.
113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
114#[serde(tag = "type", rename_all = "kebab-case")]
115pub enum FileData {
116 /// Inline bytes (base64-encoded when serialized to JSON).
117 Data {
118 /// Raw bytes or base64 string; provider crates decide encoding on the wire.
119 data: FileBytes,
120 },
121 /// URL pointing to the file.
122 Url {
123 /// Absolute URL.
124 url: String,
125 },
126 /// Provider-specific reference, e.g. an uploaded file id.
127 Reference {
128 /// `{ providerId: id }` map.
129 reference: JsonObject,
130 },
131 /// Inline text payload.
132 Text {
133 /// Text content.
134 text: String,
135 },
136}
137
138/// Either raw bytes or a base64-encoded string.
139///
140/// Providers serialize bytes as base64 on the wire; this enum lets callers
141/// hand off whichever they have without paying a re-encode cost.
142#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
143#[serde(untagged)]
144pub enum FileBytes {
145 /// Base64-encoded string.
146 Base64(String),
147 /// Raw byte buffer.
148 Bytes(Vec<u8>),
149}
150
151/// Request metadata for telemetry / debugging.
152///
153/// Mirrors the `request` field on `*GenerateResult` / `*StreamResult`.
154#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
155pub struct RequestInfo {
156 /// HTTP body sent to the provider.
157 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub body: Option<JsonValue>,
159}
160
161/// Response metadata for telemetry / debugging.
162///
163/// Mirrors the `response` field on `*GenerateResult` / `*StreamResult`.
164#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
165pub struct ResponseInfo {
166 /// Response id reported by the provider.
167 #[serde(default, skip_serializing_if = "Option::is_none")]
168 pub id: Option<String>,
169 /// Timestamp reported by the provider (ISO-8601 string for portability).
170 #[serde(default, skip_serializing_if = "Option::is_none")]
171 pub timestamp: Option<String>,
172 /// Model id reported by the provider.
173 #[serde(default, skip_serializing_if = "Option::is_none")]
174 pub model_id: Option<String>,
175 /// Response headers.
176 #[serde(default, skip_serializing_if = "Option::is_none")]
177 pub headers: Option<Headers>,
178 /// Raw response body for debugging.
179 #[serde(default, skip_serializing_if = "Option::is_none")]
180 pub body: Option<JsonValue>,
181}