Builtin Library
README.md
agents
Editor agents — a coding agent (Claude Code or the Cursor CLI) as in-engine terminals. Each agent is a static dock panel under the Agents menu, registered at editor setup like the other tabs so it opens reliably. Opening a slot spawns its agent process and renders the live terminal; reopening a slot whose agent exited relaunches it. Several slots run side by side as separate tabs.
The engine provides only the generic terminal.* PTY primitive — the agent
command, its sandbox, and the launch policy live here in Luau. Which agent a
boot runs is selected by the agent_name setting (from --agent); the launcher
builds the matching process spec.
The model and effort an agent runs on
The engine chooses the model and the effort each agent it hosts runs on (the
agents a DotBot conversation can run on: dotbot-claude, dotbot-chatgpt,
dotbot). It states a default per agent: DotBot on Claude runs on
claude-sonnet-5-5 when the agent offers it, and every agent runs at high
effort where its model takes it. The person's own choice stands in front of the
default and is kept on the device for their ZeroMind account, across
conversations and restarts. DotBot on a further account of a provider
(dotbot-claude~2, a second Claude account) is the same agent on another
account: it answers with the agent's default and the person's choice, so a
conversation moved between accounts keeps its model and effort.
local Agents = require("@builtin::modules.api.editor.agents")
local offer = {
{ id = "claude-sonnet-5", efforts = { "low", "medium", "high" } },
{ id = "claude-sonnet-5-5", efforts = { "low", "medium", "high", "xhigh", "max" } },
}
local choice = Agents.modelChoice("dotbot-claude", offer, "claude-sonnet-5")
-- choice.model == "claude-sonnet-5-5", choice.effort == "high", choice.modelFrom == "engine"
Agents.chooseModel("dotbot-claude", "claude-sonnet-5", offer) -- kept for this account
Agents.chooseEffort("dotbot-claude", "max", offer) -- refused: names "low, medium, high"
Agents.resetModelChoice("dotbot-claude") -- the engine's default again
| Call | Answers |
|---|---|
modelChoice(agent, offered, suggested?) | { ok, agent, model, effort, modelFrom, effortFrom, efforts, kept, notOffered?, effortNotTaken?, storeError? }; kept is the person's stored { model?, effort? }; storeError says why the kept choice could not be read |
chooseModel(agent, model, offered, suggested?) | { ok = true, choice, effortDropped? }, or { ok = false, reason, offered } for a model the offer does not list |
chooseEffort(agent, effort, offered, suggested?) | { ok = true, choice }, or { ok = false, reason, efforts } for an effort the model does not take |
resetModelChoice(agent) | { ok } |
offered is what the agent lists right now, { id, efforts?, defaultEffort? }
per model. A model resolves from the person's kept choice, then the engine's
default, then suggested, then the first offered; an effort from the person's
kept choice, then high, then the model's defaultEffort. A kept choice the
offer no longer holds is named in notOffered / effortNotTaken with the
reason, while the next in that order runs.