Skip to main content

aimux_core/
result.rs

1//! Result types for `do_generate` and `do_stream`.
2
3use std::collections::HashMap;
4
5use futures::Stream;
6use serde::{Deserialize, Serialize};
7use std::pin::Pin;
8use ts_rs::TS;
9
10use crate::error::AiMuxError;
11use crate::shared::FileData;
12use crate::stream_part::StreamPart;
13use crate::types::{FinishReason, ProviderMetadata, ResponseMetadata, Usage, Warning};
14
15use serde_json::Value;
16
17/// A content item in the generation result.
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TS)]
19#[ts(export)]
20pub enum GenerateContent {
21    /// Generated text.
22    Text {
23        text: String,
24        #[serde(default, skip_serializing_if = "Option::is_none")]
25        provider_metadata: Option<ProviderMetadata>,
26    },
27    /// A tool call requested by the model.
28    ToolCall {
29        tool_call_id: String,
30        tool_name: String,
31        input: serde_json::Value,
32        /// Whether the tool call will be executed by the provider.
33        /// If false/unset, the tool call is executed by the client.
34        #[serde(default, skip_serializing_if = "Option::is_none")]
35        provider_executed: Option<bool>,
36        /// Whether the tool is dynamic (defined at runtime, e.g. MCP tools).
37        #[serde(default, skip_serializing_if = "Option::is_none")]
38        dynamic: Option<bool>,
39        /// Additional provider-specific metadata for the tool call.
40        #[serde(default, skip_serializing_if = "Option::is_none")]
41        provider_metadata: Option<ProviderMetadata>,
42    },
43    /// A source / citation (e.g. URL citation from search-preview models).
44    Source {
45        id: String,
46        source_type: String,
47        url: Option<String>,
48        title: Option<String>,
49        #[serde(default, skip_serializing_if = "Option::is_none")]
50        provider_metadata: Option<ProviderMetadata>,
51    },
52    /// A reasoning / thinking segment produced by the model.
53    ///
54    /// Mirrors the Vercel AI SDK `reasoning` content type. `provider_metadata`
55    /// carries provider-specific data such as the Anthropic thinking-block
56    /// signature (`providerMetadata.anthropic.signature`).
57    Reasoning {
58        text: String,
59        provider_metadata: Option<ProviderMetadata>,
60    },
61    /// A file generated by the model (e.g. an image or document).
62    ///
63    /// Mirrors the Vercel AI SDK `file` content type. `data` is a tagged union
64    /// covering base64 data, URL, or provider reference.
65    File {
66        data: FileData,
67        media_type: String,
68        #[serde(default, skip_serializing_if = "Option::is_none")]
69        provider_metadata: Option<ProviderMetadata>,
70    },
71    /// A tool result from a provider-executed tool (e.g. xAI file_search,
72    /// web_search). Emitted alongside the preceding `ToolCall` when the
73    /// provider executes the tool server-side.
74    ToolResult {
75        tool_call_id: String,
76        tool_name: String,
77        result: Value,
78        /// Whether the result is an error or error message.
79        #[serde(default, skip_serializing_if = "Option::is_none")]
80        is_error: Option<bool>,
81        /// Whether the result is preliminary (replaces prior, e.g. image previews).
82        #[serde(default, skip_serializing_if = "Option::is_none")]
83        preliminary: Option<bool>,
84        /// Whether the tool is dynamic (defined at runtime, e.g. MCP tools).
85        #[serde(default, skip_serializing_if = "Option::is_none")]
86        dynamic: Option<bool>,
87        /// Additional provider-specific metadata for the tool result.
88        #[serde(default, skip_serializing_if = "Option::is_none")]
89        provider_metadata: Option<ProviderMetadata>,
90    },
91}
92
93/// Result of `LanguageModel::do_generate` (non-streaming).
94#[derive(Debug, Serialize, Deserialize, TS)]
95#[ts(export)]
96pub struct GenerateResult {
97    /// Generated content items (text, tool calls, etc.).
98    pub content: Vec<GenerateContent>,
99    /// Why generation stopped.
100    pub finish_reason: FinishReason,
101    /// Token usage.
102    pub usage: Usage,
103    /// Warnings issued by the provider.
104    pub warnings: Vec<Warning>,
105    /// Provider-specific metadata.
106    pub provider_metadata: Option<ProviderMetadata>,
107    /// Response metadata (id, timestamp, model_id).
108    pub response: ResponseMetadata,
109    /// The request body that was sent (for debugging).
110    pub request_body: Option<serde_json::Value>,
111    /// Response headers.
112    pub response_headers: Option<HashMap<String, String>>,
113}
114
115/// Result of `LanguageModel::do_stream` (streaming).
116pub struct StreamResult {
117    /// The stream of `StreamPart` items.
118    pub stream: Pin<Box<dyn Stream<Item = Result<StreamPart, AiMuxError>> + Send>>,
119    /// The request body that was sent (for debugging).
120    pub request_body: Option<serde_json::Value>,
121    /// Response headers.
122    pub response_headers: Option<HashMap<String, String>>,
123}
124
125impl std::fmt::Debug for StreamResult {
126    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127        f.debug_struct("StreamResult")
128            .field("request_body", &self.request_body)
129            .field("response_headers", &self.response_headers)
130            .field("stream", &"<stream>")
131            .finish()
132    }
133}