pub struct TaskContext { /* private fields */ }functional and graph only.Expand description
Runtime context passed to #[entrypoint] and #[task] functions.
Provides access to workflow state, checkpointing, interrupt/resume,
and progress streaming. Each task function receives a mutable reference
to TaskContext enabling state reads, writes, event emission, and
interrupt requests.
§Example
use adk_graph::functional::TaskContext;
#[task]
async fn my_step(ctx: &mut TaskContext) -> Result<Value> {
// Read state
let count: i64 = ctx.get("counter").unwrap_or(0);
// Write state
ctx.set("counter", serde_json::json!(count + 1));
// Emit progress
ctx.emit(StreamEvent::custom("my_step", "progress", serde_json::json!({"count": count + 1})));
Ok(serde_json::json!({"new_count": count + 1}))
}Implementations§
Source§impl TaskContext
impl TaskContext
Sourcepub fn new(
thread_id: String,
state: HashMap<String, Value>,
checkpointer: Arc<dyn Checkpointer>,
event_tx: Sender<StreamEvent>,
execution_log: Arc<RwLock<ExecutionLog>>,
cancel_token: CancellationToken,
schema: Option<StateSchema>,
) -> TaskContext
pub fn new( thread_id: String, state: HashMap<String, Value>, checkpointer: Arc<dyn Checkpointer>, event_tx: Sender<StreamEvent>, execution_log: Arc<RwLock<ExecutionLog>>, cancel_token: CancellationToken, schema: Option<StateSchema>, ) -> TaskContext
Create a new TaskContext.
Typically constructed by the macro-generated entrypoint, not by user code.
Sourcepub fn get<T>(&self, key: &str) -> Option<T>where
T: DeserializeOwned,
pub fn get<T>(&self, key: &str) -> Option<T>where
T: DeserializeOwned,
Sourcepub fn set(&mut self, key: &str, value: impl Into<Value>)
pub fn set(&mut self, key: &str, value: impl Into<Value>)
Set a value in state.
If a StateSchema is configured, the update is applied using the
appropriate reducer for the key. Otherwise the value is set directly
(overwrite semantics).
§Example
ctx.set("counter", serde_json::json!(42));Sourcepub fn emit(&self, event: StreamEvent)
pub fn emit(&self, event: StreamEvent)
Sourcepub async fn interrupt<T>(&self, message: &str) -> Result<T, GraphError>where
T: DeserializeOwned,
pub async fn interrupt<T>(&self, message: &str) -> Result<T, GraphError>where
T: DeserializeOwned,
Interrupt execution and wait for external input.
Persists the current state as an interrupt checkpoint, emits an
interrupted event, and suspends execution. When the workflow is
resumed with an interrupt value, the value is deserialized into T
and returned.
§Errors
Returns FunctionalError::InterruptTypeMismatch if the resume
value cannot be deserialized into T.
Returns FunctionalError::CheckpointFailed if persisting the
interrupt checkpoint fails.
§Example
let approval: bool = ctx.interrupt("Please approve this action").await?;Sourcepub fn with_resume_values(
self,
resume_values: HashMap<String, Value>,
) -> TaskContext
pub fn with_resume_values( self, resume_values: HashMap<String, Value>, ) -> TaskContext
Supplies values for interrupt sites, keyed by continuation key.
Re-invoke the entrypoint with these set to resume: an interrupt whose key is present returns the deserialized value instead of suspending.
§Example
// First run suspends and reports its continuation key.
let Err(e) = run(ctx).await else { unreachable!() };
// Second run supplies the value under that key.
let ctx = ctx.with_resume_values(HashMap::from([
("interrupt-1".to_string(), serde_json::json!({ "approved": true })),
]));
let output = run(ctx).await?;Sourcepub fn resume_values(&self) -> &HashMap<String, Value>
pub fn resume_values(&self) -> &HashMap<String, Value>
The values available to interrupt sites in this context.
Sourcepub fn cancel_token(&self) -> &CancellationToken
pub fn cancel_token(&self) -> &CancellationToken
Get a reference to the cancellation token.
Sourcepub fn is_cancelled(&self) -> bool
pub fn is_cancelled(&self) -> bool
Check if the workflow has been cancelled.
Sourcepub async fn current_step(&self) -> usize
pub async fn current_step(&self) -> usize
Get the current step number from the execution log.
Sourcepub fn with_schema_validator(
self,
validator: StateSchemaValidator,
) -> TaskContext
pub fn with_schema_validator( self, validator: StateSchemaValidator, ) -> TaskContext
Set a StateSchemaValidator for this context.
When set, the validator is used to validate initial state at workflow start and task output before applying reducers.
Sourcepub fn schema_validator(&self) -> Option<&StateSchemaValidator>
pub fn schema_validator(&self) -> Option<&StateSchemaValidator>
Get the schema validator, if configured.
Sourcepub fn validate_state(&self) -> Result<(), FunctionalError>
pub fn validate_state(&self) -> Result<(), FunctionalError>
Validate the current state against the schema validator.
Called at workflow start to validate initial state.
§Errors
Returns FunctionalError::SchemaValidation if validation fails.
Sourcepub fn validate_task_output(
&self,
output: &HashMap<String, Value>,
) -> Result<(), FunctionalError>
pub fn validate_task_output( &self, output: &HashMap<String, Value>, ) -> Result<(), FunctionalError>
Validate task output against the schema validator.
Called after a task produces output, before applying reducers.
§Errors
Returns FunctionalError::SchemaValidation if validation fails.
Sourcepub fn iteration_key(&mut self, task_name: &str) -> String
pub fn iteration_key(&mut self, task_name: &str) -> String
Generate a unique checkpoint key for a task inside a loop.
Each call to this method for the same task_name increments the
iteration counter, producing keys like "step_a::iter_0",
"step_a::iter_1", etc. Keys are deterministic from task name
and iteration index.
§Example
for item in items {
let key = ctx.iteration_key("process_item");
// key = "process_item::iter_0", "process_item::iter_1", ...
}Sourcepub fn current_iteration(&self, task_name: &str) -> Option<usize>
pub fn current_iteration(&self, task_name: &str) -> Option<usize>
Get the current iteration index for a task without incrementing.
Returns None if the task has not been called in a loop yet.
Sourcepub fn reset_iteration(&mut self, task_name: &str)
pub fn reset_iteration(&mut self, task_name: &str)
Reset the iteration counter for a task.
Useful when re-entering a loop (e.g., nested loops or retry).
Sourcepub fn reset_all_iterations(&mut self)
pub fn reset_all_iterations(&mut self)
Reset all iteration counters.
Sourcepub fn route_to(&mut self, targets: &[&str])
pub fn route_to(&mut self, targets: &[&str])
Records the task names this task chose, for its caller to read.
Nothing in this crate acts on the value. The functional API runs your
own control flow: #[entrypoint] calls your function once, and the
awaits inside it are the order of execution. So a task states its
choice here and the surrounding code reads it with
Self::take_pending_route and calls what it names.
For routing the framework performs, build the workflow with
StateGraph::add_conditional_edges,
which resolves a route key against declared targets and dispatches to
them.
§Example
use std::collections::HashMap;
use std::sync::Arc;
use adk_graph::checkpoint::{Checkpointer, MemoryCheckpointer};
use adk_graph::functional::{ExecutionLog, TaskContext};
use tokio::sync::{RwLock, broadcast};
use tokio_util::sync::CancellationToken;
let (event_tx, _rx) = broadcast::channel(8);
let mut ctx = TaskContext::new(
"thread-1".to_string(),
HashMap::new(),
Arc::new(MemoryCheckpointer::new()) as Arc<dyn Checkpointer>,
event_tx,
Arc::new(RwLock::new(ExecutionLog::new())),
CancellationToken::new(),
None,
);
// A task states which branches it chose.
ctx.route_to(&["process_a", "process_b"]);
// The surrounding code reads the choice and calls those tasks itself.
let chosen = ctx.take_pending_route().expect("a route was set");
assert_eq!(chosen, vec!["process_a".to_string(), "process_b".to_string()]);
// Reading it clears it, so the next task starts with no choice pending.
assert_eq!(ctx.take_pending_route(), None);Sourcepub fn take_pending_route(&mut self) -> Option<Vec<String>>
pub fn take_pending_route(&mut self) -> Option<Vec<String>>
Takes the task names recorded by Self::route_to, clearing them.
Returns None when no task set a route. Call this from the code that
sequences your tasks; nothing in this crate calls it for you.
Auto Trait Implementations§
impl !RefUnwindSafe for TaskContext
impl !UnwindSafe for TaskContext
impl Freeze for TaskContext
impl Send for TaskContext
impl Sync for TaskContext
impl Unpin for TaskContext
impl UnsafeUnpin for TaskContext
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> MaybeSend for Twhere
T: Send,
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.