Skip to main content

flow_adapter_ai/
request.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Default, Serialize, Deserialize)]
4pub struct CloudAiRequest {
5    pub model: String,
6    pub prompt: String,
7    pub max_tokens: Option<u32>,
8    pub temperature: Option<f32>,
9    pub api_key: String,
10    /// Optional system-role text. Each provider maps it to its native
11    /// shape:
12    ///
13    ///   - Claude: top-level `system` field on the request payload.
14    ///   - OpenAI: prepended `{role:"system"}` message.
15    ///   - Gemini: top-level `system_instruction`.
16    ///
17    /// `None` sends a single user-role message with no system text - the
18    /// cloud-AI **node** path, which has no per-task system prompt.
19    #[serde(default)]
20    pub system: Option<String>,
21    /// Override endpoint for the OpenAI-compatible local provider
22    /// (e.g. `http://localhost:11434/v1/chat/completions`). Cloud
23    /// providers ignore this and use their fixed `ENDPOINT` const; the
24    /// `local` provider requires it.
25    #[serde(default)]
26    pub base_url: Option<String>,
27    /// Nucleus sampling cutoff (0..=1). Forwarded by the OpenAI-compatible
28    /// body builder (`top_p`); cloud providers with their own builders
29    /// (Claude, Gemini) ignore it. `None` means "let the server decide".
30    #[serde(default)]
31    pub top_p: Option<f32>,
32    /// Top-K sampling cutoff. Non-standard in OpenAI's API but accepted
33    /// by llama.cpp / Ollama / LM Studio; the OpenAI-compatible body
34    /// builder forwards it verbatim when set.
35    #[serde(default)]
36    pub top_k: Option<u32>,
37    /// Stop sequences (any element halts generation). Forwarded as the
38    /// OpenAI `stop` field. Empty `None` means no caller-supplied stops.
39    #[serde(default)]
40    pub stop: Option<Vec<String>>,
41    /// When `true` the caller is invoking the provider's `invoke_stream`
42    /// path and expects per-chunk events. Providers always set
43    /// `stream: true` in the HTTP payload when this is set.
44    #[serde(default)]
45    pub stream: bool,
46    /// Caller-supplied correlation id stamped onto every emitted
47    /// `LlmStreamEvent`. Required when `stream = true`; harmless
48    /// otherwise.
49    #[serde(default)]
50    pub call_id: Option<String>,
51    /// Per-request reasoning/thinking toggle for models that support it.
52    /// `Some(true)` asks the provider to enable extended thinking, `Some(false)`
53    /// disables it, `None` leaves the server/model default. Each provider maps
54    /// it to its native shape (OpenAI-compat `chat_template_kwargs`, Claude
55    /// `thinking`, Gemini `thinkingConfig`).
56    #[serde(default)]
57    pub reasoning: Option<bool>,
58    /// Image references for vision models - `http(s)` URLs or `data:` URLs (the
59    /// executor resolves local paths to base64 `data:` URLs before building the
60    /// request). Empty for text-only calls.
61    #[serde(default)]
62    pub images: Vec<String>,
63    /// Tool/function specs the model may call. Empty disables tool use; the
64    /// actual call loop runs in `CloudAiProvider::invoke_tools`.
65    #[serde(default)]
66    pub tools: Vec<ToolSpec>,
67    /// Optional JSON Schema for structured output. When set, the
68    /// OpenAI-compatible body builder adds a `response_format: json_schema` so
69    /// the model is constrained to matching JSON (providers with their own body
70    /// builders - Claude / Gemini - ignore it and rely on the prompt). The
71    /// `"structured"` task sets this from the node's `outputSchema`.
72    #[serde(default, skip_serializing_if = "Option::is_none")]
73    pub response_schema: Option<serde_json::Value>,
74}
75
76/// A tool/function the model may call, in provider-neutral form. `parameters`
77/// is a JSON-Schema object describing the arguments. The executor builds these
78/// from a bound adapter's action descriptor; each provider renders one into its
79/// own tool wire shape.
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ToolSpec {
82    pub name: String,
83    pub description: String,
84    pub parameters: serde_json::Value,
85}
86
87/// Runs a single tool call on behalf of a provider's tool loop. The provider
88/// parses the model's tool call (name + JSON args) and calls this; the
89/// implementor (the executor) maps the name to an adapter action, runs it, and
90/// returns the result payload - or an `Err` string that is fed back to the
91/// model as the tool result so it can recover.
92#[async_trait::async_trait]
93pub trait ToolDispatcher: Send + Sync {
94    async fn call(&self, name: &str, args: &serde_json::Value)
95        -> Result<serde_json::Value, String>;
96}
97
98/// Result of an embeddings call (`task: "embedding"`). Carries the vector and
99/// its dimensionality so the node envelope can surface both.
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct EmbeddingResponse {
102    pub provider: String,
103    pub model: String,
104    pub embedding: Vec<f32>,
105    pub dims: usize,
106    pub latency_ms: u64,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct CloudAiResponse {
111    pub provider: String,
112    pub model: String,
113    pub text: String,
114    pub finish_reason: String,
115    pub input_tokens: u32,
116    pub output_tokens: u32,
117    pub latency_ms: u64,
118}