Skip to main content

Ai.Agent

Examples assume aliases Ai (this module), AiOpenai (ai-openai), and Js (javascript). Substitute if you import under different names.

Ai.Agent is a Telo.Invocable that runs a tool-use loop over any Ai.Model: it calls the model with a set of tools, executes whatever tools the model requests, replays the results, and repeats until the model produces a final answer (or a step cap is hit). The loop lives in the controller — not the provider — so it is provider-agnostic and every turn is observable in the returned steps trace.

Tools come from one field, toolProviders: a list of references to any Ai.ToolProvider. Both a static list (Ai.Tools) and runtime MCP discovery (AiMcp.ToolProvider, from @telorun/ai-mcp) are providers — the agent treats them uniformly.

kind: AiOpenai.OpenaiModel
metadata: { name: Gpt4o }
model: gpt-4o-mini
apiKey: "${{ secrets.openaiApiKey }}"
---
kind: Js.Script
metadata: { name: Multiplier }
code: |
function main({ a, b }) { return { product: a * b }; }
---
kind: Ai.Tools
metadata: { name: LocalTools }
tools:
- tool: !ref Multiplier
name: multiply
description: Multiply two numbers.
parameters:
type: object
additionalProperties: false
required: [a, b]
properties: { a: { type: number }, b: { type: number } }
---
kind: Ai.Agent
metadata: { name: Assistant }
model: !ref Gpt4o
system: "Use tools when helpful."
maxSteps: 8
toolProviders:
- provider: !ref LocalTools

Manifest fields

FieldTypeRequiredPurpose
modelref (Ai.Model)yesThe LLM that drives the loop.
systemstringnoDefault system prompt. Runtime inputs.system wins.
optionsobjectnoOption overrides passed to the model each turn (merged under inputs.options).
maxStepsintegernoMax model turns. Default 8.
onMaxStepsthrow|returnnoAt the cap without finishing: throw raises ERR_AGENT_MAX_STEPS; return hands back the last turn's text (finishReason: tool-calls). Default throw.
onToolErrorfeedback|thrownoWhen a tool throws or the model names an unknown tool: feedback records it in steps and returns it to the model so it can recover; throw aborts. Default feedback.
toolProvidersarraynoTool sources — see below.

toolProviders[]

FieldTypeRequiredPurpose
providerref (Ai.ToolProvider)yesA static list, MCP server, or any provider.
prefixstringnoNamespaces this provider's tool names (avoids collisions).
includestring[]noAllowlist of bare tool names to expose.
excludestring[]noDenylist of bare tool names.

Tools are listed lazily on first invoke and cached. A name clash across providers that a prefix doesn't resolve is ERR_AGENT_TOOL_COLLISION.

Invocation inputs

FieldTypeRequiredPurpose
promptstringexactly one of prompt/messagesShorthand for messages: [{ role: user, content: prompt }].
messagesarrayexactly one of prompt/messagesFull turns.
systemstringnoRuntime system override (wins over manifest system).
optionsobjectnoPer-call option overrides.

Output

{ text, usage, finishReason, steps }:

  • text — the model's final answer.
  • usage — token usage summed across every model call in the loop.
  • finishReason — from the final turn.
  • steps — one entry per turn that called tools: { text, toolCalls, toolResults }, where each result carries { toolCallId, name, content, error? }. content is the tool's reply — a string, or content parts (ContentPart[]) when a tool answered with an image; the agent carries parts through to the model untouched rather than JSON-stringifying them. Failures appear here too (not swallowed).

See also