Skip to main content

jamjet_worker/
executor.rs

1//! Node executors — one per node kind.
2//! Each executor takes a WorkItem, runs the node logic, and returns a result.
3
4use jamjet_state::backend::WorkItem;
5use serde_json::Value;
6
7/// Channel sender for real-time streaming events from executors.
8pub type StreamEventSender = tokio::sync::mpsc::Sender<Value>;
9
10pub struct ExecutionResult {
11    pub output: Value,
12    pub state_patch: Value,
13    pub duration_ms: u64,
14    /// Telemetry: GenAI provider system (e.g. "anthropic", "openai"). None for non-model nodes.
15    pub gen_ai_system: Option<String>,
16    /// Telemetry: model name used.
17    pub gen_ai_model: Option<String>,
18    /// Telemetry: input tokens consumed.
19    pub input_tokens: Option<u64>,
20    /// Telemetry: output tokens generated.
21    pub output_tokens: Option<u64>,
22    /// Telemetry: finish reason (e.g. "stop", "length", "tool_calls").
23    pub finish_reason: Option<String>,
24}
25
26/// Trait implemented by each node kind executor.
27#[async_trait::async_trait]
28pub trait NodeExecutor: Send + Sync {
29    async fn execute(&self, item: &WorkItem) -> Result<ExecutionResult, String>;
30
31    /// Execute with streaming event emission. Default delegates to `execute()`.
32    async fn execute_streaming(
33        &self,
34        item: &WorkItem,
35        _tx: StreamEventSender,
36    ) -> Result<ExecutionResult, String> {
37        self.execute(item).await
38    }
39}