Skip to main content

flowcat_core/
session.rs

1// SPDX-License-Identifier: Apache-2.0
2//
3//! Call bootstrap + finalize seam.
4//!
5//! The embedder implements [`SessionSource`] over its own control-plane HTTP
6//! API (resolve a run+token into a call config, upload artifacts, write the
7//! finalize). flowcat-core only sees the opaque shapes (see DESIGN.md
8//! "Trait contracts"). [`ResolvedCall`], [`Finalize`], [`UploadTarget`], and
9//! [`Usage`] are defined in [`crate::types`] and re-exported here.
10
11use async_trait::async_trait;
12
13use crate::error::FlowcatError;
14
15// Re-export so callers use `crate::session::{ResolvedCall, Finalize, ...}` as
16// the design lays out; the definitions live in `frame`.
17pub use crate::types::{Finalize, ResolvedCall, ToolDecl, UploadTarget, Usage};
18
19/// Bootstraps a call from a run id + per-call token and writes results back.
20///
21/// `Send + Sync` because it is shared across the spawned per-leg tasks of a call.
22#[async_trait]
23pub trait SessionSource: Send + Sync {
24    /// Resolve a run id + per-call token into the call's configuration.
25    async fn resolve(&self, run_id: i64, token: &str) -> Result<ResolvedCall, FlowcatError>;
26
27    /// Mark the run complete and persist usage / collected vars / artifact URLs.
28    async fn complete(&self, run_id: i64, token: &str, fin: Finalize) -> Result<(), FlowcatError>;
29
30    /// Obtain a (pre-signed) upload target for an artifact (`kind` = recording/transcript/…).
31    async fn artifact_upload_url(
32        &self,
33        run_id: i64,
34        token: &str,
35        kind: &str,
36    ) -> Result<UploadTarget, FlowcatError>;
37
38    /// PUT raw bytes to a (pre-signed) upload URL with the given content type.
39    async fn put_bytes(
40        &self,
41        url: &str,
42        bytes: Vec<u8>,
43        content_type: &str,
44    ) -> Result<(), FlowcatError>;
45
46    /// Fetch the current node's MCP/HTTP **workflow tools** (distinct from the
47    /// brain's graph transitions). These are the tools the control plane will
48    /// execute on the agent's behalf (see [`SessionSource::tool_call`]).
49    ///
50    /// Implementations **degrade gracefully**: any HTTP/parse failure returns
51    /// `Ok(vec![])` (the call proceeds with no node tools) rather than aborting
52    /// the live call. `params` is the tool's JSON-Schema (`input_schema`,
53    /// defaulting to an empty object).
54    async fn node_tools(
55        &self,
56        run_id: i64,
57        token: &str,
58        node_id: &str,
59    ) -> Result<Vec<ToolDecl>, FlowcatError>;
60
61    /// Relay a workflow tool call (name + args) to the control plane, which runs
62    /// the MCP/HTTP egress and returns the tool result `content` (fed back to the
63    /// model). The `is_error` flag from the control plane is folded into the
64    /// returned text — the model handles failures conversationally — so this
65    /// returns a single string in all cases. On a transport error it returns a
66    /// short "temporarily unavailable" message so the call continues.
67    async fn tool_call(
68        &self,
69        run_id: i64,
70        token: &str,
71        node_id: &str,
72        tool_name: &str,
73        args: &serde_json::Value,
74    ) -> Result<String, FlowcatError>;
75}