1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Cooperative, runtime-agnostic run cancellation.
//!
//! In the recursive runtime a single [`CancellationToken`] can be shared down a
//! tree of nested runs (a parent agent, its sub-agents, and their sub-graphs),
//! so an orchestrator cancels an entire recursion with one `cancel()` and every
//! level unwinds at its next safe checkpoint with
//! [`crate::error::TinyAgentsError::Cancelled`].
//!
//! This module provides [`CancellationToken`], a lightweight, self-contained
//! cancellation primitive (an `Arc<AtomicBool>` paired with a [`tokio::sync::Notify`])
//! used to request that an in-flight harness run stop at its next safe
//! checkpoint. It deliberately avoids pulling in a heavier dependency such as
//! `tokio-util`: the harness only needs `new`/`cancel`/`is_cancelled` plus an
//! async `cancelled().await` future, all of which are a few lines over the
//! `tokio` `sync` feature already in the dependency tree.
//!
//! # Cooperative, not preemptive
//!
//! Cancelling a token never aborts a running future. Instead the agent loop
//! polls [`CancellationToken::is_cancelled`] at the same safe checkpoints it
//! uses for steering — before each model call and before each tool call — and
//! the streaming pipeline races [`CancellationToken::cancelled`] against the
//! provider stream. On observing cancellation the run unwinds cleanly with
//! [`crate::error::TinyAgentsError::Cancelled`]. This guarantees a token is
//! never observed in the middle of a side-effecting tool call or a partially
//! consumed provider stream chunk.
//!
//! # Example
//!
//! ```
//! use tinyagents::harness::cancel::CancellationToken;
//!
//! # tokio_test_block(async {
//! let token = CancellationToken::new();
//! let waiter = token.clone();
//!
//! // In another task, request cancellation.
//! token.cancel();
//!
//! // The `cancelled` future resolves once cancellation is requested.
//! waiter.cancelled().await;
//! assert!(waiter.is_cancelled());
//! # });
//! # fn tokio_test_block<F: std::future::Future>(f: F) -> F::Output {
//! # tokio::runtime::Builder::new_current_thread()
//! # .build()
//! # .unwrap()
//! # .block_on(f)
//! # }
//! ```
pub use *;
use Arc;
use ;
use Notify;
use CancelState;
/// A [`Default`] [`CancellationToken`] is a fresh, never-cancelled token.