Skip to main content

Chapter 19: Defining Agents and Tools

TL;DR

  1. Define an Agent Persona with upsert_agent on worka/orchestrator. The description field is the system prompt for the agent.
  2. Define a Tool Schema (JSON‑Schema style) so the agent knows how to call your tools.
  3. Register the Tool with upsert_tool to make it available to agents.

An AI workflow needs two building blocks:

  1. An Agent to plan and reason.
  2. A set of Tools the agent can call.

You define both by calling tools on the worka/orchestrator virtual pack.

Creating an Agent

Agents are LLM personas. You define them by calling upsert_agent.

Backend example (Rust, in‑process MCP):

// Pseudocode – exact SDK API may differ
let client = McpClient::inproc();
client.call(
"worka/orchestrator",
"upsert_agent",
json!({
"name": "research-agent",
"description": "You are a helpful research assistant. Summarize sources and cite them."
})
).await?;

A2UI example (via action):

{
"type": "button",
"props": {
"label": "Create Agent",
"onClick": {
"type": "worka_action",
"target": "worka/orchestrator",
"tool": "upsert_agent",
"input": {
"name": "research-agent",
"description": "You are a helpful research assistant. Summarize sources and cite them."
}
}
}
}

Defining and Registering Tools

An agent can't do anything without tools. For an agent to use a tool from your MCP server (e.g., the greet tool we built), you must first register its schema with the Orchestrator. This schema is a machine-readable description of the tool's function and parameters, which the LLM uses to understand how and when to use it.

Step 1: Define the Tool Schema

Worka uses a format based on the widely-used JSON Schema standard. You define an object that describes the parameters your tool's function accepts.

Let's imagine we have a tool named google_search that takes a single string parameter, query.

const googleSearchSchema = {
type: 'object', // The root is always an object
properties: {
query: { // The name of the parameter
type: 'string',
description: 'The search query to send to Google.' // A description for the LLM
}
},
required: ['query'] // An array of required parameter names
};

Step 2: Register the Schema with upsert_tool

Once you have the schema, you call the upsert_tool tool on the worka/orchestrator pack. This tells the Orchestrator that this tool exists and makes it available to your agents.

Backend example (Rust):

let client = McpClient::inproc();
client.call(
"worka/orchestrator",
"upsert_tool",
json!({
"name": "google_search",
"description": "Performs a Google search and returns top results.",
"schema": googleSearchSchema
})
).await?;

By separating the tool's implementation (in your MCP server) from its registration (via upsert_tool), the system remains decoupled. The Orchestrator doesn't need to know how your tool works, only what it does and what parameters it needs. When an agent decides to use google_search, the Orchestrator will see the tool call and route it to your pack's MCP server for execution.