manifest
Manifest barrel — agent config conversion and tool schema handling.
Used by aai-cli (bundler) and aai-server (rpc-schemas). Generated bundle
entries call toAgentConfig, which is why this subpath is published.
Functions
Section titled “Functions”agentToolsets()
Section titled “agentToolsets()”agentToolsets(
def):Toolset[]
Every toolset an agent definition carries, in precedence order: its tools/
files, then what agent() and a host step attached (toolsets — the roster,
MCP). A dialog.tool needs no layer here: its own execute refuses out of
state, and that check travels with the def wherever it is declared — a spec,
a subagent, a direct call. Builtins are the runtime’s to append, since they
resolve against host options.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”Toolset[]
agentToolsToSchemas()
Section titled “agentToolsToSchemas()”agentToolsToSchemas(
toolsets):ToolSchema[]
Parameters
Section titled “Parameters”toolsets
Section titled “toolsets”readonly Toolset[]
Returns
Section titled “Returns”composeToolsets()
Section titled “composeToolsets()”composeToolsets(
sets,onShadowed?):ToolTable
Compose toolsets, FIRST WINS: a later set’s tool of an already-taken name is
dropped, and onShadowed hears about it — the precedence is the order.
Parameters
Section titled “Parameters”readonly Toolset[]
onShadowed?
Section titled “onShadowed?”(name, kept, dropped) => void
Returns
Section titled “Returns”gateToolset()
Section titled “gateToolset()”gateToolset(
set,gates):Toolset
Layer extra gates over a set — every gate must pass, the set’s own first.
Parameters
Section titled “Parameters”readonly ToolGate[]
Returns
Section titled “Returns”normalizeToolMessages()
Section titled “normalizeToolMessages()”normalizeToolMessages(
input):ToolMessages|undefined
Author input → the wire shape, dropping every kind the tool did not declare.
Answers undefined for a tool with nothing to say, so a schema for an
ordinary tool is byte-identical to what it was before this field existed —
which is what keeps messages off every deployed agent’s tool declarations
and out of every snapshot that did not opt in.
Parameters
Section titled “Parameters”ToolMessagesInput | undefined
Returns
Section titled “Returns”ToolMessages | undefined
toAgentConfig()
Section titled “toAgentConfig()”toAgentConfig(
source):object
Convert an agent definition into its serializable AgentConfig,
injecting the default providers, deriving the session mode, and running
the cross-field validation rules. Called from generated bundle entries and
the runtime.
Parameters
Section titled “Parameters”source
Section titled “source”Returns
Section titled “Returns”object
builtinTools?
Section titled “builtinTools?”
optionalbuiltinTools?: readonlystring[]
clientInbox?
Section titled “clientInbox?”{
sampleRate?:number; }
errorPhrase?
Section titled “errorPhrase?”
optionalerrorPhrase?:string
greeting
Section titled “greeting”greeting:
string
idleTimeoutMs?
Section titled “idleTimeoutMs?”
optionalidleTimeoutMs?:number
interruption?
Section titled “interruption?”
optionalinterruption?:"off"| {backoffMs?:number;continuationWindowMs?:number;minDurationMs?:number;minWords?:number;resumeFalseInterruption?:boolean; }
listing?
Section titled “listing?”
optionallisting?:string
optionalllm?:ProviderDescriptor<string,Record<string,unknown>>
maxOutputTokens?
Section titled “maxOutputTokens?”
optionalmaxOutputTokens?:number
maxRetries?
Section titled “maxRetries?”
optionalmaxRetries?:number
maxSteps?
Section titled “maxSteps?”
optionalmaxSteps?:number
mcpServers?
Section titled “mcpServers?”
optionalmcpServers?:Record<string, {allowedTools?: readonlystring[];pinnedTools?:Record<string,string>;tokenEnv?:string;url?:string; }>
optionalmode?:"s2s"|"pipeline"|"text"|"workflow-app"
name:
string
promptContext?
Section titled “promptContext?”
optionalpromptContext?:string
requiredEnv?
Section titled “requiredEnv?”
optionalrequiredEnv?: readonlystring[]
resetToolChoice?
Section titled “resetToolChoice?”
optionalresetToolChoice?:boolean
optionals2s?:ProviderDescriptor<string,Record<string,unknown>>
silence?
Section titled “silence?”{
deadAirCoverMs?:number;nudge?: {afterMs:number;prompt?:string; }; }
startFailurePhrase?
Section titled “startFailurePhrase?”
optionalstartFailurePhrase?:string
optionalstt?:ProviderDescriptor<string,Record<string,unknown>>
sttPrompt?
Section titled “sttPrompt?”
optionalsttPrompt?:string
systemPrompt
Section titled “systemPrompt”systemPrompt:
string
telephony?
Section titled “telephony?”
optionaltelephony?:boolean| readonlystring[]
temperature?
Section titled “temperature?”
optionaltemperature?:number
toolChoice?
Section titled “toolChoice?”
optionaltoolChoice?:"auto"|"required"|"none"| {toolName:string;type:"tool"; }
optionaltts?:ProviderDescriptor<string,Record<string,unknown>>
turnTaking?
Section titled “turnTaking?”{
detection?:string;maxSilenceMs?:number;minSilenceMs?:number;preemptiveGeneration?:boolean;startSpeakingFloorMs?:number;userTurnLimit?: {maxDurationMs?:number;maxWords?:number; }; }
usageLimits?
Section titled “usageLimits?”{
totalTokens?:number; }
voicePresets?
Section titled “voicePresets?”
optionalvoicePresets?: readonlystring[]
toolEntry()
Section titled “toolEntry()”toolEntry(
def):ToolsetEntry
Classify one def into an entry: the ONE place a def’s identity is inspected.
A clientTool (its brand) is executed by the page; everything else here.
Parameters
Section titled “Parameters”Returns
Section titled “Returns”toolRegistry()
Section titled “toolRegistry()”toolRegistry(
modules):ToolRegistry
Build a checked registry from already-loaded modules.
Synchronous, because the caller that matters most — the generated worker
entry — has the modules statically imported already, and a Promise there
would put top-level await in a bundle the guest loads.
Parameters
Section titled “Parameters”modules
Section titled “modules”Returns
Section titled “Returns”toolset()
Section titled “toolset()”toolset(
source,tools,gate?):Toolset
Build a Toolset over a map of defs, optionally gated.
Parameters
Section titled “Parameters”source
Section titled “source”Returns
Section titled “Returns”withTools()
Section titled “withTools()”withTools<
D>(def,registry):D
Attach a registry to an agent definition, returning the def the runtime runs.
A NEW object rather than a mutation: the def a module default-exports is shared (a spec imports the same one the entry does), and a loader quietly rewriting it makes the order of two imports decide what an agent can do.
It is also the seam every registry NOT assembled by a bundler goes on
through. Two do. withToolsDir (@alexkroman1/aai-runtime) scans a real
directory for a self-hosted process and comes back here. And the studio’s own
coding agent resolves its tool families from a session
(aai-guest/studio-agent.ts), which is what makes that honest rather than an
exception: a registry resolved from a session instead of from a directory,
attached the same way.
Closing over a directory is NOT what puts a registry here — this said so,
and templates/coding-agent/ disproves it: nine tools that all close over one
directory, shipped as FILES, each re-exporting an entry from a registry
shared.ts builds once. What the studio has that a template does not is a
directory chosen per SESSION and re-materialized under a running process,
where a file’s default export is evaluated once at import. The distinction is
LIFETIME, not closure, and it matters because the closure reading would tell
an author their tools cannot be files when they can.
A name the def ALREADY holds is an error. Through agent() that is now
unreachable — it returns an empty table and refuses a tools argument — so
what this catches is a hand-written export default { … tools: {…} } that
skipped agent(), and a second withTools over a def that already has one.
A name the def declared as a BUILTIN is an error too, and that one an
author can reach. builtinTools: ["calculate"] beside tools/calculate.ts
is one file name away at all times, filenames being the only thing here a
user picks freely — and it built clean: the runtime’s merge drops the
colliding builtin (mergeBuiltinSurface), so the entry the author wrote did
nothing and the only trace was one info line in a session log, minted at the
first call rather than at the build. That is the same silence discovery was
introduced to kill (“forgetting one line was silent”), reached by the other
route, and it is the one collision where BOTH halves were declared on purpose
— so it is a contradiction to report rather than a precedence to apply.
Structural rather than AgentDef, and it hands back what it was given: a
caller keeps whatever else its def carries, and nothing this returns is
described by a type the caller did not already name. builtinTools joins the
constraint as optional and widened to readonly string[], so a def that
carries none still passes and this module still names no builtin catalog.
It also RECORDS each def’s name (_testing-tool-names.ts). This is the
one step every lowering goes through that pairs a def with the name the
model calls, and a spec handed the def later — toolResultIn(calls, def),
toolNameOf(def) — has nowhere else to learn it. A WeakMap write per
tool, so a lowering that nobody tests costs nothing.
Type Parameters
Section titled “Type Parameters”D extends object
Parameters
Section titled “Parameters”D
registry
Section titled “registry”Returns
Section titled “Returns”D
withWorkflows()
Section titled “withWorkflows()”withWorkflows<
D>(def,registry,options?):D
Attach a discovered registry to an agent definition, returning the def the
runtime runs — a NEW object, for withTools’ reason (the def a module
exports is shared with every spec that imports it).
An explicit declaration wins a clash, and says so. withTools refuses a
name declared twice, because a tool’s file IS its declaration and a second
one is a contradiction. A workflow’s declaration of record is still
agent({ workflows }), and the common clash is benign — the author
registered workflows/digest.ts’s def as digest and the file ALSO
default-exports it, which is the same object under the same name. That case
is silent. A DIFFERENT def under a declared name keeps the declared one and
warns, naming the file, so the file’s author learns it is not the one
running rather than discovering it from a run that behaves like the other.
The same def declared under ANOTHER name (workflows: { nightly: digest }
beside workflows/digest.ts) registers ONCE, under the declared name, with
a warning naming the file: a def under two names was listed twice by
GET /workflows and could be started as either.
Structural rather than AgentDef, and it hands back what it was given, as
withTools does.
Type Parameters
Section titled “Type Parameters”D extends object
Parameters
Section titled “Parameters”D
registry
Section titled “registry”options?
Section titled “options?”Returns
Section titled “Returns”D
workflowRegistry()
Section titled “workflowRegistry()”workflowRegistry(
modules):WorkflowRegistry
The workflows a workflows/ directory declares, from its already-loaded
modules. Synchronous, like toolRegistry, so the generated entry carries no
top-level await.
A module that does not default-export a def is skipped (see the module
doc) — except a bodyless two-phase declaration, which is refused naming
.body(). One that is a def and is nested, misnamed or a duplicate is an
error naming the file.
Parameters
Section titled “Parameters”modules
Section titled “modules”Returns
Section titled “Returns”Interfaces
Section titled “Interfaces”ResolvedTool
Section titled “ResolvedTool”One resolved name in a ToolTable.
Properties
Section titled “Properties”
readonlyentry:ToolsetEntry
readonlyname:string
toolset
Section titled “toolset”
readonlytoolset:Toolset
ToolBearingDef
Section titled “ToolBearingDef”Properties
Section titled “Properties”
readonlytools:ToolMap
toolsets?
Section titled “toolsets?”
readonlyoptionaltoolsets?: readonlyToolset[]
Toolset
Section titled “Toolset”A source of tools, as the runtime consumes it.
The advertised list is fixed per session on every transport (an S2S service holds its tool list for the whole session), so a rule about WHEN a tool may run is a Toolset.gate at the call — which is also where the model is told why, and how to recover.
Methods
Section titled “Methods”execute()
Section titled “execute()”execute(
name,args,ctx):unknown
Run name’s body with already-validated arguments. Gating is the caller’s.
Parameters
Section titled “Parameters”string
unknown
Returns
Section titled “Returns”unknown
gate()
Section titled “gate()”gate(
name,ctx):ToolRefusal|undefined
undefined when name may run now; otherwise the refusal the model reads.
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”ToolRefusal | undefined
list()
Section titled “list()”list():
Readonly<Record<string,ToolsetEntry>>
Every tool this set advertises, by the name the model calls.
Returns
Section titled “Returns”Readonly<Record<string, ToolsetEntry>>
Properties
Section titled “Properties”source
Section titled “source”
readonlysource:ToolSource
ToolsetEntry
Section titled “ToolsetEntry”One advertised tool: the def the model reads, and who executes it.
Properties
Section titled “Properties”
readonlydef:ToolDef
Description, schema, messages and onError — what the model and the executor read.
executor
Section titled “executor”
readonlyexecutor:ToolExecutor
timeoutMs?
Section titled “timeoutMs?”
readonlyoptionaltimeoutMs?:number
A per-call deadline the entry carries (a clientTool’s timeoutMs).
ToolTable
Section titled “ToolTable”Several toolsets composed into one name → tool lookup.
Methods
Section titled “Methods”resolve()
Section titled “resolve()”resolve(
name):ResolvedTool|undefined
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”ResolvedTool | undefined
Properties
Section titled “Properties”
readonlytools: readonlyResolvedTool[]
Every advertised tool, in precedence order.
Type Aliases
Section titled “Type Aliases”AgentConfig
Section titled “AgentConfig”AgentConfig =
z.infer<typeofAgentConfigSchema>
JSON-safe subset of the agent definition — the canonical serializable config that flows CLI → server → runtime unchanged.
AgentConfigSource
Section titled “AgentConfigSource”AgentConfigSource =
Omit<AgentConfig,"mode"|"systemPrompt"|"promptContext"|"mcpServers"> &object&{ [K in HostOnlyAgentField]?: unknown }
What toAgentConfig accepts: every serializable AgentConfig
field plus the host-only fields the deny-list strips. AgentDef is assignable to this by
construction; the explicit | undefined on the host-only members keeps
spread call sites ({...agent, stt: maybeUndefined}) legal under
exactOptionalPropertyTypes.
Type Declaration
Section titled “Type Declaration”mcpServers?
Section titled “mcpServers?”
optionalmcpServers?:McpServers
Wider than the wire’s record for the same reason: an McpServerConfig may
carry a url RESOLVER and headers, both host-only. toAgentConfig
strips them (see wireMcpServers).
optionalmode?:AgentMode
See AgentDef.mode; undefined from a spread means the default.
promptContext?
Section titled “promptContext?”
optionalpromptContext?:AgentPromptContext
The same widening for promptContext, whose function half is dropped the same way.
systemPrompt?
Section titled “systemPrompt?”
optionalsystemPrompt?:AgentSystemPrompt
Wider than the config’s own string, because AgentDef.systemPrompt
may be a RESOLVER — a function this layer cannot serialize and must not
hand onward. Widened here rather than on AgentConfig so AgentDef
stays assignable to this by construction, which is what every
toAgentConfig(agent) call site relies on. toAgentConfig drops it (see
staticSystemPrompt); the runtime holds the agent’s own module and asks
the function per request.
HostOnlyAgentField
Section titled “HostOnlyAgentField”HostOnlyAgentField = typeof
HOST_ONLY_AGENT_FIELDS[number]
A host-only AgentDef field name stripped by toAgentConfig (tools, events, …).
ResolvedAgentDef
Section titled “ResolvedAgentDef”ResolvedAgentDef =
AgentDef&object
An AgentDef as the RUNTIME holds it: plus every toolset beyond the
tools/ files — RESOLVED, never authored. agent() attaches the roster’s
and withMcpTools an MCP server’s; read the whole table through
agentToolsets. Not on the authoring surface: an author never names a
toolset, so the public AgentDef does not carry the field’s type.
Type Declaration
Section titled “Type Declaration”toolsets?
Section titled “toolsets?”
readonlyoptionaltoolsets?: readonlyToolset[]
SessionMode
Section titled “SessionMode”SessionMode =
"s2s"|"pipeline"|"text"
Session mode derived from which provider fields are set.
toAgentConfig, createRuntime, and the server’s IsolateConfigSchema
all use assertProviderTriple so there’s one source of truth for the
validation.
"text" is the one mode with no audio path at all: the agent is an LLM,
a system prompt and its tools, driven by createTextAgent
(@alexkroman1/aai-runtime) over a message list rather than by a
transport over a socket.
ToolExecutor
Section titled “ToolExecutor”ToolExecutor =
"host"|"client"
Who runs a tool’s body: this process ("host"), or the connected browser page
("client", a clientTool — the call waits for the page’s tool_result).
ToolGate
Section titled “ToolGate”ToolGate = (
name,def,ctx) =>ToolRefusal|undefined
A gate over one def — what toolset composes into Toolset.gate.
Parameters
Section titled “Parameters”string
Returns
Section titled “Returns”ToolRefusal | undefined
ToolModules
Section titled “ToolModules”ToolModules =
Readonly<Record<string,unknown>>
path → module namespace, which is what both sources produce: Vite’s
import.meta.glob (eager) and the static import list the CLI generates.
ToolRegistry
Section titled “ToolRegistry”ToolRegistry =
Readonly<Record<string,ToolDef>>
A checked set of tools, keyed by the name the model calls.
ToolSchema
Section titled “ToolSchema”ToolSchema =
object
A tool declaration in wire form: name, description, and JSON Schema
parameters — the serializable counterpart of ToolDef.
Properties
Section titled “Properties”description
Section titled “description”description:
string
effect?
Section titled “effect?”
optionaleffect?:ToolEffect
What the tool does to the world — see ToolDef.effect. A host-mode client
declaring its own tools sets it the same way; an MCP tool’s comes from its
server’s readOnlyHint. Never sent to the model.
messages?
Section titled “messages?”
optionalmessages?:ToolMessages
The tool’s spoken messages, NORMALIZED — see ToolMessages.
It rides on the wire declaration rather than beside it because that is what
makes the feature mean the same thing in every mode: the deployed guest
builds this from the agent’s own ToolDefs, and a host-mode client that
supplies its own tool declarations gets the behaviour by declaring the
field. Nothing here reaches the model — toVercelTools passes name,
description and parameters to the provider and reads this itself.
Absent for every tool that declares none, which is what keeps an ordinary tool’s wire declaration byte-identical to what it was before the field existed.
name:
string
parameters
Section titled “parameters”parameters:
JSONSchema7
type:
"function"
optionalui?:ToolUi
How a page displays the tool — see ToolUi (tool-def.ts). Rides here
for the reason messages does: the deployed guest builds the declaration
from the agent’s own ToolDefs, and the pre-connection client config
carries the same hints (toolUiMap, tool-ui.ts), so the default client
renders the same thing everywhere. Absent for a tool that declares none.
ToolSource
Section titled “ToolSource”ToolSource =
"files"|"builtin"|"mcp"|"roster"|"subagent"
Where a Toolset’s tools come from — for a log line, a collision message, and a spec. It decides nothing about execution; the entry does.
WithWorkflowsOptions
Section titled “WithWorkflowsOptions”WithWorkflowsOptions =
object
Input
What withWorkflows may be told.
Properties
Section titled “Properties”
optionalwarn?: (message) =>void
Where a name-clash warning goes. Default console.warn, which under
aai build and aai dev reaches the terminal; the studio passes its own.
Parameters
Section titled “Parameters”message
Section titled “message”string
Returns
Section titled “Returns”void
WorkflowModules
Section titled “WorkflowModules”WorkflowModules =
Readonly<Record<string,unknown>>
path → module namespace, as both sources produce it: the static import
list the CLI generates, and a spec’s import.meta.glob (eager).
WorkflowRegistry
Section titled “WorkflowRegistry”WorkflowRegistry =
Readonly<Record<string,WorkflowDef>>
A checked set of workflows, keyed by the name they are started under.
Variables
Section titled “Variables”HOST_ONLY_AGENT_FIELDS
Section titled “HOST_ONLY_AGENT_FIELDS”
constHOST_ONLY_AGENT_FIELDS: readonly ["tools","syncState","workflows","roster","toolsets","dialogs","events","inputGuardrails","outputGuardrails","sessionContext","onSessionEnd","routes"]
AgentDef fields that must never cross the serialization boundary — the
single deny-list toAgentConfig strips. Everything else on the agent
definition flows into AgentConfig by default, so a new serializable
field works CLI → server → runtime without touching a mapper. A field added
to AgentDef must appear either in AgentConfigSchema or here — the
type-level guard in the internal-types test enforces that subtraction.
It cannot catch a SUPERFLUOUS entry, which is the other direction and the one
that went stale: state sat here after AgentDef.state was deleted with the
ctx.state bag, denying a key nothing produces and telling every reader the
bag still exists. An entry here is a claim that AgentDef has that field.
References
Section titled “References”ToolCompletionMessage
Section titled “ToolCompletionMessage”Re-exports ToolCompletionMessage
ToolDelayedMessage
Section titled “ToolDelayedMessage”Re-exports ToolDelayedMessage
ToolMessageCondition
Section titled “ToolMessageCondition”Re-exports ToolMessageCondition
ToolMessages
Section titled “ToolMessages”Re-exports ToolMessages
ToolMessagesInput
Section titled “ToolMessagesInput”Re-exports ToolMessagesInput
ToolStartMessage
Section titled “ToolStartMessage”Re-exports ToolStartMessage