Skip to main content

conversation_api/execution/
operational_context.rs

1//! Structured operational-context boundary.
2
3use async_trait::async_trait;
4
5use serde::{Deserialize, Serialize};
6
7use crate::execution::{ExternalError, InvocationContext};
8
9/// Deployment-owned generation vector for independently cacheable context sections.
10#[derive(Clone, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)]
11pub struct ContextGeneration {
12    pub user_scope: String,
13    pub identity: String,
14    pub memory: String,
15    pub integration_guide: String,
16    pub installed_integrations: String,
17    pub scope_integrations: String,
18}
19
20impl ContextGeneration {
21    /// Creates a vector whose sections share one deployment-owned token.
22    #[must_use]
23    pub fn new(value: impl Into<String>) -> Self {
24        let value = value.into();
25        Self {
26            user_scope: value.clone(),
27            identity: value.clone(),
28            memory: value.clone(),
29            integration_guide: value.clone(),
30            installed_integrations: value.clone(),
31            scope_integrations: value,
32        }
33    }
34
35    /// Returns whether every independently cacheable section has a non-empty token.
36    #[must_use]
37    pub fn is_complete(&self) -> bool {
38        [
39            &self.user_scope,
40            &self.identity,
41            &self.memory,
42            &self.integration_guide,
43            &self.installed_integrations,
44            &self.scope_integrations,
45        ]
46        .into_iter()
47        .all(|value| !value.trim().is_empty())
48    }
49}
50
51/// Notification that an App Facade mutation changed facts used by the Agent prompt.
52#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
53pub struct ContextInvalidation {
54    /// New effective generation after the mutation committed.
55    pub generation: ContextGeneration,
56}
57
58/// Runtime facts loaded from the App Facade. This type deliberately contains data, not messages:
59/// prompt text and rendering order are owned by the Agent implementation.
60#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
61pub struct OperationalContext {
62    pub user_scope: String,
63    pub identity: String,
64    pub memory: String,
65    pub integration_guide: String,
66    pub installed_integrations: String,
67    pub scope_integrations: String,
68}
69
70/// Delta returned for sections whose generation differs from the caller's cached vector.
71#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
72pub struct OperationalContextDelta {
73    pub generation: ContextGeneration,
74    #[serde(default, skip_serializing_if = "Option::is_none")]
75    pub user_scope: Option<String>,
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub identity: Option<String>,
78    #[serde(default, skip_serializing_if = "Option::is_none")]
79    pub memory: Option<String>,
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    pub integration_guide: Option<String>,
82    #[serde(default, skip_serializing_if = "Option::is_none")]
83    pub installed_integrations: Option<String>,
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub scope_integrations: Option<String>,
86}
87
88/// Loads typed facts used by the canonical Agent prompt.
89#[async_trait]
90pub trait ContextSource: Send + Sync {
91    async fn load(&self, context: &InvocationContext) -> Result<OperationalContext, ExternalError>;
92}