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 `created_by_subject_id` field.
604    pub created_by_subject_id: Option<String>,
605    /// The `subject` field.
606    pub subject: Option<Subject>,
607    /// The `session_start` field.
608    pub session_start: Option<AgentSessionStartConfig>,
609    /// The `prepared_workspace` field.
610    pub prepared_workspace: Option<AgentPreparedWorkspace>,
611    /// The `tools` field.
612    pub tools: Option<AgentToolConfig>,
613}
614
615#[derive(Debug, Clone, Default, PartialEq, Eq)]
616/// Native message type for `gestalt.provider.v1.AgentSessionStartConfig`.
617pub struct AgentSessionStartConfig {
618    /// The `hooks` field.
619    pub hooks: Vec<AgentSessionStartHook>,
620}
621
622#[derive(Debug, Clone, Default, PartialEq, Eq)]
623/// Native message type for `gestalt.provider.v1.AgentSessionStartHook`.
624pub struct AgentSessionStartHook {
625    /// The `id` field.
626    pub id: String,
627    /// The `type` field.
628    pub r#type: String,
629    /// The `command` field.
630    pub command: Vec<String>,
631    /// The `cwd` field.
632    pub cwd: String,
633    /// The `timeout` field.
634    pub timeout: String,
635    /// The `env` field.
636    pub env: std::collections::HashMap<String, String>,
637    /// The `output` field.
638    pub output: Option<AgentSessionStartHookOutput>,
639}
640
641#[derive(Debug, Clone, Default, PartialEq, Eq)]
642/// Native message type for `gestalt.provider.v1.AgentSessionStartHookOutput`.
643pub struct AgentSessionStartHookOutput {
644    /// The `additional_context` field.
645    pub additional_context: bool,
646    /// The `metadata` field.
647    pub metadata: bool,
648}
649
650#[derive(Debug, Clone, Default, PartialEq, Eq)]
651/// Native message type for `gestalt.provider.v1.GetAgentProviderSessionRequest`.
652pub struct GetAgentProviderSessionRequest {
653    /// The `provider_name` field.
654    pub provider_name: String,
655    /// The `session_id` field.
656    pub session_id: String,
657    /// The `subject` field.
658    pub subject: Option<Subject>,
659}
660
661#[derive(Debug, Clone, Default, PartialEq, Eq)]
662/// Native message type for `gestalt.provider.v1.ListAgentProviderSessionsRequest`.
663pub struct ListAgentProviderSessionsRequest {
664    /// The `provider_name` field.
665    pub provider_name: String,
666    /// The `subject` field.
667    pub subject: Option<Subject>,
668    /// The `session_ids` field.
669    pub session_ids: Vec<String>,
670    /// The `state` field.
671    pub state: AgentSessionState,
672    /// The `limit` field.
673    pub limit: i32,
674    /// The `summary_only` field.
675    pub summary_only: bool,
676}
677
678#[derive(Debug, Clone, Default, PartialEq)]
679/// Native message type for `gestalt.provider.v1.ListAgentProviderSessionsResponse`.
680pub struct ListAgentProviderSessionsResponse {
681    /// The `sessions` field.
682    pub sessions: Vec<AgentSession>,
683}
684
685#[derive(Debug, Clone, Default, PartialEq)]
686/// Native message type for `gestalt.provider.v1.UpdateAgentProviderSessionRequest`.
687pub struct UpdateAgentProviderSessionRequest {
688    /// The `provider_name` field.
689    pub provider_name: String,
690    /// The `session_id` field.
691    pub session_id: String,
692    /// The `client_ref` field.
693    pub client_ref: String,
694    /// The `state` field.
695    pub state: AgentSessionState,
696    /// The `metadata` field.
697    pub metadata: Option<AgentJson>,
698    /// The `subject` field.
699    pub subject: Option<Subject>,
700}
701
702#[derive(Debug, Clone, Default, PartialEq)]
703/// Native message type for `gestalt.provider.v1.AgentTurn`.
704pub struct AgentTurn {
705    /// The `id` field.
706    pub id: String,
707    /// The `session_id` field.
708    pub session_id: String,
709    /// The `provider_name` field.
710    pub provider_name: String,
711    /// The `model` field.
712    pub model: String,
713    /// The `status` field.
714    pub status: AgentExecutionStatus,
715    /// The `messages` field.
716    pub messages: Vec<AgentMessage>,
717    /// The `output` field.
718    pub output: Option<AgentTurnOutput>,
719    /// The `status_message` field.
720    pub status_message: String,
721    /// The `created_by_subject_id` field.
722    pub created_by_subject_id: Option<String>,
723    /// The `created_at` field.
724    pub created_at: Option<SystemTime>,
725    /// The `started_at` field.
726    pub started_at: Option<SystemTime>,
727    /// The `completed_at` field.
728    pub completed_at: Option<SystemTime>,
729    /// The `execution_ref` field.
730    pub execution_ref: String,
731}
732
733#[derive(Debug, Clone, PartialEq)]
734/// The structured-or-text output of a finished turn.
735pub enum AgentTurnOutput {
736    /// The `Text` variant.
737    Text(AgentTurnTextOutput),
738    /// The `Structured` variant.
739    Structured(AgentTurnStructuredOutput),
740}
741
742#[derive(Debug, Clone, Default, PartialEq, Eq)]
743/// Native message type for `gestalt.provider.v1.AgentTurnTextOutput`.
744pub struct AgentTurnTextOutput {
745    /// The `text` field.
746    pub text: String,
747}
748
749#[derive(Debug, Clone, Default, PartialEq)]
750/// Native message type for `gestalt.provider.v1.AgentTurnStructuredOutput`.
751pub struct AgentTurnStructuredOutput {
752    /// The `text` field.
753    pub text: String,
754    /// The `value` field.
755    pub value: Option<AgentJson>,
756}
757
758#[derive(Debug, Clone, Default, PartialEq)]
759/// Native message type for `gestalt.provider.v1.AgentTurnDisplay`.
760pub struct AgentTurnDisplay {
761    /// The `kind` field.
762    pub kind: String,
763    /// The `phase` field.
764    pub phase: String,
765    /// The `text` field.
766    pub text: String,
767    /// The `label` field.
768    pub label: String,
769    /// The `ref` field.
770    pub r#ref: String,
771    /// The `parent_ref` field.
772    pub parent_ref: String,
773    /// The `input` field.
774    pub input: Option<AgentJson>,
775    /// The `output` field.
776    pub output: Option<AgentJson>,
777    /// The `error` field.
778    pub error: Option<AgentJson>,
779    /// The `action` field.
780    pub action: String,
781    /// The `format` field.
782    pub format: String,
783    /// The `language` field.
784    pub language: String,
785}
786
787#[derive(Debug, Clone, PartialEq)]
788/// Native message type for `gestalt.provider.v1.CreateAgentProviderTurnRequest`.
789pub struct CreateAgentProviderTurnRequest {
790    /// The `provider_name` field.
791    pub provider_name: String,
792    /// The `turn_id` field.
793    pub turn_id: String,
794    /// The `session_id` field.
795    pub session_id: String,
796    /// The `idempotency_key` field.
797    pub idempotency_key: String,
798    /// The `model` field.
799    pub model: String,
800    /// The `messages` field.
801    pub messages: Vec<AgentMessage>,
802    /// The `output` field.
803    pub output: AgentOutput,
804    /// The `metadata` field.
805    pub metadata: Option<AgentJson>,
806    /// The `created_by_subject_id` field.
807    pub created_by_subject_id: Option<String>,
808    /// The `execution_ref` field.
809    pub execution_ref: String,
810    /// The `subject` field.
811    pub subject: Option<Subject>,
812    /// The `model_options` field.
813    pub model_options: Option<AgentJson>,
814    /// The `timeout_seconds` field.
815    pub timeout_seconds: i32,
816    /// The `context` field.
817    pub context: Option<pb::RequestContext>,
818}
819
820#[derive(Debug, Clone, PartialEq)]
821/// Native enum for `gestalt.provider.v1.AgentOutput`.
822pub enum AgentOutput {
823    /// The `Text` variant.
824    Text(AgentTextOutput),
825    /// The `Structured` variant.
826    Structured(AgentStructuredOutput),
827}
828
829#[derive(Debug, Clone, Default, PartialEq, Eq)]
830/// Native message type for `gestalt.provider.v1.AgentTextOutput`.
831pub struct AgentTextOutput {}
832
833#[derive(Debug, Clone, PartialEq)]
834/// Native message type for `gestalt.provider.v1.AgentStructuredOutput`.
835pub struct AgentStructuredOutput {
836    /// The `schema` field.
837    pub schema: AgentJson,
838}
839
840impl AgentOutput {
841    /// Requests an unstructured text turn.
842    pub fn text() -> Self {
843        Self::Text(AgentTextOutput {})
844    }
845
846    /// Requests a structured turn with the supplied JSON Schema object.
847    pub fn structured_schema<T: Serialize>(schema: T) -> ProviderResult<Self> {
848        Ok(Self::Structured(AgentStructuredOutput {
849            schema: protocol::json_from_serializable(schema)?,
850        }))
851    }
852}
853
854#[derive(Debug, Clone, Default, PartialEq, Eq)]
855/// Native message type for `gestalt.provider.v1.GetAgentProviderTurnRequest`.
856pub struct GetAgentProviderTurnRequest {
857    /// The `provider_name` field.
858    pub provider_name: String,
859    /// The `turn_id` field.
860    pub turn_id: String,
861    /// The `subject` field.
862    pub subject: Option<Subject>,
863}
864
865#[derive(Debug, Clone, Default, PartialEq, Eq)]
866/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnsRequest`.
867pub struct ListAgentProviderTurnsRequest {
868    /// The `provider_name` field.
869    pub provider_name: String,
870    /// The `session_id` field.
871    pub session_id: String,
872    /// The `subject` field.
873    pub subject: Option<Subject>,
874    /// The `turn_ids` field.
875    pub turn_ids: Vec<String>,
876    /// The `status` field.
877    pub status: AgentExecutionStatus,
878    /// The `limit` field.
879    pub limit: i32,
880    /// The `summary_only` field.
881    pub summary_only: bool,
882}
883
884#[derive(Debug, Clone, Default, PartialEq)]
885/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnsResponse`.
886pub struct ListAgentProviderTurnsResponse {
887    /// The `turns` field.
888    pub turns: Vec<AgentTurn>,
889}
890
891#[derive(Debug, Clone, Default, PartialEq, Eq)]
892/// Native message type for `gestalt.provider.v1.CancelAgentProviderTurnRequest`.
893pub struct CancelAgentProviderTurnRequest {
894    /// The `provider_name` field.
895    pub provider_name: String,
896    /// The `turn_id` field.
897    pub turn_id: String,
898    /// The `reason` field.
899    pub reason: String,
900    /// The `subject` field.
901    pub subject: Option<Subject>,
902}
903
904#[derive(Debug, Clone, Default, PartialEq)]
905/// Native message type for `gestalt.provider.v1.AgentTurnEvent`.
906pub struct AgentTurnEvent {
907    /// The `id` field.
908    pub id: String,
909    /// The `turn_id` field.
910    pub turn_id: String,
911    /// The `seq` field.
912    pub seq: i64,
913    /// The `type` field.
914    pub r#type: String,
915    /// The `source` field.
916    pub source: String,
917    /// The `visibility` field.
918    pub visibility: String,
919    /// The `data` field.
920    pub data: Option<AgentJson>,
921    /// The `created_at` field.
922    pub created_at: Option<SystemTime>,
923    /// The `display` field.
924    pub display: Option<AgentTurnDisplay>,
925}
926
927#[derive(Debug, Clone, Default, PartialEq, Eq)]
928/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnEventsRequest`.
929pub struct ListAgentProviderTurnEventsRequest {
930    /// The `provider_name` field.
931    pub provider_name: String,
932    /// The `turn_id` field.
933    pub turn_id: String,
934    /// The `after_seq` field.
935    pub after_seq: i64,
936    /// The `limit` field.
937    pub limit: i32,
938    /// The `subject` field.
939    pub subject: Option<Subject>,
940}
941
942#[derive(Debug, Clone, Default, PartialEq)]
943/// Native message type for `gestalt.provider.v1.ListAgentProviderTurnEventsResponse`.
944pub struct ListAgentProviderTurnEventsResponse {
945    /// The `events` field.
946    pub events: Vec<AgentTurnEvent>,
947}
948
949#[derive(Debug, Clone, Default, PartialEq, Eq)]
950/// Native message type for `gestalt.provider.v1.GetAgentProviderInteractionRequest`.
951pub struct GetAgentProviderInteractionRequest {
952    /// The `interaction_id` field.
953    pub interaction_id: String,
954    /// The `subject` field.
955    pub subject: Option<Subject>,
956}
957
958#[derive(Debug, Clone, Default, PartialEq, Eq)]
959/// Native message type for `gestalt.provider.v1.ListAgentProviderInteractionsRequest`.
960pub struct ListAgentProviderInteractionsRequest {
961    /// The `provider_name` field.
962    pub provider_name: String,
963    /// The `turn_id` field.
964    pub turn_id: String,
965    /// The `subject` field.
966    pub subject: Option<Subject>,
967}
968
969#[derive(Debug, Clone, Default, PartialEq)]
970/// Native message type for `gestalt.provider.v1.ListAgentProviderInteractionsResponse`.
971pub struct ListAgentProviderInteractionsResponse {
972    /// The `interactions` field.
973    pub interactions: Vec<AgentInteraction>,
974}
975
976#[derive(Debug, Clone, Default, PartialEq)]
977/// Native message type for `gestalt.provider.v1.ResolveAgentProviderInteractionRequest`.
978pub struct ResolveAgentProviderInteractionRequest {
979    /// The `provider_name` field.
980    pub provider_name: String,
981    /// The `interaction_id` field.
982    pub interaction_id: String,
983    /// The `resolution` field.
984    pub resolution: Option<AgentJson>,
985    /// The `subject` field.
986    pub subject: Option<Subject>,
987}
988
989#[derive(Debug, Clone, Default, PartialEq, Eq)]
990/// MCP-style behavior hints of a tool.
991pub struct AgentToolAnnotations {
992    /// The `read_only_hint` field.
993    pub read_only_hint: Option<bool>,
994    /// The `idempotent_hint` field.
995    pub idempotent_hint: Option<bool>,
996    /// The `destructive_hint` field.
997    pub destructive_hint: Option<bool>,
998    /// The `open_world_hint` field.
999    pub open_world_hint: Option<bool>,
1000}
1001
1002#[derive(Debug, Clone, Default, PartialEq)]
1003/// Native message type for `gestalt.provider.v1.ListedAgentTool`.
1004pub struct ListedAgentTool {
1005    /// The `id` field.
1006    pub id: String,
1007    /// The `mcp_name` field.
1008    pub mcp_name: String,
1009    /// The `title` field.
1010    pub title: String,
1011    /// The `description` field.
1012    pub description: String,
1013    /// The `input_schema` field.
1014    pub input_schema: String,
1015    /// The `output_schema` field.
1016    pub output_schema: String,
1017    /// The `annotations` field.
1018    pub annotations: Option<AgentToolAnnotations>,
1019    /// The `ref` field.
1020    pub r#ref: Option<AgentToolRef>,
1021    /// The `tags` field.
1022    pub tags: Vec<String>,
1023    /// The `search_text` field.
1024    pub search_text: String,
1025}
1026
1027/// Creates a native agent message.
1028pub fn new_agent_message(input: AgentMessage) -> ProviderResult<AgentMessage> {
1029    Ok(AgentMessage {
1030        role: input.role,
1031        text: input.text,
1032        parts: input
1033            .parts
1034            .into_iter()
1035            .map(new_agent_message_part)
1036            .collect::<ProviderResult<Vec<_>>>()?,
1037        metadata: input.metadata,
1038    })
1039}
1040
1041/// Creates a native agent message part.
1042pub fn new_agent_message_part(input: AgentMessagePart) -> ProviderResult<AgentMessagePart> {
1043    let mut part_type = input.r#type;
1044    if part_type == AgentMessagePartType::Unspecified {
1045        part_type = infer_agent_message_part_type(&input);
1046    }
1047    Ok(AgentMessagePart {
1048        r#type: part_type,
1049        text: input.text,
1050        json: input.json,
1051        tool_call: input.tool_call.map(new_agent_tool_call).transpose()?,
1052        tool_result: input.tool_result.map(new_agent_tool_result).transpose()?,
1053        image_ref: input.image_ref.map(new_agent_image_ref),
1054    })
1055}
1056
1057/// Creates a native agent tool-call payload.
1058pub fn new_agent_tool_call(
1059    input: AgentMessagePartToolCall,
1060) -> ProviderResult<AgentMessagePartToolCall> {
1061    Ok(AgentMessagePartToolCall {
1062        id: input.id,
1063        tool_id: input.tool_id,
1064        arguments: input.arguments,
1065    })
1066}
1067
1068/// Creates a native agent tool-result payload.
1069pub fn new_agent_tool_result(
1070    input: AgentMessagePartToolResult,
1071) -> ProviderResult<AgentMessagePartToolResult> {
1072    Ok(AgentMessagePartToolResult {
1073        tool_call_id: input.tool_call_id,
1074        status: input.status,
1075        content: input.content,
1076        output: input.output,
1077    })
1078}
1079
1080/// Creates a native agent image-reference payload.
1081pub fn new_agent_image_ref(input: AgentMessagePartImageRef) -> AgentMessagePartImageRef {
1082    AgentMessagePartImageRef {
1083        uri: input.uri,
1084        mime_type: input.mime_type,
1085    }
1086}
1087
1088/// Creates a native agent tool reference.
1089pub fn new_agent_tool_ref(input: AgentToolRef) -> AgentToolRef {
1090    AgentToolRef {
1091        app: input.app,
1092        operation: input.operation,
1093        connection: input.connection,
1094        instance: input.instance,
1095        title: input.title,
1096        description: input.description,
1097        credential_mode: input.credential_mode,
1098        system: input.system,
1099        run_as: input.run_as,
1100    }
1101}
1102
1103fn infer_agent_message_part_type(input: &AgentMessagePart) -> AgentMessagePartType {
1104    if input.tool_call.is_some() {
1105        AgentMessagePartType::ToolCall
1106    } else if input.tool_result.is_some() {
1107        AgentMessagePartType::ToolResult
1108    } else if input.image_ref.is_some() {
1109        AgentMessagePartType::ImageRef
1110    } else if input.json.is_some() {
1111        AgentMessagePartType::Json
1112    } else if !input.text.is_empty() {
1113        AgentMessagePartType::Text
1114    } else {
1115        AgentMessagePartType::Unspecified
1116    }
1117}
1118
1119fn json_from_struct(value: Option<Struct>) -> Option<AgentJson> {
1120    value.map(|value| protocol::json_from_struct(&value))
1121}
1122
1123fn struct_from_json(value: Option<AgentJson>) -> ProviderResult<Option<Struct>> {
1124    value.map(protocol::struct_from_json).transpose()
1125}
1126
1127fn value_from_json(value: Option<AgentJson>) -> Option<Value> {
1128    value.map(protocol::value_from_json)
1129}
1130
1131fn timestamp_from_time(value: Option<SystemTime>) -> Option<Timestamp> {
1132    value.map(protocol::timestamp_from_system_time)
1133}
1134
1135fn agent_subject_from_proto(value: Option<pb::SubjectContext>) -> Option<Subject> {
1136    value.map(|value| Subject {
1137        id: value.id,
1138        credential_subject_id: value.credential_subject_id,
1139        email: value.email,
1140        display_name: value.display_name,
1141    })
1142}
1143
1144pub(crate) fn agent_tool_ref_from_proto(value: pb::AgentToolRef) -> AgentToolRef {
1145    AgentToolRef {
1146        app: value.app,
1147        operation: value.operation,
1148        connection: value.connection,
1149        instance: value.instance,
1150        title: value.title,
1151        description: value.description,
1152        credential_mode: value.credential_mode,
1153        system: value.system,
1154        run_as: agent_run_as_context_from_proto(value.run_as),
1155    }
1156}
1157
1158fn agent_run_as_context_from_proto(value: Option<pb::SubjectContext>) -> Option<Subject> {
1159    value.map(|value| Subject {
1160        id: value.id,
1161        credential_subject_id: value.credential_subject_id,
1162        email: value.email,
1163        display_name: value.display_name,
1164    })
1165}
1166
1167pub(crate) fn message_from_proto(value: pb::AgentMessage) -> AgentMessage {
1168    AgentMessage {
1169        role: value.role,
1170        text: value.text,
1171        parts: value
1172            .parts
1173            .into_iter()
1174            .map(message_part_from_proto)
1175            .collect(),
1176        metadata: json_from_struct(value.metadata),
1177    }
1178}
1179
1180pub(crate) fn message_to_proto(value: AgentMessage) -> ProviderResult<pb::AgentMessage> {
1181    Ok(pb::AgentMessage {
1182        role: value.role,
1183        text: value.text,
1184        parts: value
1185            .parts
1186            .into_iter()
1187            .map(message_part_to_proto)
1188            .collect::<ProviderResult<Vec<_>>>()?,
1189        metadata: struct_from_json(value.metadata)?,
1190    })
1191}
1192
1193fn message_part_from_proto(value: pb::AgentMessagePart) -> AgentMessagePart {
1194    AgentMessagePart {
1195        r#type: AgentMessagePartType::from_i32_lossy(value.r#type),
1196        text: value.text,
1197        json: json_from_struct(value.json),
1198        tool_call: value.tool_call.map(|value| AgentMessagePartToolCall {
1199            id: value.id,
1200            tool_id: value.tool_id,
1201            arguments: json_from_struct(value.arguments),
1202        }),
1203        tool_result: value.tool_result.map(|value| AgentMessagePartToolResult {
1204            tool_call_id: value.tool_call_id,
1205            status: value.status,
1206            content: value.content,
1207            output: json_from_struct(value.output),
1208        }),
1209        image_ref: value.image_ref.map(|value| AgentMessagePartImageRef {
1210            uri: value.uri,
1211            mime_type: value.mime_type,
1212        }),
1213    }
1214}
1215
1216fn message_part_to_proto(value: AgentMessagePart) -> ProviderResult<pb::AgentMessagePart> {
1217    Ok(pb::AgentMessagePart {
1218        r#type: value.r#type.as_i32(),
1219        text: value.text,
1220        json: struct_from_json(value.json)?,
1221        tool_call: value
1222            .tool_call
1223            .map(|value| -> ProviderResult<pb::AgentMessagePartToolCall> {
1224                Ok(pb::AgentMessagePartToolCall {
1225                    id: value.id,
1226                    tool_id: value.tool_id,
1227                    arguments: struct_from_json(value.arguments)?,
1228                })
1229            })
1230            .transpose()?,
1231        tool_result: value
1232            .tool_result
1233            .map(|value| -> ProviderResult<pb::AgentMessagePartToolResult> {
1234                Ok(pb::AgentMessagePartToolResult {
1235                    tool_call_id: value.tool_call_id,
1236                    status: value.status,
1237                    content: value.content,
1238                    output: struct_from_json(value.output)?,
1239                })
1240            })
1241            .transpose()?,
1242        image_ref: value.image_ref.map(|value| pb::AgentMessagePartImageRef {
1243            uri: value.uri,
1244            mime_type: value.mime_type,
1245        }),
1246    })
1247}
1248
1249fn session_to_proto(value: AgentSession) -> ProviderResult<pb::AgentSession> {
1250    Ok(pb::AgentSession {
1251        id: value.id,
1252        provider_name: value.provider_name,
1253        model: value.model,
1254        client_ref: value.client_ref,
1255        state: value.state.as_i32(),
1256        metadata: struct_from_json(value.metadata)?,
1257        created_by_subject_id: value.created_by_subject_id.clone().unwrap_or_default(),
1258        created_at: timestamp_from_time(value.created_at),
1259        updated_at: timestamp_from_time(value.updated_at),
1260        last_turn_at: timestamp_from_time(value.last_turn_at),
1261    })
1262}
1263
1264fn turn_to_proto(value: AgentTurn) -> ProviderResult<pb::AgentTurn> {
1265    Ok(pb::AgentTurn {
1266        id: value.id,
1267        session_id: value.session_id,
1268        provider_name: value.provider_name,
1269        model: value.model,
1270        status: value.status.as_i32(),
1271        messages: value
1272            .messages
1273            .into_iter()
1274            .map(message_to_proto)
1275            .collect::<ProviderResult<Vec<_>>>()?,
1276        output: agent_turn_output_to_proto(value.output)?,
1277        status_message: value.status_message,
1278        created_by_subject_id: value.created_by_subject_id.clone().unwrap_or_default(),
1279        created_at: timestamp_from_time(value.created_at),
1280        started_at: timestamp_from_time(value.started_at),
1281        completed_at: timestamp_from_time(value.completed_at),
1282        execution_ref: value.execution_ref,
1283    })
1284}
1285
1286fn display_to_proto(value: AgentTurnDisplay) -> pb::AgentTurnDisplay {
1287    pb::AgentTurnDisplay {
1288        kind: value.kind,
1289        phase: value.phase,
1290        text: value.text,
1291        label: value.label,
1292        r#ref: value.r#ref,
1293        parent_ref: value.parent_ref,
1294        input: value_from_json(value.input),
1295        output: value_from_json(value.output),
1296        error: value_from_json(value.error),
1297        action: value.action,
1298        format: value.format,
1299        language: value.language,
1300    }
1301}
1302
1303fn agent_turn_output_to_proto(
1304    value: Option<AgentTurnOutput>,
1305) -> ProviderResult<Option<pb::agent_turn::Output>> {
1306    match value {
1307        Some(AgentTurnOutput::Text(output)) => Ok(Some(pb::agent_turn::Output::Text(
1308            pb::AgentTurnTextOutput { text: output.text },
1309        ))),
1310        Some(AgentTurnOutput::Structured(output)) => Ok(Some(pb::agent_turn::Output::Structured(
1311            pb::AgentTurnStructuredOutput {
1312                text: output.text,
1313                value: struct_from_json(output.value)?,
1314            },
1315        ))),
1316        None => Ok(None),
1317    }
1318}
1319
1320fn agent_output_from_proto(value: Option<pb::AgentOutput>) -> ProviderResult<Option<AgentOutput>> {
1321    match value.and_then(|output| output.kind) {
1322        Some(pb::agent_output::Kind::Text(_)) => Ok(Some(AgentOutput::Text(AgentTextOutput {}))),
1323        Some(pb::agent_output::Kind::Structured(output)) => {
1324            let schema = json_from_struct(output.schema)
1325                .ok_or_else(|| crate::Error::bad_request("output.structured.schema is required"))?;
1326            Ok(Some(AgentOutput::Structured(AgentStructuredOutput {
1327                schema,
1328            })))
1329        }
1330        None => Ok(None),
1331    }
1332}
1333
1334fn required_agent_output_from_proto(value: Option<pb::AgentOutput>) -> ProviderResult<AgentOutput> {
1335    agent_output_from_proto(value)?
1336        .ok_or_else(|| crate::Error::bad_request("create turn output is required"))
1337}
1338
1339fn event_to_proto(value: AgentTurnEvent) -> ProviderResult<pb::AgentTurnEvent> {
1340    Ok(pb::AgentTurnEvent {
1341        id: value.id,
1342        turn_id: value.turn_id,
1343        seq: value.seq,
1344        r#type: value.r#type,
1345        source: value.source,
1346        visibility: value.visibility,
1347        data: struct_from_json(value.data)?,
1348        created_at: timestamp_from_time(value.created_at),
1349        display: value.display.map(display_to_proto),
1350    })
1351}
1352
1353fn interaction_to_proto(value: AgentInteraction) -> ProviderResult<pb::AgentInteraction> {
1354    Ok(pb::AgentInteraction {
1355        id: value.id,
1356        r#type: value.r#type.as_i32(),
1357        state: value.state.as_i32(),
1358        title: value.title,
1359        prompt: value.prompt,
1360        request: struct_from_json(value.request)?,
1361        resolution: struct_from_json(value.resolution)?,
1362        created_at: timestamp_from_time(value.created_at),
1363        resolved_at: timestamp_from_time(value.resolved_at),
1364        turn_id: value.turn_id,
1365        session_id: value.session_id,
1366    })
1367}
1368
1369fn capabilities_to_proto(value: AgentProviderCapabilities) -> pb::AgentProviderCapabilities {
1370    pb::AgentProviderCapabilities {
1371        streaming_text: value.streaming_text,
1372        tool_calls: value.tool_calls,
1373        parallel_tool_calls: value.parallel_tool_calls,
1374        interactions: value.interactions,
1375        resumable_turns: value.resumable_turns,
1376        reasoning_summaries: value.reasoning_summaries,
1377        bounded_list_hydration: value.bounded_list_hydration,
1378        supported_tool_sources: value
1379            .supported_tool_sources
1380            .into_iter()
1381            .map(AgentToolSourceMode::as_i32)
1382            .collect(),
1383        supports_session_start: value.supports_session_start,
1384        supports_prepared_workspace: value.supports_prepared_workspace,
1385    }
1386}
1387
1388fn create_session_request_from_proto(
1389    value: pb::CreateAgentProviderSessionRequest,
1390) -> CreateAgentProviderSessionRequest {
1391    CreateAgentProviderSessionRequest {
1392        idempotency_key: value.idempotency_key,
1393        model: value.model,
1394        client_ref: value.client_ref,
1395        metadata: json_from_struct(value.metadata),
1396        created_by_subject_id: Some(value.created_by_subject_id)
1397            .filter(|value| !value.trim().is_empty())
1398            .map(|value| value.to_string()),
1399        subject: agent_subject_from_proto(value.subject),
1400        session_start: value.session_start.map(|value| AgentSessionStartConfig {
1401            hooks: value
1402                .hooks
1403                .into_iter()
1404                .map(|hook| AgentSessionStartHook {
1405                    id: hook.id,
1406                    r#type: hook.r#type,
1407                    command: hook.command,
1408                    cwd: hook.cwd,
1409                    timeout: hook.timeout,
1410                    env: hook.env.into_iter().collect(),
1411                    output: hook.output.map(|output| AgentSessionStartHookOutput {
1412                        additional_context: output.additional_context,
1413                        metadata: output.metadata,
1414                    }),
1415                })
1416                .collect(),
1417        }),
1418        prepared_workspace: value
1419            .prepared_workspace
1420            .map(|value| AgentPreparedWorkspace {
1421                root: value.root,
1422                cwd: value.cwd,
1423            }),
1424        tools: value.tools.map(agent_tool_config_from_proto),
1425    }
1426}
1427
1428fn create_turn_request_from_proto(
1429    value: pb::CreateAgentProviderTurnRequest,
1430) -> ProviderResult<CreateAgentProviderTurnRequest> {
1431    if value.timeout_seconds < 0 {
1432        return Err(crate::Error::bad_request(
1433            "agent create turn timeout_seconds must not be negative",
1434        ));
1435    }
1436    Ok(CreateAgentProviderTurnRequest {
1437        provider_name: value.provider_name,
1438        turn_id: value.turn_id,
1439        session_id: value.session_id,
1440        idempotency_key: value.idempotency_key,
1441        model: value.model,
1442        messages: value.messages.into_iter().map(message_from_proto).collect(),
1443        output: required_agent_output_from_proto(value.output)?,
1444        metadata: json_from_struct(value.metadata),
1445        created_by_subject_id: Some(value.created_by_subject_id)
1446            .filter(|value| !value.trim().is_empty())
1447            .map(|value| value.to_string()),
1448        execution_ref: value.execution_ref,
1449        subject: agent_subject_from_proto(value.subject),
1450        model_options: json_from_struct(value.model_options),
1451        timeout_seconds: value.timeout_seconds,
1452        context: value.context,
1453    })
1454}
1455
1456fn listed_tool_from_proto(value: pb::ListedAgentTool) -> ListedAgentTool {
1457    ListedAgentTool {
1458        id: value.id,
1459        mcp_name: value.mcp_name,
1460        title: value.title,
1461        description: value.description,
1462        input_schema: value.input_schema,
1463        output_schema: value.output_schema,
1464        annotations: value.annotations.map(|annotations| AgentToolAnnotations {
1465            read_only_hint: annotations.read_only_hint,
1466            idempotent_hint: annotations.idempotent_hint,
1467            destructive_hint: annotations.destructive_hint,
1468            open_world_hint: annotations.open_world_hint,
1469        }),
1470        r#ref: value.r#ref.map(agent_tool_ref_from_proto),
1471        tags: value.tags,
1472        search_text: value.search_text,
1473    }
1474}
1475
1476fn agent_tool_config_from_proto(value: pb::AgentToolConfig) -> AgentToolConfig {
1477    let source = match value.source {
1478        Some(pb::agent_tool_config::Source::None(_)) => {
1479            Some(AgentToolConfigSource::None(AgentNoTools {}))
1480        }
1481        Some(pb::agent_tool_config::Source::Catalog(catalog)) => {
1482            Some(AgentToolConfigSource::Catalog(AgentCatalogToolConfig {
1483                refs: catalog
1484                    .refs
1485                    .into_iter()
1486                    .map(agent_tool_ref_from_proto)
1487                    .collect(),
1488                tools: catalog
1489                    .tools
1490                    .into_iter()
1491                    .map(listed_tool_from_proto)
1492                    .collect(),
1493            }))
1494        }
1495        None => None,
1496    };
1497    AgentToolConfig { source }
1498}
1499
1500#[async_trait]
1501/// Provider trait for serving the Gestalt agent-provider protocol.
1502pub trait AgentProvider: Send + Sync + 'static {
1503    /// Configures the provider before it starts serving requests.
1504    async fn configure(
1505        &self,
1506        _name: &str,
1507        _config: serde_json::Map<String, serde_json::Value>,
1508    ) -> ProviderResult<()> {
1509        Ok(())
1510    }
1511
1512    /// Returns runtime metadata that should augment the static manifest.
1513    fn metadata(&self) -> Option<RuntimeMetadata> {
1514        None
1515    }
1516
1517    /// Returns non-fatal warnings the host should surface to users.
1518    fn warnings(&self) -> Vec<String> {
1519        Vec::new()
1520    }
1521
1522    /// Performs an optional health check.
1523    async fn health_check(&self) -> ProviderResult<()> {
1524        Ok(())
1525    }
1526
1527    /// Starts provider-owned background work after configuration.
1528    async fn start(&self) -> ProviderResult<()> {
1529        Ok(())
1530    }
1531
1532    /// Shuts the provider down before the runtime exits.
1533    async fn close(&self) -> ProviderResult<()> {
1534        Ok(())
1535    }
1536
1537    /// Creates or idempotently returns an agent session.
1538    ///
1539    /// Mints the session id returned on the [`AgentSession`]. Must be
1540    /// idempotent on `idempotency_key` scoped per subject
1541    /// (`created_by_subject_id`); an empty key always creates.
1542    async fn create_session(
1543        &self,
1544        _request: CreateAgentProviderSessionRequest,
1545    ) -> ProviderResult<AgentSession> {
1546        Err(crate::Error::unimplemented(
1547            "agent create session is not implemented",
1548        ))
1549    }
1550
1551    /// Returns one agent session by ID.
1552    async fn get_session(
1553        &self,
1554        _request: GetAgentProviderSessionRequest,
1555    ) -> ProviderResult<AgentSession> {
1556        Err(crate::Error::unimplemented(
1557            "agent get session is not implemented",
1558        ))
1559    }
1560
1561    /// Lists agent sessions visible to the request subject.
1562    async fn list_sessions(
1563        &self,
1564        _request: ListAgentProviderSessionsRequest,
1565    ) -> ProviderResult<ListAgentProviderSessionsResponse> {
1566        Err(crate::Error::unimplemented(
1567            "agent list sessions is not implemented",
1568        ))
1569    }
1570
1571    /// Updates mutable agent session metadata or state.
1572    async fn update_session(
1573        &self,
1574        _request: UpdateAgentProviderSessionRequest,
1575    ) -> ProviderResult<AgentSession> {
1576        Err(crate::Error::unimplemented(
1577            "agent update session is not implemented",
1578        ))
1579    }
1580
1581    /// Starts or idempotently returns an agent turn.
1582    async fn create_turn(
1583        &self,
1584        _request: CreateAgentProviderTurnRequest,
1585    ) -> ProviderResult<AgentTurn> {
1586        Err(crate::Error::unimplemented(
1587            "agent create turn is not implemented",
1588        ))
1589    }
1590
1591    /// Returns one agent turn by ID.
1592    async fn get_turn(&self, _request: GetAgentProviderTurnRequest) -> ProviderResult<AgentTurn> {
1593        Err(crate::Error::unimplemented(
1594            "agent get turn is not implemented",
1595        ))
1596    }
1597
1598    /// Lists turns for a session or query.
1599    async fn list_turns(
1600        &self,
1601        _request: ListAgentProviderTurnsRequest,
1602    ) -> ProviderResult<ListAgentProviderTurnsResponse> {
1603        Err(crate::Error::unimplemented(
1604            "agent list turns is not implemented",
1605        ))
1606    }
1607
1608    /// Requests cancellation of a running or pending turn.
1609    async fn cancel_turn(
1610        &self,
1611        _request: CancelAgentProviderTurnRequest,
1612    ) -> ProviderResult<AgentTurn> {
1613        Err(crate::Error::unimplemented(
1614            "agent cancel turn is not implemented",
1615        ))
1616    }
1617
1618    /// Lists ordered events emitted by a turn.
1619    async fn list_turn_events(
1620        &self,
1621        _request: ListAgentProviderTurnEventsRequest,
1622    ) -> ProviderResult<ListAgentProviderTurnEventsResponse> {
1623        Err(crate::Error::unimplemented(
1624            "agent list turn events is not implemented",
1625        ))
1626    }
1627
1628    /// Returns one pending or resolved interaction.
1629    async fn get_interaction(
1630        &self,
1631        _request: GetAgentProviderInteractionRequest,
1632    ) -> ProviderResult<AgentInteraction> {
1633        Err(crate::Error::unimplemented(
1634            "agent get interaction is not implemented",
1635        ))
1636    }
1637
1638    /// Lists interactions associated with a turn.
1639    async fn list_interactions(
1640        &self,
1641        _request: ListAgentProviderInteractionsRequest,
1642    ) -> ProviderResult<ListAgentProviderInteractionsResponse> {
1643        Err(crate::Error::unimplemented(
1644            "agent list interactions is not implemented",
1645        ))
1646    }
1647
1648    /// Records a response to a pending interaction.
1649    async fn resolve_interaction(
1650        &self,
1651        _request: ResolveAgentProviderInteractionRequest,
1652    ) -> ProviderResult<AgentInteraction> {
1653        Err(crate::Error::unimplemented(
1654            "agent resolve interaction is not implemented",
1655        ))
1656    }
1657
1658    /// Returns the provider's supported agent features.
1659    async fn get_capabilities(
1660        &self,
1661        _request: GetAgentProviderCapabilitiesRequest,
1662    ) -> ProviderResult<AgentProviderCapabilities> {
1663        Err(crate::Error::unimplemented(
1664            "agent get capabilities is not implemented",
1665        ))
1666    }
1667}
1668
1669#[derive(Clone)]
1670pub(crate) struct AgentServer<P> {
1671    provider: Arc<P>,
1672}
1673
1674impl<P> AgentServer<P> {
1675    pub(crate) fn new(provider: Arc<P>) -> Self {
1676        Self { provider }
1677    }
1678}
1679
1680#[async_trait]
1681impl<P> pb::agent_server::Agent for AgentServer<P>
1682where
1683    P: AgentProvider,
1684{
1685    async fn create_session(
1686        &self,
1687        request: GrpcRequest<pb::CreateAgentProviderSessionRequest>,
1688    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1689        let request = request.into_inner();
1690        let context = request.context.clone();
1691        let session = scope_request_context(
1692            context,
1693            self.provider
1694                .create_session(create_session_request_from_proto(request)),
1695        )
1696        .await
1697        .map_err(|error| rpc_status("agent create session", error))?;
1698        Ok(GrpcResponse::new(session_to_proto(session).map_err(
1699            |error| rpc_status("agent create session", error),
1700        )?))
1701    }
1702
1703    async fn get_session(
1704        &self,
1705        request: GrpcRequest<pb::GetAgentProviderSessionRequest>,
1706    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1707        let request = request.into_inner();
1708        let context = request.context.clone();
1709        let session = scope_request_context(
1710            context,
1711            self.provider.get_session(GetAgentProviderSessionRequest {
1712                provider_name: request.provider_name,
1713                session_id: request.session_id,
1714                subject: agent_subject_from_proto(request.subject),
1715            }),
1716        )
1717        .await
1718        .map_err(|error| rpc_status("agent get session", error))?;
1719        Ok(GrpcResponse::new(
1720            session_to_proto(session).map_err(|error| rpc_status("agent get session", error))?,
1721        ))
1722    }
1723
1724    async fn list_sessions(
1725        &self,
1726        request: GrpcRequest<pb::ListAgentProviderSessionsRequest>,
1727    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderSessionsResponse>, Status> {
1728        let request = request.into_inner();
1729        let context = request.context.clone();
1730        let response = scope_request_context(
1731            context,
1732            self.provider
1733                .list_sessions(ListAgentProviderSessionsRequest {
1734                    provider_name: request.provider_name,
1735                    subject: agent_subject_from_proto(request.subject),
1736                    session_ids: request.session_ids,
1737                    state: AgentSessionState::from_i32_lossy(request.state),
1738                    limit: request.limit,
1739                    summary_only: request.summary_only,
1740                }),
1741        )
1742        .await
1743        .map_err(|error| rpc_status("agent list sessions", error))?;
1744        Ok(GrpcResponse::new(pb::ListAgentProviderSessionsResponse {
1745            sessions: response
1746                .sessions
1747                .into_iter()
1748                .map(session_to_proto)
1749                .collect::<ProviderResult<Vec<_>>>()
1750                .map_err(|error| rpc_status("agent list sessions", error))?,
1751        }))
1752    }
1753
1754    async fn update_session(
1755        &self,
1756        request: GrpcRequest<pb::UpdateAgentProviderSessionRequest>,
1757    ) -> std::result::Result<GrpcResponse<pb::AgentSession>, Status> {
1758        let request = request.into_inner();
1759        let context = request.context.clone();
1760        let session = scope_request_context(
1761            context,
1762            self.provider
1763                .update_session(UpdateAgentProviderSessionRequest {
1764                    provider_name: request.provider_name,
1765                    session_id: request.session_id,
1766                    client_ref: request.client_ref,
1767                    state: AgentSessionState::from_i32_lossy(request.state),
1768                    metadata: json_from_struct(request.metadata),
1769                    subject: agent_subject_from_proto(request.subject),
1770                }),
1771        )
1772        .await
1773        .map_err(|error| rpc_status("agent update session", error))?;
1774        Ok(GrpcResponse::new(session_to_proto(session).map_err(
1775            |error| rpc_status("agent update session", error),
1776        )?))
1777    }
1778
1779    async fn create_turn(
1780        &self,
1781        request: GrpcRequest<pb::CreateAgentProviderTurnRequest>,
1782    ) -> std::result::Result<GrpcResponse<pb::AgentTurn>, Status> {
1783        let request = request.into_inner();
1784        let context = request.context.clone();
1785        let turn = scope_request_context(
1786            context,
1787            self.provider.create_turn(
1788                create_turn_request_from_proto(request)
1789                    .map_err(|error| rpc_status("agent create turn", error))?,
1790            ),
1791        )
1792        .await
1793        .map_err(|error| rpc_status("agent create turn", error))?;
1794        Ok(GrpcResponse::new(
1795            turn_to_proto(turn).map_err(|error| rpc_status("agent create turn", error))?,
1796        ))
1797    }
1798
1799    async fn get_turn(
1800        &self,
1801        request: GrpcRequest<pb::GetAgentProviderTurnRequest>,
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.get_turn(GetAgentProviderTurnRequest {
1808                provider_name: request.provider_name,
1809                turn_id: request.turn_id,
1810                subject: agent_subject_from_proto(request.subject),
1811            }),
1812        )
1813        .await
1814        .map_err(|error| rpc_status("agent get turn", error))?;
1815        Ok(GrpcResponse::new(
1816            turn_to_proto(turn).map_err(|error| rpc_status("agent get turn", error))?,
1817        ))
1818    }
1819
1820    async fn list_turns(
1821        &self,
1822        request: GrpcRequest<pb::ListAgentProviderTurnsRequest>,
1823    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderTurnsResponse>, Status> {
1824        let request = request.into_inner();
1825        let context = request.context.clone();
1826        let response = scope_request_context(
1827            context,
1828            self.provider.list_turns(ListAgentProviderTurnsRequest {
1829                provider_name: request.provider_name,
1830                session_id: request.session_id,
1831                subject: agent_subject_from_proto(request.subject),
1832                turn_ids: request.turn_ids,
1833                status: AgentExecutionStatus::from_i32_lossy(request.status),
1834                limit: request.limit,
1835                summary_only: request.summary_only,
1836            }),
1837        )
1838        .await
1839        .map_err(|error| rpc_status("agent list turns", error))?;
1840        Ok(GrpcResponse::new(pb::ListAgentProviderTurnsResponse {
1841            turns: response
1842                .turns
1843                .into_iter()
1844                .map(turn_to_proto)
1845                .collect::<ProviderResult<Vec<_>>>()
1846                .map_err(|error| rpc_status("agent list turns", error))?,
1847        }))
1848    }
1849
1850    async fn cancel_turn(
1851        &self,
1852        request: GrpcRequest<pb::CancelAgentProviderTurnRequest>,
1853    ) -> std::result::Result<GrpcResponse<pb::AgentTurn>, Status> {
1854        let request = request.into_inner();
1855        let context = request.context.clone();
1856        let turn = scope_request_context(
1857            context,
1858            self.provider.cancel_turn(CancelAgentProviderTurnRequest {
1859                provider_name: request.provider_name,
1860                turn_id: request.turn_id,
1861                reason: request.reason,
1862                subject: agent_subject_from_proto(request.subject),
1863            }),
1864        )
1865        .await
1866        .map_err(|error| rpc_status("agent cancel turn", error))?;
1867        Ok(GrpcResponse::new(
1868            turn_to_proto(turn).map_err(|error| rpc_status("agent cancel turn", error))?,
1869        ))
1870    }
1871
1872    async fn list_turn_events(
1873        &self,
1874        request: GrpcRequest<pb::ListAgentProviderTurnEventsRequest>,
1875    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderTurnEventsResponse>, Status> {
1876        let request = request.into_inner();
1877        let context = request.context.clone();
1878        let response = scope_request_context(
1879            context,
1880            self.provider
1881                .list_turn_events(ListAgentProviderTurnEventsRequest {
1882                    provider_name: request.provider_name,
1883                    turn_id: request.turn_id,
1884                    after_seq: request.after_seq,
1885                    limit: request.limit,
1886                    subject: agent_subject_from_proto(request.subject),
1887                }),
1888        )
1889        .await
1890        .map_err(|error| rpc_status("agent list turn events", error))?;
1891        Ok(GrpcResponse::new(pb::ListAgentProviderTurnEventsResponse {
1892            events: response
1893                .events
1894                .into_iter()
1895                .map(event_to_proto)
1896                .collect::<ProviderResult<Vec<_>>>()
1897                .map_err(|error| rpc_status("agent list turn events", error))?,
1898        }))
1899    }
1900
1901    async fn get_interaction(
1902        &self,
1903        request: GrpcRequest<pb::GetAgentProviderInteractionRequest>,
1904    ) -> std::result::Result<GrpcResponse<pb::AgentInteraction>, Status> {
1905        let request = request.into_inner();
1906        let context = request.context.clone();
1907        let interaction = scope_request_context(
1908            context,
1909            self.provider
1910                .get_interaction(GetAgentProviderInteractionRequest {
1911                    interaction_id: request.interaction_id,
1912                    subject: agent_subject_from_proto(request.subject),
1913                }),
1914        )
1915        .await
1916        .map_err(|error| rpc_status("agent get interaction", error))?;
1917        Ok(GrpcResponse::new(
1918            interaction_to_proto(interaction)
1919                .map_err(|error| rpc_status("agent get interaction", error))?,
1920        ))
1921    }
1922
1923    async fn list_interactions(
1924        &self,
1925        request: GrpcRequest<pb::ListAgentProviderInteractionsRequest>,
1926    ) -> std::result::Result<GrpcResponse<pb::ListAgentProviderInteractionsResponse>, Status> {
1927        let request = request.into_inner();
1928        let context = request.context.clone();
1929        let response = scope_request_context(
1930            context,
1931            self.provider
1932                .list_interactions(ListAgentProviderInteractionsRequest {
1933                    provider_name: request.provider_name,
1934                    turn_id: request.turn_id,
1935                    subject: agent_subject_from_proto(request.subject),
1936                }),
1937        )
1938        .await
1939        .map_err(|error| rpc_status("agent list interactions", error))?;
1940        Ok(GrpcResponse::new(
1941            pb::ListAgentProviderInteractionsResponse {
1942                interactions: response
1943                    .interactions
1944                    .into_iter()
1945                    .map(interaction_to_proto)
1946                    .collect::<ProviderResult<Vec<_>>>()
1947                    .map_err(|error| rpc_status("agent list interactions", error))?,
1948            },
1949        ))
1950    }
1951
1952    async fn resolve_interaction(
1953        &self,
1954        request: GrpcRequest<pb::ResolveAgentProviderInteractionRequest>,
1955    ) -> std::result::Result<GrpcResponse<pb::AgentInteraction>, Status> {
1956        let request = request.into_inner();
1957        let context = request.context.clone();
1958        let interaction = scope_request_context(
1959            context,
1960            self.provider
1961                .resolve_interaction(ResolveAgentProviderInteractionRequest {
1962                    provider_name: request.provider_name,
1963                    interaction_id: request.interaction_id,
1964                    resolution: json_from_struct(request.resolution),
1965                    subject: agent_subject_from_proto(request.subject),
1966                }),
1967        )
1968        .await
1969        .map_err(|error| rpc_status("agent resolve interaction", error))?;
1970        Ok(GrpcResponse::new(
1971            interaction_to_proto(interaction)
1972                .map_err(|error| rpc_status("agent resolve interaction", error))?,
1973        ))
1974    }
1975
1976    async fn get_capabilities(
1977        &self,
1978        _request: GrpcRequest<pb::GetAgentProviderCapabilitiesRequest>,
1979    ) -> std::result::Result<GrpcResponse<pb::AgentProviderCapabilities>, Status> {
1980        let capabilities = self
1981            .provider
1982            .get_capabilities(GetAgentProviderCapabilitiesRequest {})
1983            .await
1984            .map_err(|error| rpc_status("agent get capabilities", error))?;
1985        Ok(GrpcResponse::new(capabilities_to_proto(capabilities)))
1986    }
1987}