Skip to main content
Tools are how an agent reaches outside the chat — searching the web, querying a database, running calculations, calling your domain functions. In Cognis, every tool implements the Tool trait. There are three idiomatic ways to write one, each more convenient than the last when you can use it.

What a tool is

Four facts and a method:
  • name — what the model will type to call you.
  • description — what the model reads to decide when to call you. Make it good.
  • args_schema — JSON Schema for the arguments. The provider sends this to the model.
  • return_direct — when true, the tool’s output becomes the final response (skips the next model turn).
  • _run — the body. Receives ToolInput, returns ToolOutput.

When to reach for which option

Quick example — typed SchemaBasedTool

The most common shape: typed Params, derive JsonSchema, implement one method.
SchemaBasedTool provides a blanket Tool impl that handles serde, validation, and the JSON Schema for you.

Quick example — hand-written Tool

When you need control over the schema or want to handle raw ToolInput:
Source: examples/tools/derive_tool.rs.

Wiring tools into an agent

Tools are Arc<dyn Tool>. The builder accepts one or many.
You can also gate which tools the model is allowed to call at runtime via middleware (ToolAllowList, ToolDenyList).

Validators

When using #[cognis::tool] or SchemaBasedTool, you can declare per-field validators that emit both runtime checks and JSON Schema constraints: These ride on the args struct fields — the model sees them in the schema, and your tool receives validated input.

Built-in tools

Cognis ships a few generally useful tools under cognis::tools::*:
  • Calculator — pure-Rust expression evaluator (+ - * / % ^, parens, unary -). No code execution.
  • FilesystemTool family — read/write/edit/list a workspace, gated by a Backend.
  • HttpRequest (feature tools-http) — make HTTP calls with allow-listed hosts.
  • JsonQuery — JMESPath-like query over JSON.
  • PythonRepl — sandboxed Python execution (where the runtime is available).
  • OpenApiTool — generate tools from an OpenAPI spec.
  • HumanTool — ask a human a question, return their reply.

ToolOrchestrator (no-loop DAG)

When you need to call a fixed set of tools in a known DAG — not an agent loop — use ToolOrchestrator:
Topo-sorts the DAG, runs independent steps concurrently, and skips downstream steps whose ancestors errored.

How it works

  • The model never sees Rust types directly. It sees the JSON Schema you produce. Make descriptions and field docs clear — that’s the model’s only signal.
  • Tool dispatch is a node in the agent graph. When the model emits tool calls, the dispatcher node parses arguments, runs the tool, and threads the result back as a Message::tool entry tied to the call id.
  • Errors are tool-shaped. Returning an error from _run becomes a ToolMessage with the error text — the agent sees it and can recover or apologize.

See also

Models and providers

The other half of the agent — the LLM that picks the tool.

Human-in-the-loop

Require approval before sensitive tools run.

Middleware

ToolAllowList, ToolDenyList, ToolRetry, ToolEmulator.

Patterns → HITL approval

A worked tool-approval flow.