Skip to main content
After this guide, a tool or job in one agent hands part of its work to another agent, or makes a plain model call when no agent is needed. Agents.invoke runs a full turn on the target agent, with its persona, skills, processors, and governance; AI.generate calls a model with a prompt and nothing else. For routing between agents set up in the admin dashboard, use a Space. Verified against lua-cli 3.33.0. Before you begin
  • A project created with lua init and signed in with lua auth configure (Install and sign in).
  • The target agent, in the same organization, released and answering in lua chat, or this agent’s own ID, to invoke itself.
1

Find the target agent's ID and store it

lua agents --json --ci prints an array of organizations, each with an agents array of agentId and name; your own project’s ID is project.agentId in lua status --json --ci. Keep the ID in an environment variable: lua test reads .env, deployed code reads the production variables, and sandbox chat uploads the .env values with the sandbox version.
Output
2

Invoke it from a tool

Inside a conversation the turn runs as the current end user. threadId isolates the target agent’s conversation; without it the invocation joins the end user’s default thread with that agent. When the target’s preprocessor or governance stops the turn, the call throws with code set to PREPROCESSOR_BLOCKED or GOVERNANCE_BLOCKED and the block text as the message; catch that case rather than treating it as a tool failure.
src/skills/tools/DraftReplyTool.ts
3

Invoke it from a job

A job has no current user. Pass userId so the turn runs as that user, with their profile and history; omit it and the turn runs in system scope, with no end user and no stored conversation (Execution contexts). user_abc123 is a placeholder for a stored Lua user ID (Identify users).
src/jobs/WeeklyReviewJob.ts
4

Make a one-off model call

AI.generate with an options object returns text, finishReason, and usage; model pins a code from lua models list --json --ci (About models), and without it the platform default answers. With structuredOutput.schema, a JSON Schema whose top-level type is object, the parsed value lands on output when the model finishes normally; it is not validated, so check it before use.
src/skills/tools/ClassifyTicketTool.ts
5

Test locally

lua test skill runs a tool on your machine; AI.generate and Agents.invoke still reach the platform. Locally, Agents.invoke runs as you with your developer credentials, drops userId, model, and timeoutMs, and reports a blocked turn as finishReason preprocessor_blocked or governance_blocked instead of throwing.
Output
Without model, the platform default answered the same input in another shape ("category": "Billing", a sub_category, no summary), which is why the tool validates output and falls back to text.
6

Release it

lua push uploads a version and changes nothing for end users; lua version create snapshots the agent; lua version promote <n> makes that snapshot live and is also the rollback path (Release an agent to production).
lua version create prints ✓ Created v<n> (staged); in a script, n=$(lua version list --limit 1 --json --ci | jq -r '.[0].version') then lua version promote "$n". lua push all exits 0 even when a primitive fails; check its output for component(s) failed to push.
7

Verify

Ask a question the tool delegates, then read the logs.
The reply contains the sales agent’s draft, and the log shows draft_reply running. The target agent records the delegated turn on the thread you named; lua logs --agent-id <agent-id> --type all --limit 5 shows it when you administer that agent.

Options you may need

Set a timeout that fits the caller

timeoutMs defaults to 120 000 ms. A tool, webhook, or processor is itself stopped at 180 seconds, so a larger value buys nothing there; a job runs up to its own timeout (300 seconds by default, 600 at most).

Override the target’s persona for one turn

systemPrompt replaces the target agent’s persona for that invocation only, and runtimeContext appends context to the request; the target’s skills and processors still apply. Agents.invoke(agentId, 'a plain prompt') returns only the reply text.

Shape a plain call

messages replaces prompt with a full message array; maxOutputTokens caps the answer.

If it isn’t working

Cause The target agent’s preprocessor or governance policy stopped the turn; the error’s message is the block text. Fix Catch the error as in the example, read lua logs --type preprocessor on the target agent, and adjust its rules or your prompt.
Cause The target took longer than timeoutMs, or your calling context hit its own budget first. Fix Raise timeoutMs up to the caller’s limit, move the call into a job, or narrow the prompt.
Cause output is set only when the model finishes with stop, and the parsed JSON is not validated against your schema. Fix Validate with zod as in the example, fall back to text, and try a different model.

Next steps

Agents reference

Every option and the output shape.

AI reference

AI.generate inputs, outputs, and structured output.

About Spaces

Routing between agents, set up in the admin dashboard.

Workflow quickstart

Agent steps with retries, approvals, and budgets.