← Swink Agent

Tools Run Concurrently

Your LLM asked for three things at once. Why would you do them one at a time?

The default is fast

When the model returns multiple tool calls in a single turn, Swink Agent spawns them all concurrently via tokio::spawn. Each tool gets its own cancellation token. Results come back as they finish.

No configuration needed. No "enable parallel mode" flag. Concurrency is the default because waiting is not a feature.

Sequential execution is available if you really, truly want it. We won't judge. Much.

But what if things change mid-flight?

Steering. After each tool completes, the harness polls for steering input. If a human (or another system) sends a redirect, every remaining in-flight tool gets cancelled via its CancellationToken. Cancelled tools get error results injected automatically so the context stays consistent.

Think of it as a pilot overriding autopilot. The plane doesn't crash — it just changes course.

The dispatch pipeline

Every tool call passes through four stages before it actually runs. Any stage can say no.

1
PreDispatch Policies Deny lists, sandboxing, argument rewriting. Policies can skip a single tool or abort the entire batch.
2
Approval Gate Optional human-in-the-loop. The callback can approve, approve with modified arguments, or reject outright.
3
Schema Validation Arguments are validated against the tool's JSON Schema. Bad input gets caught here, not inside your tool code.
4
Execution tokio::spawn. The tool runs. Results flow back. The world keeps spinning.

Execution policies

Concurrent is the default, but you have options.

PolicyBehavior
ConcurrentAll tools spawn at once. The fast path. The default.
SequentialOne at a time, in model order. For when order matters.
PrioritySort by priority, then concurrent within each group. The fancy path.
CustomImplement ToolExecutionStrategy. You partition, we execute. Full control.

Building tools is embarrassingly easy

FnTool lets you build a tool from a closure in about five lines. Schema derived from a struct. No boilerplate. No ceremony.

let tool = FnTool::new("weather", "Weather", "Get weather.")
  .with_schema_for::<Params>()
  .with_execute_simple(|params, _cancel| async move {
    AgentToolResult::text("72F and sunny")
  });

// That's a production-ready tool. Really.

Need more control? Implement AgentTool on a struct. Connection pools, caches, setup/teardown — all yours. And ToolMiddleware lets you wrap any tool with timeouts, logging, or whatever else you dream up — without modifying the original.

Cancellation-aware Every tool receives a CancellationToken. Built-in tools check it before I/O and race against it during execution.
Schema-validated Arguments are checked against JSON Schema before your code runs. LLM hallucinated a bad parameter? Caught.
Middleware-ready Wrap any tool with timeouts, logging, or custom logic. Middleware stacks. It's decorators all the way down.
Image-capable Tool results can include images, not just text. ContentBlock supports both. The LLM sees what it needs to see.

Fast by default. Interruptible when it matters.

github.com/SuperSwinkAI/Swink-Agent

← Back to Swink Agent