ablative docs
↑↓ move↵ openesc close
Stack Notebook ablative.com.au

Cancel and steer an activity

Use worker cancellation and capability-gated agent intervention with the full attempt identity.

Open .md

Workflow cancellation

Cancelling a workflow records its terminal state, stops its in-flight activities and recursively cancels Running or Paused descendants. A declared run deadline also starts this cascade. Each descendant records its own cancellation. Completed descendants retain their terminal history.

The cascade sends controls for all live attempts of each ended run. gRPC carries CancelActivity; liminal carries the run and attempt too. These internal frames implement run cancellation. They provide no general public API for choosing one ordinary activity.

Run-wide worker cancellation
On main, crates/aion-server/src/worker/cancel_cascade_hook.rs:150 invokes cancellation for the ended run; worker/activity_cancel.rs:268–284 sends each gRPC CancelActivity frame. These frames serve run-wide cancellation, rather than a public single-activity route.
Quota commissioning
On main, crates/aion-server/src/run/outbox_commission.rs:160–162 skips a disabled outbox; lines 212–231 install namespace backpressure only on the enabled dispatcher.
Counted dispatches
On main, crates/aion/src/runtime/nif_collect.rs:306–316 stages parallel/collect members through the outbox. runtime/nif_activity_dispatch.rs:448 dispatches an ordinary call directly, outside that count.
Defaults
On main, crates/aion-server/src/config/defaults.rs:33 sets the namespace ceiling to 1024. config/sections.rs:940–945 defaults outbox.enabled to false; crates/aion-server/templates/first-run-config.toml:77 enables it.
Cluster share
On main, crates/aion-server/src/worker/backpressure.rs computes ceil(namespace quota × owned shards / total shards). Rounding can put aggregate claimed capacity slightly above the nominal quota.
Handoff and execution
On main, crates/aion-server/src/worker/outbox_dispatcher.rs:650–677 marks a successfully handed-off row done. worker/dispatch.rs:308–319 defines dispatch success as placement with a worker. The claim ceiling therefore bounds claimed rows; worker concurrency bounds executing handler slots.

Cancel one agent attempt

Use an agent worker connected over liminal. Enumerate its workflow’s live attempts. Copy the run, activity and attempt from the response and choose an attempt whose advertised capabilities include Cancel.

curl --fail-with-body -sS -X POST "${AION_HTTP_ENDPOINT:-http://127.0.0.1:8080}/workflows/attempts" \
  -H "authorization: Bearer $AION_TOKEN" \
  -H 'content-type: application/json' \
  --data-binary '{"namespace":"default","workflow_id":"00000000-0000-0000-0000-000000000001"}'

Replace the example ids and activity position with those returned values, then send the intervention.

curl --fail-with-body -sS -X POST "${AION_HTTP_ENDPOINT:-http://127.0.0.1:8080}/workflows/intervene" \
  -H "authorization: Bearer $AION_TOKEN" \
  -H 'content-type: application/json' \
  --data-binary '{"namespace":"default","workflow_id":"00000000-0000-0000-0000-000000000001","run_id":"00000000-0000-0000-0000-000000000002","activity_id":3,"attempt":1,"kind":{"kind":"Cancel","reason":"operator requested stop"}}'

Read the outcome. Applied controls that agent attempt. An unadvertised primitive returns CapabilityNotSupported. An unavailable owner or transport returns StaleTarget, including a gRPC-only worker or a build without liminal. Use workflow cancel to terminate the durable run and its descendants.

Other interventions

POST /workflows/attempts
Body: namespace and workflow_id UUID string. Returns attempts with run_id, activity_id, attempt and capabilities. Caller must have namespace access to the workflow.
POST /workflows/intervene
Body: namespace, workflow_id, run_id, activity_id, attempt and kind. Identity values come from the attempts read. The server stamps the issuing subject and time.
Cancel
kind is {"kind":"Cancel","reason":"operator requested stop"}. Requires an agent attempt whose worker advertises Cancel and has a live liminal connection. Available through HTTP only; there is no CLI command for single-attempt cancellation.
InjectMessage
kind is {"kind":"InjectMessage","text":"Focus on the failing check","priority":{"priority":"Interrupt"}}. Normal priority queues a turn; Interrupt requests immediate steering.
Other primitives
PauseResume carries paused; UpdateBudget carries max_tokens and max_turns (nullable); RespondToApproval carries call_id, decision {"decision":"Approve"} or {"decision":"Deny"}, and nullable note. Each requires advertised support.
Response
HTTP 200 contains outcome with outcome Applied, CapabilityNotSupported (unadvertised primitive), or StaleTarget (missing owner or unreachable transport). A gRPC-only worker cannot receive the intervention. Inspect the outcome field; authorization and malformed input use HTTP errors.
Implementation
crates/aion-server/src/api/http/intervene.rs:42–105 and crates/aion-core/src/intervention.rs:69–178 define the target and tagged control shapes.
Workflow and descendants
crates/aion/src/engine/api_workflow_ops.rs:150–190 and lifecycle/cancel_cascade.rs:267–309 record the target cancellation and recursively cancel Running or Paused descendants. Each run uses its own recorder.
Deadline cascade
crates/aion/src/lifecycle/deadline.rs:173–190 starts the same descendant cascade after a declared run deadline.
Single agent intervention
crates/aion-server/src/api/http/router.rs:497–498 and api/http/intervene.rs:66–109 serve HTTP intervention. worker/intervention.rs:301–303 requires the worker’s advertised primitive.
Transport boundary
crates/aion-server/src/state/accessors.rs:229–239 selects liminal intervention transport. state/routing.rs:86–101 supplies an unreachable transport otherwise; an unreachable attempt returns StaleTarget. The CLI has no intervention command.

Controls are recorded in the activity transcript. Workflow-visible decisions still use signals and workflow cancellation in durable history. Preserve idempotency keys and compensating actions for external changes already made.