Skip to main content

conversation_api/execution/
facade.rs

1//! App Facade contract used by the canonical Agent implementation.
2
3use async_trait::async_trait;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::execution::{ActionId, ExternalError, InvocationContext, OperationId};
8
9/// Canonical App Facade request selected by Agent-owned tool code.
10#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
11#[serde(deny_unknown_fields)]
12pub struct FacadeRequest {
13    /// Stable idempotency identifier for this tool operation.
14    pub operation_id: OperationId,
15    /// Canonical `/app/...` target. The Agent owns every tool-to-target mapping.
16    pub target: String,
17    /// Structured input validated and normalized by Agent-owned tool code.
18    pub input: Value,
19}
20
21pub use crate::{InteractionCard, InteractionKind, InteractionTone};
22
23/// Prepared operation awaiting an explicit commit or rejection.
24#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
25#[serde(deny_unknown_fields)]
26pub struct PreparedAction {
27    /// Stable action identifier used for idempotent commit and rejection.
28    pub action_id: ActionId,
29    /// Idempotency identifier supplied by Runtime.
30    pub operation_id: OperationId,
31    /// App Facade-generated preview suitable for user confirmation.
32    pub card: InteractionCard,
33    /// Opaque execution plan. Runtime persists it but never exposes it to the model or UI.
34    #[serde(default)]
35    pub payload: Value,
36    /// App Facade revision that must still be current when committing.
37    pub revision: u64,
38}
39
40/// Structured result returned by an App Facade operation.
41#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
42#[serde(deny_unknown_fields)]
43pub struct FacadeResult {
44    /// App Facade result payload.
45    pub value: Value,
46    /// New prompt-context generation when this operation changed Agent-visible facts.
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub context_invalidation: Option<crate::execution::ContextInvalidation>,
49}
50
51/// Environment-specific implementation of the App Facade boundary.
52///
53/// Implementations may execute in-process (`MeowCore`) or through RPC (agent-cloud/Lion), but they
54/// cannot supply prompts, tools, workflows, or model-facing schemas.
55#[async_trait]
56pub trait AppFacade: Send + Sync {
57    /// Executes a direct App Facade request.
58    async fn invoke(
59        &self,
60        context: &InvocationContext,
61        request: FacadeRequest,
62    ) -> Result<FacadeResult, ExternalError>;
63
64    /// Prepares a mutating operation without applying it.
65    async fn prepare(
66        &self,
67        context: &InvocationContext,
68        request: FacadeRequest,
69    ) -> Result<PreparedAction, ExternalError>;
70
71    /// Commits a prepared operation idempotently.
72    async fn commit(
73        &self,
74        context: &InvocationContext,
75        action: PreparedAction,
76    ) -> Result<FacadeResult, ExternalError>;
77
78    /// Rejects a prepared operation idempotently.
79    async fn reject(
80        &self,
81        context: &InvocationContext,
82        action: PreparedAction,
83    ) -> Result<(), ExternalError>;
84}