Cancellation and timeouts
Agents abandon executions. Carmy treats that as a first-class event, not an accident.
Deadlines
Section titled “Deadlines”Every execution has a deadline: 30 seconds by default.
timeout_secs = 10 # or CARMY_TIMEOUT_SECS=10carmy::app().timeout(std::time::Duration::from_secs(10)).run().awaitA timed-out execution returns TIMEOUT (status timed_out, HTTP 504).
The cancellation token
Section titled “The cancellation token”Every execution has a CancellationToken in ctx.cancellation. The runtime cancels it
and stops polling the tool when any of these happens:
- the deadline passes
- the HTTP client disconnects, on a JSON or SSE request
- an MCP client sends
notifications/cancelled - the caller drops the execution future or stream
Work that a tool spawns in the background should watch the token:
#[carmy::tool(effect = "external_write")]async fn export_report(ctx: AgentContext, input: ExportInput) -> AgentResult<Export> { let token = ctx.cancellation.clone(); let upload = tokio::spawn(async move { tokio::select! { _ = token.cancelled() => Err("cancelled"), result = upload_to_storage(input) => result, } }); // …}Semantics
Section titled “Semantics”Cancellation cannot un-send an email. That’s why Carmy records an interrupted execution
as uncertain: its idempotency reservation is kept, and a retry reports
EXECUTION_UNCERTAIN instead of running the side effect twice. See
Idempotency.