Skip to main content

gestalt/
agent_provider.rs

1use std::sync::Arc;
2use std::time::SystemTime;
3
4use prost_types::{Struct, Timestamp, Value};
5use serde::Serialize;
6use tonic::codegen::async_trait;
7use tonic::{Request as GrpcRequest, Response as GrpcResponse, Status};
8
9use crate::api::{RuntimeMetadata, Subject, scope_request_context};
10use crate::error::Result as ProviderResult;
11use crate::generated::v1::{self as pb};
12use crate::protocol;
13use crate::rpc_status::rpc_status;
14
15/// Native JSON object used by authored agent providers.
16pub type AgentJson = serde_json::Value;
17
18#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
19#[repr(i32)]
20/// Native enum for `gestalt.provider.v1.AgentMessagePartType`.
21pub enum AgentMessagePartType {
22    #[default]
23    /// The `Unspecified` variant.
24    Unspecified = 0,
25    /// The `Text` variant.
26    Text = 1,
27    /// The `Json` variant.
28    Json = 2,
29    /// The `ToolCall` variant.
30    ToolCall = 3,
31    /// The `ToolResult` variant.
32    ToolResult = 4,
33    /// The `ImageRef` variant.
34    ImageRef = 5,
35}
36
37impl AgentMessagePartType {
38    /// Returns the wire integer for this value.
39    pub const fn as_i32(self) -> i32 {
40        self as i32
41    }
42
43    /// Converts a wire integer, mapping unknown values to the unspecified
44    /// variant.
45    pub const fn from_i32_lossy(value: i32) -> Self {
46        match value {
47            1 => Self::Text,
48            2 => Self::Json,
49            3 => Self::ToolCall,
50            4 => Self::ToolResult,
51            5 => Self::ImageRef,
52            _ => Self::Unspecified,
53        }
54    }
55}
56
57impl TryFrom<i32> for AgentMessagePartType {
58    type Error = crate::Error;
59
60    fn try_from(value: i32) -> ProviderResult<Self> {
61        match value {
62            0 => Ok(Self::Unspecified),
63            1 => Ok(Self::Text),
64            2 => Ok(Self::Json),
65            3 => Ok(Self::ToolCall),
66            4 => Ok(Self::ToolResult),
67            5 => Ok(Self::ImageRef),
68            _ => Err(crate::Error::bad_request(format!(
69                "unknown agent message part type {value}"
70            ))),
71        }
72    }
73}
74
75#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
76#[repr(i32)]
77/// Native enum for `gestalt.provider.v1.AgentToolSourceMode`.
78pub enum AgentToolSourceMode {
79    #[default]
80    /// The `Unspecified` variant.
81    Unspecified = 0,
82    /// The `Catalog` variant.
83    Catalog = 2,
84    /// The `None` variant.
85    None = 3,
86}
87
88impl AgentToolSourceMode {
89    /// Returns the wire integer for this value.
90    pub const fn as_i32(self) -> i32 {
91        self as i32
92    }
93
94    /// Converts a wire integer, mapping unknown values to the unspecified
95    /// variant.
96    pub const fn from_i32_lossy(value: i32) -> Self {
97        match value {
98            2 => Self::Catalog,
99            3 => Self::None,
100            _ => Self::Unspecified,
101        }
102    }
103}
104
105impl TryFrom<i32> for AgentToolSourceMode {
106    type Error = crate::Error;
107
108    fn try_from(value: i32) -> ProviderResult<Self> {
109        match value {
110            0 => Ok(Self::Unspecified),
111            2 => Ok(Self::Catalog),
112            3 => Ok(Self::None),
113            _ => Err(crate::Error::bad_request(format!(
114                "unknown agent tool source mode {value}"
115            ))),
116        }
117    }
118}
119
120#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
121#[repr(i32)]
122/// Native enum for `gestalt.provider.v1.AgentExecutionStatus`.
123pub enum AgentExecutionStatus {
124    #[default]
125    /// The `Unspecified` variant.
126    Unspecified = 0,
127    /// The `Pending` variant.
128    Pending = 1,
129    /// The `Running` variant.
130    Running = 2,
131    /// The `Succeeded` variant.
132    Succeeded = 3,
133    /// The `Failed` variant.
134    Failed = 4,
135    /// The `Canceled` variant.
136    Canceled = 5,
137    /// The `WaitingForInput` variant.
138    WaitingForInput = 6,
139}
140
141impl AgentExecutionStatus {
142    /// Returns the wire integer for this value.
143    pub const fn as_i32(self) -> i32 {
144        self as i32
145    }
146
147    /// Converts a wire integer, mapping unknown values to the unspecified
148    /// variant.
149    pub const fn from_i32_lossy(value: i32) -> Self {
150        match value {
151            1 => Self::Pending,
152            2 => Self::Running,
153            3 => Self::Succeeded,
154            4 => Self::Failed,
155            5 => Self::Canceled,
156            6 => Self::WaitingForInput,
157            _ => Self::Unspecified,
158        }
159    }
160}
161
162impl TryFrom<i32> for AgentExecutionStatus {
163    type Error = crate::Error;
164
165    fn try_from(value: i32) -> ProviderResult<Self> {
166        match value {
167            0 => Ok(Self::Unspecified),
168            1 => Ok(Self::Pending),
169            2 => Ok(Self::Running),
170            3 => Ok(Self::Succeeded),
171            4 => Ok(Self::Failed),
172            5 => Ok(Self::Canceled),
173            6 => Ok(Self::WaitingForInput),
174            _ => Err(crate::Error::bad_request(format!(
175                "unknown agent execution status {value}"
176            ))),
177        }
178    }
179}
180
181#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
182#[repr(i32)]
183/// Native enum for `gestalt.provider.v1.AgentSessionState`.
184pub enum AgentSessionState {
185    #[default]
186    /// The `Unspecified` variant.
187    Unspecified = 0,
188    /// The `Active` variant.
189    Active = 1,
190    /// The `Archived` variant.
191    Archived = 2,
192}
193
194impl AgentSessionState {
195    /// Returns the wire integer for this value.
196    pub const fn as_i32(self) -> i32 {
197        self as i32
198    }
199
200    /// Converts a wire integer, mapping unknown values to the unspecified
201    /// variant.
202    pub const fn from_i32_lossy(value: i32) -> Self {
203        match value {
204            1 => Self::Active,
205            2 => Self::Archived,
206            _ => Self::Unspecified,
207        }
208    }
209}
210
211impl TryFrom<i32> for AgentSessionState {
212    type Error = crate::Error;
213
214    fn try_from(value: i32) -> ProviderResult<Self> {
215        match value {
216            0 => Ok(Self::Unspecified),
217            1 => Ok(Self::Active),
218            2 => Ok(Self::Archived),
219            _ => Err(crate::Error::bad_request(format!(
220                "unknown agent session state {value}"
221            ))),
222        }
223    }
224}
225
226#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
227#[repr(i32)]
228/// Native enum for `gestalt.provider.v1.AgentInteractionType`.
229pub enum AgentInteractionType {
230    #[default]
231    /// The `Unspecified` variant.
232    Unspecified = 0,
233    /// The `Approval` variant.
234    Approval = 1,
235    /// The `Clarification` variant.
236    Clarification = 2,
237    /// The `Input` variant.
238    Input = 3,
239}
240
241impl AgentInteractionType {
242    /// Returns the wire integer for this value.
243    pub const fn as_i32(self) -> i32 {
244        self as i32
245    }
246
247    /// Converts a wire integer, mapping unknown values to the unspecified
248    /// variant.
249    pub const fn from_i32_lossy(value: i32) -> Self {
250        match value {
251            1 => Self::Approval,
252            2 => Self::Clarification,
253            3 => Self::Input,
254            _ => Self::Unspecified,
255        }
256    }
257}
258
259impl TryFrom<i32> for AgentInteractionType {
260    type Error = crate::Error;
261
262    fn try_from(value: i32) -> ProviderResult<Self> {
263        match value {
264            0 => Ok(Self::Unspecified),
265            1 => Ok(Self::Approval),
266            2 => Ok(Self::Clarification),
267            3 => Ok(Self::Input),
268            _ => Err(crate::Error::bad_request(format!(
269                "unknown agent interaction type {value}"
270            ))),
271        }
272    }
273}
274
275#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
276#[repr(i32)]
277/// Native enum for `gestalt.provider.v1.AgentInteractionState`.
278pub enum AgentInteractionState {
279    #[default]
280    /// The `Unspecified` variant.
281    Unspecified = 0,
282    /// The `Pending` variant.
283    Pending = 1,
284    /// The `Resolved` variant.
285    Resolved = 2,
286    /// The `Canceled` variant.
287    Canceled = 3,
288}
289
290impl AgentInteractionState {
291    /// Returns the wire integer for this value.
292    pub const fn as_i32(self) -> i32 {
293        self as i32
294    }
295
296    /// Converts a wire integer, mapping unknown values to the unspecified
297    /// variant.
298    pub const fn from_i32_lossy(value: i32) -> Self {
299        match value {
300            1 => Self::Pending,
301            2 => Self::Resolved,
302            3 => Self::Canceled,
303            _ => Self::Unspecified,
304        }
305    }
306}
307
308impl TryFrom<i32> for AgentInteractionState {
309    type Error = crate::Error;
310
311    fn try_from(value: i32) -> ProviderResult<Self> {
312        match value {
313            0 => Ok(Self::Unspecified),
314            1 => Ok(Self::Pending),
315            2 => Ok(Self::Resolved),
316            3 => Ok(Self::Canceled),
317            _ => Err(crate::Error::bad_request(format!(
318                "unknown agent interaction state {value}"
319            ))),
320        }
321    }
322}
323
324#[derive(Debug, Clone, Default, PartialEq)]
325/// Native message type for `gestalt.provider.v1.AgentMessage`.
326pub struct AgentMessage {
327    /// The `role` field.
328    pub role: String,
329    /// The `text` field.
330    pub text: String,
331    /// The `parts` field.
332    pub parts: Vec<AgentMessagePart>,
333    /// The `metadata` field.
334    pub metadata: Option<AgentJson>,
335}
336
337#[derive(Debug, Clone, Default, PartialEq)]
338/// Native message type for `gestalt.provider.v1.AgentMessagePartToolCall`.
339pub struct AgentMessagePartToolCall {
340    /// The `id` field.
341    pub id: String,
342    /// The `tool_id` field.
343    pub tool_id: String,
344    /// The `arguments` field.
345    pub arguments: Option<AgentJson>,
346}
347
348#[derive(Debug, Clone, Default, PartialEq)]
349/// Native message type for `gestalt.provider.v1.AgentMessagePartToolResult`.
350pub struct AgentMessagePartToolResult {
351    /// The `tool_call_id` field.
352    pub tool_call_id: String,
353    /// The `status` field.
354    pub status: i32,
355    /// The `content` field.
356    pub content: String,
357    /// The `output` field.
358    pub output: Option<AgentJson>,
359}
360
361#[derive(Debug, Clone, Default, PartialEq, Eq)]
362/// Native message type for `gestalt.provider.v1.AgentMessagePartImageRef`.
363pub struct AgentMessagePartImageRef {
364    /// The `uri` field.
365    pub uri: String,
366    /// The `mime_type` field.
367    pub mime_type: String,
368}
369
370#[derive(Debug, Clone, Default, PartialEq)]
371/// Native message type for `gestalt.provider.v1.AgentMessagePart`.
372pub struct AgentMessagePart {
373    /// The `type` field.
374    pub r#type: AgentMessagePartType,
375    /// The `text` field.
376    pub text: String,
377    /// The `json` field.
378    pub json: Option<AgentJson>,
379    /// The `tool_call` field.
380    pub tool_call: Option<AgentMessagePartToolCall>,
381    /// The `tool_result` field.
382    pub tool_result: Option<AgentMessagePartToolResult>,
383    /// The `image_ref` field.
384    pub image_ref: Option<AgentMessagePartImageRef>,
385}
386
387#[derive(Debug, Clone, Default, PartialEq, Eq)]
388/// Describes the workspace a provider prepared for a session.
389pub struct AgentPreparedWorkspace {
390    /// The `root` field.
391    pub root: String,
392    /// The `cwd` field.
393    pub cwd: String,
394}
395
396#[derive(Debug, Clone, Default, PartialEq, Eq)]
397/// Native message type for `gestalt.provider.v1.AgentToolRef`.
398pub struct AgentToolRef {
399    /// The `app` field.
400    pub app: String,
401    /// The `operation` field.
402    pub operation: String,
403    /// The `connection` field.
404    pub connection: String,
405    /// The `instance` field.
406    pub instance: String,
407    /// The `title` field.
408    pub title: String,
409    /// The `description` field.
410    pub description: String,
411    /// The `credential_mode` field.
412    pub credential_mode: String,
413    /// The `system` field.
414    pub system: String,
415    /// The `run_as` field.
416    pub run_as: Option<Subject>,
417}
418
419#[derive(Debug, Clone, Default, PartialEq)]
420/// Native message type for `gestalt.provider.v1.AgentToolConfig`.
421pub struct AgentToolConfig {
422    /// The `source` field.
423    pub source: Option<AgentToolConfigSource>,
424}
425
426#[derive(Debug, Clone, PartialEq)]
427/// Selects where a session's tools come from.
428pub enum AgentToolConfigSource {
429    /// The `None` variant.
430    None(AgentNoTools),
431    /// The `Catalog` variant.
432    Catalog(AgentCatalogToolConfig),
433}
434
435#[derive(Debug, Clone, Default, PartialEq, Eq)]
436pub struct AgentNoTools {}
437
438#[derive(Debug, Clone, Default, PartialEq)]
439/// Native message type for `gestalt.provider.v1.AgentCatalogToolConfig`.
440pub struct AgentCatalogToolConfig {
441    /// The `refs` field.
442    pub refs: Vec<AgentToolRef>,
443    /// The `tools` field.
444    pub tools: Vec<ListedAgentTool>,
445}
446
447impl AgentMessage {
448    /// Sets message metadata from any JSON-object-like serializable value.
449    pub fn with_metadata<T: Serialize>(mut self, value: T) -> ProviderResult<Self> {
450        self.metadata = Some(protocol::json_from_serializable(value)?);
451        Ok(self)
452    }
453
454    /// Creates a user text message.
455    pub fn user_text(text: impl Into<String>) -> Self {
456        Self {
457            role: "user".to_string(),
458            text: text.into(),
459            ..Default::default()
460        }
461    }
462}
463
464impl AgentMessagePart {
465    /// Creates a JSON message part from any JSON-object-like serializable value.
466    pub fn json<T: Serialize>(value: T) -> ProviderResult<Self> {
467        Ok(Self {
468            r#type: AgentMessagePartType::Json,
469            json: Some(protocol::json_from_serializable(value)?),
470            ..Default::default()
471        })
472    }
473}
474
475impl AgentMessagePartToolCall {
476    /// Sets tool-call arguments from any JSON-object-like serializable value.
477    pub fn with_arguments<T: Serialize>(mut self, value: T) -> ProviderResult<Self> {
478        self.arguments = Some(protocol::json_from_serializable(value)?);
479        Ok(self)
480    }
481}
482
483impl AgentMessagePartToolResult {
484    /// Sets tool-result output from any JSON-object-like serializable value.
485    pub fn with_output<T: Serialize>(mut self, value: T) -> ProviderResult<Self> {
486        self.output = Some(protocol::json_from_serializable(value)?);
487        Ok(self)
488    }
489}
490
491/// Native agent workspace request data.
492#[derive(Clone, Debug, Default, PartialEq, Eq)]
493pub struct AgentWorkspace {
494    /// The `checkouts` field.
495    pub checkouts: Vec<AgentWorkspaceGitCheckout>,
496    /// The `cwd` field.
497    pub cwd: String,
498}
499
500/// Native agent workspace git checkout data.
501#[derive(Clone, Debug, Default, PartialEq, Eq)]
502pub struct AgentWorkspaceGitCheckout {
503    /// The `url` field.
504    pub url: String,
505    /// The `reference` field.
506    pub reference: String,
507    /// The `path` field.
508    pub path: String,
509}
510
511#[derive(Debug, Clone, Default, PartialEq, Eq)]
512/// Native message type for `gestalt.provider.v1.AgentProviderCapabilities`.
513pub struct AgentProviderCapabilities {
514    /// The `streaming_text` field.
515    pub streaming_text: bool,
516    /// The `tool_calls` field.
517    pub tool_calls: bool,
518    /// The `parallel_tool_calls` field.
519    pub parallel_tool_calls: bool,
520    /// The `interactions` field.
521    pub interactions: bool,
522    /// The `resumable_turns` field.
523    pub resumable_turns: bool,
524    /// The `reasoning_summaries` field.
525    pub reasoning_summaries: bool,
526    /// The `bounded_list_hydration` field.
527    pub bounded_list_hydration: bool,
528    /// The `supported_tool_sources` field.
529    pub supported_tool_sources: Vec<AgentToolSourceMode>,
530    /// The `supports_session_start` field.
531    pub supports_session_start: bool,
532    /// The `supports_prepared_workspace` field.
533    pub supports_prepared_workspace: bool,
534}
535
536#[derive(Debug, Clone, Default, PartialEq, Eq)]
537/// Native message type for `gestalt.provider.v1.GetAgentProviderCapabilitiesRequest`.
538pub struct GetAgentProviderCapabilitiesRequest {}
539
540#[derive(Debug, Clone, Default, PartialEq)]
541/// Native message type for `gestalt.provider.v1.AgentInteraction`.
542pub struct AgentInteraction {
543    /// The `id` field.
544    pub id: String,
545    /// The `type` field.
546    pub r#type: AgentInteractionType,
547    /// The `state` field.
548    pub state: AgentInteractionState,
549    /// The `title` field.
550    pub title: String,
551    /// The `prompt` field.
552    pub prompt: String,
553    /// The `request` field.
554    pub request: Option<AgentJson>,
555    /// The `resolution` field.
556    pub resolution: Option<AgentJson>,
557    /// The `created_at` field.
558    pub created_at: Option<SystemTime>,
559    /// The `resolved_at` field.
560    pub resolved_at: Option<SystemTime>,
561    /// The `turn_id` field.
562    pub turn_id: String,
563    /// The `session_id` field.
564    pub session_id: String,
565}
566
567#[derive(Debug, Clone, Default, PartialEq)]
568/// Native message type for `gestalt.provider.v1.AgentSession`.
569pub struct AgentSession {
570    /// The `id` field.
571    pub id: String,
572    /// The `provider_name` field.
573    pub provider_name: String,
574    /// The `model` field.
575    pub model: String,
576    /// The `client_ref` field.
577    pub client_ref: String,
578    /// The `state` field.
579    pub state: AgentSessionState,
580    /// The `metadata` field.
581    pub metadata: Option<AgentJson>,
582    /// The `created_by_subject_id` field.
583    pub created_by_subject_id: Option<String>,
584    /// The `created_at` field.
585    pub created_at: Option<SystemTime>,
586    /// The `updated_at` field.
587    pub updated_at: Option<SystemTime>,
588    /// The `last_turn_at` field.
589    pub last_turn_at: Option<SystemTime>,
590}
591
592/// Request passed to [`AgentProvider::create_session`].
593#[derive(Debug, Clone, Default, PartialEq)]
594pub struct CreateAgentProviderSessionRequest {
595    /// The `idempotency_key` field.
596    pub idempotency_key: String,
597    /// The `model` field.
598    pub model: String,
599    /// The `client_ref` field.
600    pub client_ref: String,
601    /// The `metadata` field.
602    pub metadata: Option<AgentJson>,
603    /// The `session_start` field.
604    pub session_start: Option<AgentSessionStartConfig>,
605    /// The `prepared_workspace` field.
606    pub prepared_workspace: Option<AgentPreparedWorkspace>,
607    /// The `tools` field.
608    pub tools: Option<AgentToolConfig>,
609}
610
611#[derive(Debug, Clone, Default, PartialEq, Eq)]
612/// Native message type for `gestalt.provider.v1.AgentSessionStartConfig`.
613pub struct AgentSessionStartConfig {
614    /// The `hooks` field.
615    pub hooks: Vec<AgentSessionStartHook>,
616}
617
618#[derive(Debug, Clone, Default, PartialEq, Eq)]
619/// Native message type for `gestalt.provider.v1.AgentSessionStartHook`.
620pub struct AgentSessionStartHook {
621    /// The `id` field.
622    pub id: String,
623    /// The `type` field.
624    pub r#type: String,
625    /// The `command` field.
626    pub command: Vec<String>,
627    /// The `cwd` field.
628    pub cwd: String,
629    /// The `timeout` field.
630    pub timeout: String,
631    /// The `env` field.
632    pub env: std::collections::HashMap<String, String>,
633    /// The `output` field.
634    pub output: Option<AgentSessionStartHookOutput>,
635}
636
637#[derive(Debug, Clone, Default, PartialEq, Eq)]
638/// Native message type for `gestalt.provider.v1.AgentSessionStartHookOutput`.
639pub struct AgentSessionStartHookOutput {
640    /// The `additional_context` field.
641    pub additional_context: bool,
642    /// The `metadata` field.
643    pub metadata: bool,
644}
645
646#[derive(Debug, Clone, Default, PartialEq, Eq)]
647/// Native message type for `gestalt.provider.v1.GetAgentProviderSessionRequest`.
648pub struct GetAgentProviderSessionRequest {
649    /// The `provider_name` field.
650    pub provider_name: String,
651    /// The `session_id` field.
652    pub session_id: String,
653}
654
655#[derive(Debug, Clone, Default, PartialEq, Eq)]
656/// Native message type for `gestalt.provider.v1.ListAgentProviderSessionsRequest`.
657pub struct ListAgentProviderSessionsRequest {
658    /// The `provider_name` field.
659    pub provider_name: String,
660    /// The `session_ids` field.
661    pub session_ids: Vec<String>,
662    /// The `state` field.
663    pub state: AgentSessionState,
664    /// The `limit` field.
665    pub limit: i32,
666    /// The `summary_only` field.
667    pub summary_only: bool,
668}
669
670#[derive(Debug, Clone, Default, PartialEq)]
671/// Native message type for `gestalt.provider.v1.ListAgentProviderSessionsResponse`.
672pub struct ListAgentProviderSessionsResponse {
673    /// The `sessions` field.
674    pub sessions: Vec<AgentSession>,
675}
676
677#[derive(Debug, Clone, Default, PartialEq)]
678/// Native message type for `gestalt.provider.v1.UpdateAgentProviderSessionRequest`.
679pub struct UpdateAgentProviderSessionRequest {
680    /// The `provider_name` field.
681    pub provider_name: String,
682    /// The `session_id` field.
683    pub session_id: String,
684    /// The `client_ref` field.
685    pub client_ref: String,
686    /// The `state` field.
687    pub state: AgentSessionState,
688    /// The `metadata` field.
689    pub metadata: Option<AgentJson>,
690}
691
692#[derive(Debug, Clone, Default, PartialEq)]
693/// Native message type for `gestalt.provider.v1.AgentTurn`.
694pub struct AgentTurn {
695    /// The `id` field.
696    pub id: String,
697    /// The `session_id` field.
698    pub session_id: String,
699    /// The `provider_name` field.
700    pub provider_name: String,
701    /// The `model` field.
702    pub model: String,
703    /// The `status` field.
704    pub status: AgentExecutionStatus,
705    /// The `messages` field.
706    pub messages: Vec<AgentMessage>,
707    /// The `output` field.
708    pub output: Option<AgentTurnOutput>,
709    /// The `status_message` field.
710    pub status_message: String,
711    /// The `created_by_subject_id` field.
712    pub created_by_subject_id: Option<String>,
713    /// The `created_at` field.
714    pub created_at: Option<SystemTime>,
715    /// The `started_at` field.
716    pub started_at: Option<SystemTime>,
717    /// The `completed_at` field.
718    pub completed_at: Option<SystemTime>,
719    /// The `execution_ref` field.
720    pub execution_ref: String,
721}
722
723#[derive(Debug, Clone, PartialEq)]
724/// The structured-or-text output of a finished turn.
725pub enum AgentTurnOutput {
726    /// The `Text` variant.
727    Text(AgentTurnTextOutput),
728    /// The `Structured` variant.
729    Structured(AgentTurnStructuredOutput),
730}
731
732#[derive(Debug, Clone, Default, PartialEq, Eq)]
733/// Native message type for `gestalt.provider.v1.AgentTurnTextOutput`.
734pub struct AgentTurnTextOutput {
735    /// The `text` field.
736    pub text: String,
737}
738
739#[derive(Debug, Clone, Default, PartialEq)]
740/// Native message type for `gestalt.provider.v1.AgentTurnStructuredOutput`.
741pub struct AgentTurnStructuredOutput {
742    /// The `text` field.
743    pub text: String,
744    /// The `value` field.
745    pub value: Option<AgentJson>,
746}
747
748#[derive(Debug, Clone, Default, PartialEq)]
749/// Native message type for `gestalt.provider.v1.AgentTurnDisplay`.
750pub struct AgentTurnDisplay {
751    /// The `kind` field.
752    pub kind: String,
753    /// The `phase` field.
754    pub phase: String,
755    /// The `text` field.
756    pub text: String,
757    /// The `label` field.
758    pub label: String,
759    /// The `ref` field.
760    pub r#ref: String,
761    /// The `parent_ref` field.
762    pub parent_ref: String,
763    /// The `input` field.
764    pub input: Option<AgentJson>,
765    /// The `output` field.
766    pub output: Option<AgentJson>,
767    /// The `error` field.
768    pub error: Option<AgentJson>,
769    /// The `action` field.
770    pub action: String,
771    /// The `format` field.
772    pub format: String,
773    /// The `language` field.
774    pub language: String,
775}
776
777#[derive(Debug, Clone, PartialEq)]
778/// Native message type for `gestalt.provider.v1.CreateAgentProviderTurnRequest`.
779pub struct CreateAgentProviderTurnRequest {
780    /// The `provider_name` field.
781    pub provider_name: String,
782    /// The `turn_id` field.
783    pub turn_id: String,
784    /// The `session_id` field.
785    pub session_id: String,
786    /// The `idempotency_key` field.
787    pub idempotency_key: String,
788    /// The `model` field.
789    pub model: String,
790    /// The `messages` field.
791    pub messages: Vec<AgentMessage>,
792    /// The `output` field.
793    pub output: AgentOutput,
794    /// The `metadata` field.
795    pub metadata: Option<AgentJson>,
796    /// The `execution_ref` field.
797    pub execution_ref: String,
798    /// The `model_options` field.
799    pub model_options: Option<AgentJson>,
800    /// The `timeout_seconds` field.
801    pub timeout_seconds: i32,
802    /// The `context` field.
803    pub context: Option<pb::RequestContext>,
804}
805
806#[derive(Debug, Clone, PartialEq)]
807/// Native enum for `gestalt.provider.v1.AgentOutput`.
808pub enum AgentOutput {
809    /// The `Text` variant.
810    Text(AgentTextOutput),
811    /// The `Structured` variant.
812    Structured(AgentStructuredOutput),
813}
814
815#[derive(Debug, Clone, Default, PartialEq, Eq)]
816/// Native message type for `gestalt.provider.v1.AgentTextOutput`.
817pub struct AgentTextOutput {}
818
819#[derive(Debug, Clone, PartialEq)]
820/// Native message type for `gestalt.provider.v1.AgentStructuredOutput`.
821pub struct AgentStructuredOutput {
822    /// The `schema` field.
823    pub schema: AgentJson,
824}
825
826impl AgentOutput {
827    /// Requests an unstructured text turn.
828    pub fn text() -> Self {
829        Self::Text(AgentTextOutput {})
830    }
831
832    /// Requests a structured turn with the supplied JSON Schema object.
833    pub fn structured_schema<T: Serialize>(schema: T) -> ProviderResult<Self> {
834        Ok(Self::Structured(AgentStructuredOutput {
835            schema: protocol::json_from_serializable(schema)?,
836        }))
837    }
838}
839
840#[derive(Debug, Clone, Default, PartialEq, Eq)]
841/// Native message type for `gestalt.provider.v1.GetAgentProviderTurnRequest`.
842pub struct GetAgentProviderTurnRequest {
843    /// The `provider_name` field.
844    pub provider_name: String,
845    /// The `turn_id` field.
846    pub turn_id: String,
847}
848
849#[derive(Debug, Clone, Default, PartialEq, Eq)]
850/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnsRequest`.
851pub struct ListAgentProviderTurnsRequest {
852    /// The `provider_name` field.
853    pub provider_name: String,
854    /// The `session_id` field.
855    pub session_id: String,
856    /// The `turn_ids` field.
857    pub turn_ids: Vec<String>,
858    /// The `status` field.
859    pub status: AgentExecutionStatus,
860    /// The `limit` field.
861    pub limit: i32,
862    /// The `summary_only` field.
863    pub summary_only: bool,
864}
865
866#[derive(Debug, Clone, Default, PartialEq)]
867/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnsResponse`.
868pub struct ListAgentProviderTurnsResponse {
869    /// The `turns` field.
870    pub turns: Vec<AgentTurn>,
871}
872
873#[derive(Debug, Clone, Default, PartialEq, Eq)]
874/// Native message type for `gestalt.provider.v1.CancelAgentProviderTurnRequest`.
875pub struct CancelAgentProviderTurnRequest {
876    /// The `provider_name` field.
877    pub provider_name: String,
878    /// The `turn_id` field.
879    pub turn_id: String,
880    /// The `reason` field.
881    pub reason: String,
882}
883
884#[derive(Debug, Clone, Default, PartialEq)]
885/// Native message type for `gestalt.provider.v1.AgentTurnEvent`.
886pub struct AgentTurnEvent {
887    /// The `id` field.
888    pub id: String,
889    /// The `turn_id` field.
890    pub turn_id: String,
891    /// The `seq` field.
892    pub seq: i64,
893    /// The `type` field.
894    pub r#type: String,
895    /// The `source` field.
896    pub source: String,
897    /// The `visibility` field.
898    pub visibility: String,
899    /// The `data` field.
900    pub data: Option<AgentJson>,
901    /// The `created_at` field.
902    pub created_at: Option<SystemTime>,
903    /// The `display` field.
904    pub display: Option<AgentTurnDisplay>,
905}
906
907#[derive(Debug, Clone, Default, PartialEq, Eq)]
908/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnEventsRequest`.
909pub struct ListAgentProviderTurnEventsRequest {
910    /// The `provider_name` field.
911    pub provider_name: String,
912    /// The `turn_id` field.
913    pub turn_id: String,
914    /// The `after_seq` field.
915    pub after_seq: i64,
916    /// The `limit` field.
917    pub limit: i32,
918}
919
920#[derive(Debug, Clone, Default, PartialEq)]
921/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnEventsResponse`.
922pub struct ListAgentProviderTurnEventsResponse {
923    /// The `events` field.
924    pub events: Vec<AgentTurnEvent>,
925}
926
927#[derive(Debug, Clone, Default, PartialEq, Eq)]
928/// Native message type for `gestalt.provider.v1.GetAgentProviderInteractionRequest`.
929pub struct GetAgentProviderInteractionRequest {
930    /// The `interaction_id` field.
931    pub interaction_id: String,
932}
933
934#[derive(Debug, Clone, Default, PartialEq, Eq)]
935/// Native message type for `gestalt.provider.v1.ListAgentProviderInteractionsRequest`.
936pub struct ListAgentProviderInteractionsRequest {
937    /// The `provider_name` field.
938    pub provider_name: String,
939    /// The `turn_id` field.
940    pub turn_id: String,
941}
942
943#[derive(Debug, Clone, Default, PartialEq)]
944/// Native message type for `gestalt.provider.v1.ListAgentProviderInteractionsResponse`.
945pub struct ListAgentProviderInteractionsResponse {
946    /// The `interactions` field.
947    pub interactions: Vec<AgentInteraction>,
948}
949
950#[derive(Debug, Clone, Default, PartialEq)]
951/// Native message type for `gestalt.provider.v1.ResolveAgentProviderInteractionRequest`.
952pub struct ResolveAgentProviderInteractionRequest {
953    /// The `provider_name` field.
954    pub provider_name: String,
955    /// The `interaction_id` field.
956    pub interaction_id: String,
957    /// The `resolution` field.
958    pub resolution: Option<AgentJson>,
959}
960
961#[derive(Debug, Clone, Default, PartialEq, Eq)]
962/// MCP-style behavior hints of a tool.
963pub struct AgentToolAnnotations {
964    /// The `read_only_hint` field.
965    pub read_only_hint: Option<bool>,
966    /// The `idempotent_hint` field.
967    pub idempotent_hint: Option<bool>,
968    /// The `destructive_hint` field.
969    pub destructive_hint: Option<bool>,
970    /// The `open_world_hint` field.
971    pub open_world_hint: Option<bool>,
972}
973
974#[derive(Debug, Clone, Default, PartialEq)]
975/// Native message type for `gestalt.provider.v1.ListedAgentTool`.
976pub struct ListedAgentTool {
977    /// The `id` field.
978    pub id: String,
979    /// The `mcp_name` field.
980    pub mcp_name: String,
981    /// The `title` field.
982    pub title: String,
983    /// The `description` field.
984    pub description: String,
985    /// The `input_schema` field.
986    pub input_schema: String,
987    /// The `output_schema` field.
988    pub output_schema: String,
989    /// The `annotations` field.
990    pub annotations: Option<AgentToolAnnotations>,
991    /// The `ref` field.
992    pub r#ref: Option<AgentToolRef>,
993    /// The `tags` field.
994    pub tags: Vec<String>,
995    /// The `search_text` field.
996    pub search_text: String,
997}
998
999/// Creates a native agent message.
1000pub fn new_agent_message(input: AgentMessage) -> ProviderResult<AgentMessage> {
1001    Ok(AgentMessage {
1002        role: input.role,
1003        text: input.text,
1004        parts: input
1005            .parts
1006            .into_iter()
1007            .map(new_agent_message_part)
1008            .collect::<ProviderResult<Vec<_>>>()?,
1009        metadata: input.metadata,
1010    })
1011}
1012
1013/// Creates a native agent message part.
1014pub fn new_agent_message_part(input: AgentMessagePart) -> ProviderResult<AgentMessagePart> {
1015    let mut part_type = input.r#type;
1016    if part_type == AgentMessagePartType::Unspecified {
1017        part_type = infer_agent_message_part_type(&input);
1018    }
1019    Ok(AgentMessagePart {
1020        r#type: part_type,
1021        text: input.text,
1022        json: input.json,
1023        tool_call: input.tool_call.map(new_agent_tool_call).transpose()?,
1024        tool_result: input.tool_result.map(new_agent_tool_result).transpose()?,
1025        image_ref: input.image_ref.map(new_agent_image_ref),
1026    })
1027}
1028
1029/// Creates a native agent tool-call payload.
1030pub fn new_agent_tool_call(
1031    input: AgentMessagePartToolCall,
1032) -> ProviderResult<AgentMessagePartToolCall> {
1033    Ok(AgentMessagePartToolCall {
1034        id: input.id,
1035        tool_id: input.tool_id,
1036        arguments: input.arguments,
1037    })
1038}
1039
1040/// Creates a native agent tool-result payload.
1041pub fn new_agent_tool_result(
1042    input: AgentMessagePartToolResult,
1043) -> ProviderResult<AgentMessagePartToolResult> {
1044    Ok(AgentMessagePartToolResult {
1045        tool_call_id: input.tool_call_id,
1046        status: input.status,
1047        content: input.content,
1048        output: input.output,
1049    })
1050}
1051
1052/// Creates a native agent image-reference payload.
1053pub fn new_agent_image_ref(input: AgentMessagePartImageRef) -> AgentMessagePartImageRef {
1054    AgentMessagePartImageRef {
1055        uri: input.uri,
1056        mime_type: input.mime_type,
1057    }
1058}
1059
1060/// Creates a native agent tool reference.
1061pub fn new_agent_tool_ref(input: AgentToolRef) -> AgentToolRef {
1062    AgentToolRef {
1063        app: input.app,
1064        operation: input.operation,
1065        connection: input.connection,
1066        instance: input.instance,
1067        title: input.title,
1068        description: input.description,
1069        credential_mode: input.credential_mode,
1070        system: input.system,
1071        run_as: input.run_as,
1072    }
1073}
1074
1075fn infer_agent_message_part_type(input: &AgentMessagePart) -> AgentMessagePartType {
1076    if input.tool_call.is_some() {
1077        AgentMessagePartType::ToolCall
1078    } else if input.tool_result.is_some() {
1079        AgentMessagePartType::ToolResult
1080    } else if input.image_ref.is_some() {
1081        AgentMessagePartType::ImageRef
1082    } else if input.json.is_some() {
1083        AgentMessagePartType::Json
1084    } else if !input.text.is_empty() {
1085        AgentMessagePartType::Text
1086    } else {
1087        AgentMessagePartType::Unspecified
1088    }
1089}
1090
1091fn json_from_struct(value: Option<Struct>) -> Option<AgentJson> {
1092    value.map(|value| protocol::json_from_struct(&value))
1093}
1094
1095fn struct_from_json(value: Option<AgentJson>) -> ProviderResult<Option<Struct>> {
1096    value.map(protocol::struct_from_json).transpose()
1097}
1098
1099fn value_from_json(value: Option<AgentJson>) -> Option<Value> {
1100    value.map(protocol::value_from_json)
1101}
1102
1103fn timestamp_from_time(value: Option<SystemTime>) -> Option<Timestamp> {
1104    value.map(protocol::timestamp_from_system_time)
1105}
1106
1107pub(crate) fn agent_tool_ref_from_proto(value: pb::AgentToolRef) -> AgentToolRef {
1108    AgentToolRef {
1109        app: value.app,
1110        operation: value.operation,
1111        connection: value.connection,
1112        instance: value.instance,
1113        title: value.title,
1114        description: value.description,
1115        credential_mode: value.credential_mode,
1116        system: value.system,
1117        run_as: agent_run_as_context_from_proto(value.run_as),
1118    }
1119}
1120
1121fn agent_run_as_context_from_proto(value: Option<pb::SubjectContext>) -> Option<Subject> {
1122    value.map(|value| Subject {
1123        id: value.id,
1124        email: value.email,
1125        display_name: value.display_name,
1126    })
1127}
1128
1129pub(crate) fn message_from_proto(value: pb::AgentMessage) -> AgentMessage {
1130    AgentMessage {
1131        role: value.role,
1132        text: value.text,
1133        parts: value
1134            .parts
1135            .into_iter()
1136            .map(message_part_from_proto)
1137            .collect(),
1138        metadata: json_from_struct(value.metadata),
1139    }
1140}
1141
1142pub(crate) fn message_to_proto(value: AgentMessage) -> ProviderResult<pb::AgentMessage> {
1143    Ok(pb::AgentMessage {
1144        role: value.role,
1145        text: value.text,
1146        parts: value
1147            .parts
1148            .into_iter()
1149            .map(message_part_to_proto)
1150            .collect::<ProviderResult<Vec<_>>>()?,
1151        metadata: struct_from_json(value.metadata)?,
1152    })
1153}
1154
1155fn message_part_from_proto(value: pb::AgentMessagePart) -> AgentMessagePart {
1156    AgentMessagePart {
1157        r#type: AgentMessagePartType::from_i32_lossy(value.r#type),
1158        text: value.text,
1159        json: json_from_struct(value.json),
1160        tool_call: value.tool_call.map(|value| AgentMessagePartToolCall {
1161            id: value.id,
1162            tool_id: value.tool_id,
1163            arguments: json_from_struct(value.arguments),
1164        }),
1165        tool_result: value.tool_result.map(|value| AgentMessagePartToolResult {
1166            tool_call_id: value.tool_call_id,
1167            status: value.status,
1168            content: value.content,
1169            output: json_from_struct(value.output),
1170        }),
1171        image_ref: value.image_ref.map(|value| AgentMessagePartImageRef {
1172            uri: value.uri,
1173            mime_type: value.mime_type,
1174        }),
1175    }
1176}
1177
1178fn message_part_to_proto(value: AgentMessagePart) -> ProviderResult<pb::AgentMessagePart> {
1179    Ok(pb::AgentMessagePart {
1180        r#type: value.r#type.as_i32(),
1181        text: value.text,
1182        json: struct_from_json(value.json)?,
1183        tool_call: value
1184            .tool_call
1185            .map(|value| -> ProviderResult<pb::AgentMessagePartToolCall> {
1186                Ok(pb::AgentMessagePartToolCall {
1187                    id: value.id,
1188                    tool_id: value.tool_id,
1189                    arguments: struct_from_json(value.arguments)?,
1190                })
1191            })
1192            .transpose()?,
1193        tool_result: value
1194            .tool_result
1195            .map(|value| -> ProviderResult<pb::AgentMessagePartToolResult> {
1196                Ok(pb::AgentMessagePartToolResult {
1197                    tool_call_id: value.tool_call_id,
1198                    status: value.status,
1199                    content: value.content,
1200                    output: struct_from_json(value.output)?,
1201                })
1202            })
1203            .transpose()?,
1204        image_ref: value.image_ref.map(|value| pb::AgentMessagePartImageRef {
1205            uri: value.uri,
1206            mime_type: value.mime_type,
1207        }),
1208    })
1209}
1210
1211fn session_to_proto(value: AgentSession) -> ProviderResult<pb::AgentSession> {
1212    Ok(pb::AgentSession {
1213        id: value.id,
1214        provider_name: value.provider_name,
1215        model: value.model,
1216        client_ref: value.client_ref,
1217        state: value.state.as_i32(),
1218        metadata: struct_from_json(value.metadata)?,
1219        created_by_subject_id: value.created_by_subject_id.clone().unwrap_or_default(),
1220        created_at: timestamp_from_time(value.created_at),
1221        updated_at: timestamp_from_time(value.updated_at),
1222        last_turn_at: timestamp_from_time(value.last_turn_at),
1223    })
1224}
1225
1226fn turn_to_proto(value: AgentTurn) -> ProviderResult<pb::AgentTurn> {
1227    Ok(pb::AgentTurn {
1228        id: value.id,
1229        session_id: value.session_id,
1230        provider_name: value.provider_name,
1231        model: value.model,
1232        status: value.status.as_i32(),
1233        messages: value
1234            .messages
1235            .into_iter()
1236            .map(message_to_proto)
1237            .collect::<ProviderResult<Vec<_>>>()?,
1238        output: agent_turn_output_to_proto(value.output)?,
1239        status_message: value.status_message,
1240        created_by_subject_id: value.created_by_subject_id.clone().unwrap_or_default(),
1241        created_at: timestamp_from_time(value.created_at),
1242        started_at: timestamp_from_time(value.started_at),
1243        completed_at: timestamp_from_time(value.completed_at),
1244        execution_ref: value.execution_ref,
1245    })
1246}
1247
1248fn display_to_proto(value: AgentTurnDisplay) -> pb::AgentTurnDisplay {
1249    pb::AgentTurnDisplay {
1250        kind: value.kind,
1251        phase: value.phase,
1252        text: value.text,
1253        label: value.label,
1254        r#ref: value.r#ref,
1255        parent_ref: value.parent_ref,
1256        input: value_from_json(value.input),
1257        output: value_from_json(value.output),
1258        error: value_from_json(value.error),
1259        action: value.action,
1260        format: value.format,
1261        language: value.language,
1262    }
1263}
1264
1265fn agent_turn_output_to_proto(
1266    value: Option<AgentTurnOutput>,
1267) -> ProviderResult<Option<pb::agent_turn::Output>> {
1268    match value {
1269        Some(AgentTurnOutput::Text(output)) => Ok(Some(pb::agent_turn::Output::Text(
1270            pb::AgentTurnTextOutput { text: output.text },
1271        ))),
1272        Some(AgentTurnOutput::Structured(output)) => Ok(Some(pb::agent_turn::Output::Structured(
1273            pb::AgentTurnStructuredOutput {
1274                text: output.text,
1275                value: struct_from_json(output.value)?,
1276            },
1277        ))),
1278        None => Ok(None),
1279    }
1280}
1281
1282fn agent_output_from_proto(value: Option<pb::AgentOutput>) -> ProviderResult<Option<AgentOutput>> {
1283    match value.and_then(|output| output.kind) {
1284        Some(pb::agent_output::Kind::Text(_)) => Ok(Some(AgentOutput::Text(AgentTextOutput {}))),
1285        Some(pb::agent_output::Kind::Structured(output)) => {
1286            let schema = json_from_struct(output.schema)
1287                .ok_or_else(|| crate::Error::bad_request("output.structured.schema is required"))?;
1288            Ok(Some(AgentOutput::Structured(AgentStructuredOutput {
1289                schema,
1290            })))
1291        }
1292        None => Ok(None),
1293    }
1294}
1295
1296fn required_agent_output_from_proto(value: Option<pb::AgentOutput>) -> ProviderResult<AgentOutput> {
1297    agent_output_from_proto(value)?
1298        .ok_or_else(|| crate::Error::bad_request("create turn output is required"))
1299}
1300
1301fn event_to_proto(value: AgentTurnEvent) -> ProviderResult<pb::AgentTurnEvent> {
1302    Ok(pb::AgentTurnEvent {
1303        id: value.id,
1304        turn_id: value.turn_id,
1305        seq: value.seq,
1306        r#type: value.r#type,
1307        source: value.source,
1308        visibility: value.visibility,
1309        data: struct_from_json(value.data)?,
1310        created_at: timestamp_from_time(value.created_at),
1311        display: value.display.map(display_to_proto),
1312    })
1313}
1314
1315fn interaction_to_proto(value: AgentInteraction) -> ProviderResult<pb::AgentInteraction> {
1316    Ok(pb::AgentInteraction {
1317        id: value.id,
1318        r#type: value.r#type.as_i32(),
1319        state: value.state.as_i32(),
1320        title: value.title,
1321        prompt: value.prompt,
1322        request: struct_from_json(value.request)?,
1323        resolution: struct_from_json(value.resolution)?,
1324        created_at: timestamp_from_time(value.created_at),
1325        resolved_at: timestamp_from_time(value.resolved_at),
1326        turn_id: value.turn_id,
1327        session_id: value.session_id,
1328    })
1329}
1330
1331fn capabilities_to_proto(value: AgentProviderCapabilities) -> pb::AgentProviderCapabilities {
1332    pb::AgentProviderCapabilities {
1333        streaming_text: value.streaming_text,
1334        tool_calls: value.tool_calls,
1335        parallel_tool_calls: value.parallel_tool_calls,
1336        interactions: value.interactions,
1337        resumable_turns: value.resumable_turns,
1338        reasoning_summaries: value.reasoning_summaries,
1339        bounded_list_hydration: value.bounded_list_hydration,
1340        supported_tool_sources: value
1341            .supported_tool_sources
1342            .into_iter()
1343            .map(AgentToolSourceMode::as_i32)
1344            .collect(),
1345        supports_session_start: value.supports_session_start,
1346        supports_prepared_workspace: value.supports_prepared_workspace,
1347    }
1348}
1349
1350fn create_session_request_from_proto(
1351    value: pb::CreateAgentProviderSessionRequest,
1352) -> CreateAgentProviderSessionRequest {
1353    CreateAgentProviderSessionRequest {
1354        idempotency_key: value.idempotency_key,
1355        model: value.model,
1356        client_ref: value.client_ref,
1357        metadata: json_from_struct(value.metadata),
1358        session_start: value.session_start.map(|value| AgentSessionStartConfig {
1359            hooks: value
1360                .hooks
1361                .into_iter()
1362                .map(|hook| AgentSessionStartHook {
1363                    id: hook.id,
1364                    r#type: hook.r#type,
1365                    command: hook.command,
1366                    cwd: hook.cwd,
1367                    timeout: hook.timeout,
1368                    env: hook.env.into_iter().collect(),
1369                    output: hook.output.map(|output| AgentSessionStartHookOutput {
1370                        additional_context: output.additional_context,
1371                        metadata: output.metadata,
1372                    }),
1373                })
1374                .collect(),
1375        }),
1376        prepared_workspace: value
1377            .prepared_workspace
1378            .map(|value| AgentPreparedWorkspace {
1379                root: value.root,
1380                cwd: value.cwd,
1381            }),
1382        tools: value.tools.map(agent_tool_config_from_proto),
1383    }
1384}
1385
1386fn create_turn_request_from_proto(
1387    value: pb::CreateAgentProviderTurnRequest,
1388) -> ProviderResult<CreateAgentProviderTurnRequest> {
1389    if value.timeout_seconds < 0 {
1390        return Err(crate::Error::bad_request(
1391            "agent create turn timeout_seconds must not be negative",
1392        ));
1393    }
1394    Ok(CreateAgentProviderTurnRequest {
1395        provider_name: value.provider_name,
1396        turn_id: value.turn_id,
1397        session_id: value.session_id,
1398        idempotency_key: value.idempotency_key,
1399        model: value.model,
1400        messages: value.messages.into_iter().map(message_from_proto).collect(),
1401        output: required_agent_output_from_proto(value.output)?,
1402        metadata: json_from_struct(value.metadata),
1403        execution_ref: value.execution_ref,
1404        model_options: json_from_struct(value.model_options),
1405        timeout_seconds: value.timeout_seconds,
1406        context: value.context,
1407    })
1408}
1409
1410fn listed_tool_from_proto(value: pb::ListedAgentTool) -> ListedAgentTool {
1411    ListedAgentTool {
1412        id: value.id,
1413        mcp_name: value.mcp_name,
1414        title: value.title,
1415        description: value.description,
1416        input_schema: value.input_schema,
1417        output_schema: value.output_schema,
1418        annotations: value.annotations.map(|annotations| AgentToolAnnotations {
1419            read_only_hint: annotations.read_only_hint,
1420            idempotent_hint: annotations.idempotent_hint,
1421            destructive_hint: annotations.destructive_hint,
1422            open_world_hint: annotations.open_world_hint,
1423        }),
1424        r#ref: value.r#ref.map(agent_tool_ref_from_proto),
1425        tags: value.tags,
1426        search_text: value.search_text,
1427    }
1428}
1429
1430fn agent_tool_config_from_proto(value: pb::AgentToolConfig) -> AgentToolConfig {
1431    let source = match value.source {
1432        Some(pb::agent_tool_config::Source::None(_)) => {
1433            Some(AgentToolConfigSource::None(AgentNoTools {}))
1434        }
1435        Some(pb::agent_tool_config::Source::Catalog(catalog)) => {
1436            Some(AgentToolConfigSource::Catalog(AgentCatalogToolConfig {
1437                refs: catalog
1438                    .refs
1439                    .into_iter()
1440                    .map(agent_tool_ref_from_proto)
1441                    .collect(),
1442                tools: catalog
1443                    .tools
1444                    .into_iter()
1445                    .map(listed_tool_from_proto)
1446                    .collect(),
1447            }))
1448        }
1449        None => None,
1450    };
1451    AgentToolConfig { source }
1452}
1453
1454#[async_trait]
1455/// Provider trait for serving the Gestalt agent-provider protocol.
1456pub trait AgentProvider: Send + Sync + 'static {
1457    /// Configures the provider before it starts serving requests.
1458    async fn configure(
1459        &self,
1460        _name: &str,
1461        _config: serde_json::Map<String, serde_json::Value>,
1462    ) -> ProviderResult<()> {
1463        Ok(())
1464    }
1465
1466    /// Returns runtime metadata that should augment the static manifest.
1467    fn metadata(&self) -> Option<RuntimeMetadata> {
1468        None
1469    }
1470
1471    /// Returns non-fatal warnings the host should surface to users.
1472    fn warnings(&self) -> Vec<String> {
1473        Vec::new()
1474    }
1475
1476    /// Performs an optional health check.
1477    async fn health_check(&self) -> ProviderResult<()> {
1478        Ok(())
1479    }
1480
1481    /// Starts provider-owned background work after configuration.
1482    async fn start(&self) -> ProviderResult<()> {
1483        Ok(())
1484    }
1485
1486    /// Shuts the provider down before the runtime exits.
1487    async fn close(&self) -> ProviderResult<()> {
1488        Ok(())
1489    }
1490
1491    /// Creates or idempotently returns an agent session.
1492    ///
1493    /// Mints the session id returned on the [`AgentSession`]. Must be
1494    /// idempotent on `idempotency_key` scoped per subject
1495    /// (`context.subject.id`); an empty key always creates.
1496    async fn create_session(
1497        &self,
1498        _request: CreateAgentProviderSessionRequest,
1499    ) -> ProviderResult<AgentSession> {
1500        Err(crate::Error::unimplemented(
1501            "agent create session is not implemented",
1502        ))
1503    }
1504
1505    /// Returns one agent session by ID.
1506    async fn get_session(
1507        &self,
1508        _request: GetAgentProviderSessionRequest,
1509    ) -> ProviderResult<AgentSession> {
1510        Err(crate::Error::unimplemented(
1511            "agent get session is not implemented",
1512        ))
1513    }
1514
1515    /// Lists agent sessions visible to the request subject.
1516    async fn list_sessions(
1517        &self,
1518        _request: ListAgentProviderSessionsRequest,
1519    ) -> ProviderResult<ListAgentProviderSessionsResponse> {
1520        Err(crate::Error::unimplemented(
1521            "agent list sessions is not implemented",
1522        ))
1523    }
1524
1525    /// Updates mutable agent session metadata or state.
1526    async fn update_session(
1527        &self,
1528        _request: UpdateAgentProviderSessionRequest,
1529    ) -> ProviderResult<AgentSession> {
1530        Err(crate::Error::unimplemented(
1531            "agent update session is not implemented",
1532        ))
1533    }
1534
1535    /// Starts or idempotently returns an agent turn.
1536    async fn create_turn(
1537        &self,
1538        _request: CreateAgentProviderTurnRequest,
1539    ) -> ProviderResult<AgentTurn> {
1540        Err(crate::Error::unimplemented(
1541            "agent create turn is not implemented",
1542        ))
1543    }
1544
1545    /// Returns one agent turn by ID.
1546    async fn get_turn(&self, _request: GetAgentProviderTurnRequest) -> ProviderResult<AgentTurn> {
1547        Err(crate::Error::unimplemented(
1548            "agent get turn is not implemented",
1549        ))
1550    }
1551
1552    /// Lists turns for a session or query.
1553    async fn list_turns(
1554        &self,
1555        _request: ListAgentProviderTurnsRequest,
1556    ) -> ProviderResult<ListAgentProviderTurnsResponse> {
1557        Err(crate::Error::unimplemented(
1558            "agent list turns is not implemented",
1559        ))
1560    }
1561
1562    /// Requests cancellation of a running or pending turn.
1563    async fn cancel_turn(
1564        &self,
1565        _request: CancelAgentProviderTurnRequest,
1566    ) -> ProviderResult<AgentTurn> {
1567        Err(crate::Error::unimplemented(
1568            "agent cancel turn is not implemented",
1569        ))
1570    }
1571
1572    /// Lists ordered events emitted by a turn.
1573    async fn list_turn_events(
1574        &self,
1575        _request: ListAgentProviderTurnEventsRequest,
1576    ) -> ProviderResult<ListAgentProviderTurnEventsResponse> {
1577        Err(crate::Error::unimplemented(
1578            "agent list turn events is not implemented",
1579        ))
1580    }
1581
1582    /// Returns one pending or resolved interaction.
1583    async fn get_interaction(
1584        &self,
1585        _request: GetAgentProviderInteractionRequest,
1586    ) -> ProviderResult<AgentInteraction> {
1587        Err(crate::Error::unimplemented(
1588            "agent get interaction is not implemented",
1589        ))
1590    }
1591
1592    /// Lists interactions associated with a turn.
1593    async fn list_interactions(
1594        &self,
1595        _request: ListAgentProviderInteractionsRequest,
1596    ) -> ProviderResult<ListAgentProviderInteractionsResponse> {
1597        Err(crate::Error::unimplemented(
1598            "agent list interactions is not implemented",
1599        ))
1600    }
1601
1602    /// Records a response to a pending interaction.
1603    async fn resolve_interaction(
1604        &self,
1605        _request: ResolveAgentProviderInteractionRequest,
1606    ) -> ProviderResult<AgentInteraction> {
1607        Err(crate::Error::unimplemented(
1608            "agent resolve interaction is not implemented",
1609        ))
1610    }
1611
1612    /// Returns the provider's supported agent features.
1613    async fn get_capabilities(
1614        &self,
1615        _request: GetAgentProviderCapabilitiesRequest,
1616    ) -> ProviderResult<AgentProviderCapabilities> {
1617        Err(crate::Error::unimplemented(
1618            "agent get capabilities is not implemented",
1619        ))
1620    }
1621}
1622
1623#[derive(Clone)]
1624pub(crate) struct AgentServer<P> {
1625    provider: Arc<P>,
1626}
1627
1628impl<P> AgentServer<P> {
1629    pub(crate) fn new(provider: Arc<P>) -> Self {
1630        Self { provider }
1631    }
1632}
1633
1634#[async_trait]
1635impl<P> pb::agent_server::Agent for AgentServer<P>
1636where
1637    P: AgentProvider,
1638{
1639    async fn create_session(
1640        &self,
1641        request: GrpcRequest<pb::CreateAgentProviderSessionRequest>,
1642    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1643        let request = request.into_inner();
1644        let context = request.context.clone();
1645        let session = scope_request_context(
1646            context,
1647            self.provider
1648                .create_session(create_session_request_from_proto(request)),
1649        )
1650        .await
1651        .map_err(|error| rpc_status("agent create session", error))?;
1652        Ok(GrpcResponse::new(session_to_proto(session).map_err(
1653            |error| rpc_status("agent create session", error),
1654        )?))
1655    }
1656
1657    async fn get_session(
1658        &self,
1659        request: GrpcRequest<pb::GetAgentProviderSessionRequest>,
1660    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1661        let request = request.into_inner();
1662        let context = request.context.clone();
1663        let session = scope_request_context(
1664            context,
1665            self.provider.get_session(GetAgentProviderSessionRequest {
1666                provider_name: request.provider_name,
1667                session_id: request.session_id,
1668            }),
1669        )
1670        .await
1671        .map_err(|error| rpc_status("agent get session", error))?;
1672        Ok(GrpcResponse::new(
1673            session_to_proto(session).map_err(|error| rpc_status("agent get session", error))?,
1674        ))
1675    }
1676
1677    async fn list_sessions(
1678        &self,
1679        request: GrpcRequest<pb::ListAgentProviderSessionsRequest>,
1680    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderSessionsResponse>, Status> {
1681        let request = request.into_inner();
1682        let context = request.context.clone();
1683        let response = scope_request_context(
1684            context,
1685            self.provider
1686                .list_sessions(ListAgentProviderSessionsRequest {
1687                    provider_name: request.provider_name,
1688                    session_ids: request.session_ids,
1689                    state: AgentSessionState::from_i32_lossy(request.state),
1690                    limit: request.limit,
1691                    summary_only: request.summary_only,
1692                }),
1693        )
1694        .await
1695        .map_err(|error| rpc_status("agent list sessions", error))?;
1696        Ok(GrpcResponse::new(pb::ListAgentProviderSessionsResponse {
1697            sessions: response
1698                .sessions
1699                .into_iter()
1700                .map(session_to_proto)
1701                .collect::<ProviderResult<Vec<_>>>()
1702                .map_err(|error| rpc_status("agent list sessions", error))?,
1703        }))
1704    }
1705
1706    async fn update_session(
1707        &self,
1708        request: GrpcRequest<pb::UpdateAgentProviderSessionRequest>,
1709    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1710        let request = request.into_inner();
1711        let context = request.context.clone();
1712        let session = scope_request_context(
1713            context,
1714            self.provider
1715                .update_session(UpdateAgentProviderSessionRequest {
1716                    provider_name: request.provider_name,
1717                    session_id: request.session_id,
1718                    client_ref: request.client_ref,
1719                    state: AgentSessionState::from_i32_lossy(request.state),
1720                    metadata: json_from_struct(request.metadata),
1721                }),
1722        )
1723        .await
1724        .map_err(|error| rpc_status("agent update session", error))?;
1725        Ok(GrpcResponse::new(session_to_proto(session).map_err(
1726            |error| rpc_status("agent update session", error),
1727        )?))
1728    }
1729
1730    async fn create_turn(
1731        &self,
1732        request: GrpcRequest<pb::CreateAgentProviderTurnRequest>,
1733    ) -> std::result::Result<GrpcResponse<pb::AgentTurn>, Status> {
1734        let request = request.into_inner();
1735        let context = request.context.clone();
1736        let turn = scope_request_context(
1737            context,
1738            self.provider.create_turn(
1739                create_turn_request_from_proto(request)
1740                    .map_err(|error| rpc_status("agent create turn", error))?,
1741            ),
1742        )
1743        .await
1744        .map_err(|error| rpc_status("agent create turn", error))?;
1745        Ok(GrpcResponse::new(
1746            turn_to_proto(turn).map_err(|error| rpc_status("agent create turn", error))?,
1747        ))
1748    }
1749
1750    async fn get_turn(
1751        &self,
1752        request: GrpcRequest<pb::GetAgentProviderTurnRequest>,
1753    ) -> std::result::Result<GrpcResponse<pb::AgentTurn>, Status> {
1754        let request = request.into_inner();
1755        let context = request.context.clone();
1756        let turn = scope_request_context(
1757            context,
1758            self.provider.get_turn(GetAgentProviderTurnRequest {
1759                provider_name: request.provider_name,
1760                turn_id: request.turn_id,
1761            }),
1762        )
1763        .await
1764        .map_err(|error| rpc_status("agent get turn", error))?;
1765        Ok(GrpcResponse::new(
1766            turn_to_proto(turn).map_err(|error| rpc_status("agent get turn", error))?,
1767        ))
1768    }
1769
1770    async fn list_turns(
1771        &self,
1772        request: GrpcRequest<pb::ListAgentProviderTurnsRequest>,
1773    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderTurnsResponse>, Status> {
1774        let request = request.into_inner();
1775        let context = request.context.clone();
1776        let response = scope_request_context(
1777            context,
1778            self.provider.list_turns(ListAgentProviderTurnsRequest {
1779                provider_name: request.provider_name,
1780                session_id: request.session_id,
1781                turn_ids: request.turn_ids,
1782                status: AgentExecutionStatus::from_i32_lossy(request.status),
1783                limit: request.limit,
1784                summary_only: request.summary_only,
1785            }),
1786        )
1787        .await
1788        .map_err(|error| rpc_status("agent list turns", error))?;
1789        Ok(GrpcResponse::new(pb::ListAgentProviderTurnsResponse {
1790            turns: response
1791                .turns
1792                .into_iter()
1793                .map(turn_to_proto)
1794                .collect::<ProviderResult<Vec<_>>>()
1795                .map_err(|error| rpc_status("agent list turns", error))?,
1796        }))
1797    }
1798
1799    async fn cancel_turn(
1800        &self,
1801        request: GrpcRequest<pb::CancelAgentProviderTurnRequest>,
1802    ) -> std::result::Result<GrpcResponse<pb::AgentTurn>, Status> {
1803        let request = request.into_inner();
1804        let context = request.context.clone();
1805        let turn = scope_request_context(
1806            context,
1807            self.provider.cancel_turn(CancelAgentProviderTurnRequest {
1808                provider_name: request.provider_name,
1809                turn_id: request.turn_id,
1810                reason: request.reason,
1811            }),
1812        )
1813        .await
1814        .map_err(|error| rpc_status("agent cancel turn", error))?;
1815        Ok(GrpcResponse::new(
1816            turn_to_proto(turn).map_err(|error| rpc_status("agent cancel turn", error))?,
1817        ))
1818    }
1819
1820    async fn list_turn_events(
1821        &self,
1822        request: GrpcRequest<pb::ListAgentProviderTurnEventsRequest>,
1823    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderTurnEventsResponse>, Status> {
1824        let request = request.into_inner();
1825        let context = request.context.clone();
1826        let response = scope_request_context(
1827            context,
1828            self.provider
1829                .list_turn_events(ListAgentProviderTurnEventsRequest {
1830                    provider_name: request.provider_name,
1831                    turn_id: request.turn_id,
1832                    after_seq: request.after_seq,
1833                    limit: request.limit,
1834                }),
1835        )
1836        .await
1837        .map_err(|error| rpc_status("agent list turn events", error))?;
1838        Ok(GrpcResponse::new(pb::ListAgentProviderTurnEventsResponse {
1839            events: response
1840                .events
1841                .into_iter()
1842                .map(event_to_proto)
1843                .collect::<ProviderResult<Vec<_>>>()
1844                .map_err(|error| rpc_status("agent list turn events", error))?,
1845        }))
1846    }
1847
1848    async fn get_interaction(
1849        &self,
1850        request: GrpcRequest<pb::GetAgentProviderInteractionRequest>,
1851    ) -> std::result::Result<GrpcResponse<pb::AgentInteraction>, Status> {
1852        let request = request.into_inner();
1853        let context = request.context.clone();
1854        let interaction = scope_request_context(
1855            context,
1856            self.provider
1857                .get_interaction(GetAgentProviderInteractionRequest {
1858                    interaction_id: request.interaction_id,
1859                }),
1860        )
1861        .await
1862        .map_err(|error| rpc_status("agent get interaction", error))?;
1863        Ok(GrpcResponse::new(
1864            interaction_to_proto(interaction)
1865                .map_err(|error| rpc_status("agent get interaction", error))?,
1866        ))
1867    }
1868
1869    async fn list_interactions(
1870        &self,
1871        request: GrpcRequest<pb::ListAgentProviderInteractionsRequest>,
1872    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderInteractionsResponse>, Status> {
1873        let request = request.into_inner();
1874        let context = request.context.clone();
1875        let response = scope_request_context(
1876            context,
1877            self.provider
1878                .list_interactions(ListAgentProviderInteractionsRequest {
1879                    provider_name: request.provider_name,
1880                    turn_id: request.turn_id,
1881                }),
1882        )
1883        .await
1884        .map_err(|error| rpc_status("agent list interactions", error))?;
1885        Ok(GrpcResponse::new(
1886            pb::ListAgentProviderInteractionsResponse {
1887                interactions: response
1888                    .interactions
1889                    .into_iter()
1890                    .map(interaction_to_proto)
1891                    .collect::<ProviderResult<Vec<_>>>()
1892                    .map_err(|error| rpc_status("agent list interactions", error))?,
1893            },
1894        ))
1895    }
1896
1897    async fn resolve_interaction(
1898        &self,
1899        request: GrpcRequest<pb::ResolveAgentProviderInteractionRequest>,
1900    ) -> std::result::Result<GrpcResponse<pb::AgentInteraction>, Status> {
1901        let request = request.into_inner();
1902        let context = request.context.clone();
1903        let interaction = scope_request_context(
1904            context,
1905            self.provider
1906                .resolve_interaction(ResolveAgentProviderInteractionRequest {
1907                    provider_name: request.provider_name,
1908                    interaction_id: request.interaction_id,
1909                    resolution: json_from_struct(request.resolution),
1910                }),
1911        )
1912        .await
1913        .map_err(|error| rpc_status("agent resolve interaction", error))?;
1914        Ok(GrpcResponse::new(
1915            interaction_to_proto(interaction)
1916                .map_err(|error| rpc_status("agent resolve interaction", error))?,
1917        ))
1918    }
1919
1920    async fn get_capabilities(
1921        &self,
1922        _request: GrpcRequest<pb::GetAgentProviderCapabilitiesRequest>,
1923    ) -> std::result::Result<GrpcResponse<pb::AgentProviderCapabilities>, Status> {
1924        let capabilities = self
1925            .provider
1926            .get_capabilities(GetAgentProviderCapabilitiesRequest {})
1927            .await
1928            .map_err(|error| rpc_status("agent get capabilities", error))?;
1929        Ok(GrpcResponse::new(capabilities_to_proto(capabilities)))
1930    }
1931}