Skip to main content

gemini_adk_rs/tasks/
mod.rs

1//! Independent capability activations inside one speaking session.
2//!
3//! [`TaskRuntime`] is a synchronous owner of task state, governance and approval.
4//! Live and offline drivers execute the [`OwnedInvocation`] it returns, then
5//! return the completion to the same runtime. Workers never select a foreground
6//! task or deliver speech. State snapshots and tool factories isolate accepted
7//! task state from cancelled or superseded workers. Trusted custom tools must
8//! not retain unrelated mutable state outside the supplied context/factory.
9//!
10//! Snapshots are observations, not durable recovery checkpoints. Commit adapters
11//! must honor their idempotency argument and support external reconciliation;
12//! cancelling a future cannot establish whether an external effect happened.
13mod runtime;
14mod services;
15mod types;
16pub use runtime::{InvocationCompletion, OwnedInvocation, TaskRuntime};
17pub use services::{
18    AcceptedTaskEffect, OwnedTaskServiceWork, TaskEffect, TaskEffects, TaskMemoryService,
19    TaskObservation, TaskPattern, TaskServiceCompletion, TaskServices, TaskWatcher,
20};
21pub use types::*;
22#[cfg(test)]
23mod tests;
24
25/// Two installed skills for session-level tests: `billing`, whose flow
26/// offers `verify` until it has run and then `pay`, and `faq`, whose one
27/// tool `answer` has no flow.
28#[cfg(test)]
29pub(crate) fn two_skill_runtime() -> TaskRuntime {
30    use crate::flow::{Enforcement, Flow, FlowStack, Guard};
31    use crate::tool::{SimpleTool, ToolDispatcher};
32    use serde_json::json;
33    use std::sync::Arc;
34
35    fn skill(name: &str, tools: &[&str], flow: Option<FlowFactory>) -> CompiledSkill {
36        let names: Vec<String> = tools.iter().map(ToString::to_string).collect();
37        let registered = names.clone();
38        CompiledSkill {
39            services: None,
40            name: name.into(),
41            version: "1.0.0".into(),
42            description: format!("{name} tasks"),
43            instruction: format!("You handle {name}."),
44            input_schema: json!({"type":"object"}),
45            output_schema: json!({"type":"object"}),
46            validate_input: Arc::new(|_| Ok(())),
47            validate_output: Arc::new(|_| Ok(())),
48            initial_state: Default::default(),
49            flow_factory: flow,
50            tool_factory: Arc::new(move |_| {
51                let mut dispatcher = ToolDispatcher::new();
52                for tool in &registered {
53                    dispatcher.register(SimpleTool::new(
54                        tool.clone(),
55                        tool.clone(),
56                        None,
57                        |_| async { Ok(json!({"ok": true})) },
58                    ));
59                }
60                Ok(dispatcher)
61            }),
62            tools: names
63                .iter()
64                .map(|tool| TaskTool {
65                    name: tool.clone(),
66                    description: tool.clone(),
67                    parameters: None,
68                    effect: TaskToolEffect::Read,
69                })
70                .collect(),
71            receipt_applier: None,
72            code: None,
73            project_output: None,
74        }
75    }
76    let billing_flow: FlowFactory = Arc::new(|| {
77        Ok(Flow::new()
78            .step("verify")
79            .allow(["verify"])
80            .done(Guard::called_ok("verify"))
81            .step("pay")
82            .after("verify")
83            .allow(["pay"])
84            .done(Guard::called_ok("pay"))
85            .step("end")
86            .after("pay")
87            .terminal()
88            .build()
89            .unwrap()
90            .compile()
91            .map(|flow| FlowStack::new(flow, Enforcement::Enforce))
92            .unwrap())
93    });
94    TaskRuntime::new(vec![
95        skill("billing", &["verify", "pay"], Some(billing_flow)),
96        skill("faq", &["answer"], None),
97    ])
98    .unwrap()
99}