Reference
Agent API
The authored API is exported from @agent-jsx/core/agent. An agent renders its complete model-facing definition, but never declares whether it is a parent or child; composition supplies that relationship.
Agent<S, P>
abstract class Agent<
S extends Record<string, unknown>,
P extends object = {}
>
A hierarchy-free agent definition. S is durable state and P is the explicit input contract supplied by a composition boundary.
initialStateRequired initial durable state.render()Required synchronous model-facing definition.define(...)Protected helper that brands and type-checks the render result.propsCurrent typed composition input.Identity and model
static agentName = "policy-reviewer";
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
});
}
agentName is durable class identity; model is a required field in the rendered definition. Both are authored policy. The compiler does not infer provider, role, model, or hierarchy from class names, filenames, or export names.
render() and this.define(...)
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
description: "Reviews one supplied policy.",
displayName: "Policy reviewer",
inputSchema: policyInputSchema,
outputSchema: policyOutputSchema,
prompt: "Review the policy for concrete risks.",
tools: { lookup },
skills: [releaseNotesSkill],
mcpServers: {
policies: {
url: "https://mcp.example.com/policies",
transport: "streamable-http",
},
},
});
}
The required render result is one declarative agent definition. It may derive prompt or tools from current props and state, while model, description, display name, input/output schemas, skills, and MCP dependencies remain stable across renders. The model-driven Cloudflare target is currently the only target that lowers every field.
render() declares what the model can see and use. Returning an element or a Promise is an error. Application UI belongs outside the authored Agent class.state and setState(...)
readonly state: S;
setState(next: S | ((state: S) => S)): void;
Read current state and replace it with a value or functional update. Generated Cloudflare targets bridge this operation to Durable Object state; local compilation uses the same store contract.
@callable()
@callable()
approve(input: Approval): Result {
this.setState(state => applyApproval(state, input));
return { accepted: true };
}
Marks a method as part of the agent’s explicit public capability surface. Code generation creates the target-specific proxy; undecorated methods remain internal.
prompt
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
prompt: (
<prompt>
<sys p={10}>Review the supplied policy.</sys>
<msg p={8}>{this.props.policy}</msg>
</prompt>
),
});
}
Accepts plain text or prompt JSX. Prompt blocks are rendered under a priority budget. A model-driven class without skills exposes the result through getSystemPrompt(); a skill-bearing class composes the live authored prompt with Think’s Session skill catalog in beforeTurn().
inputSchema and outputSchema
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
inputSchema: policyInputSchema,
outputSchema: policyOutputSchema,
});
}
These static contracts define a class-authored child’s native agentTool boundary. Standard Schema values such as Zod pass through to AI SDK v6; a target-neutral throwing parse(value) validator is adapted without losing validation. After Cloudflare validates object input, the generated child binds it as the current this.props before re-rendering its prompt and tools. Child text is decoded first, then the parent tool applies the output schema exactly once so transforms are not duplicated.
tools
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
tools: {
lookup: {
description: "Read one policy by id.",
execute: ({ id }: { id: string }) => readPolicy(id),
},
},
});
}
Accepts an AI SDK-style tool map or declarative <tool> JSX. The model-driven Cloudflare target re-derives the map whenever Think asks for tools while preserving each AI SDK tool object, its schemas, execution function, approval policy, provider metadata, and structured-result contract. Declarative tools are merged with generated child agentTool entries.
skills and mcpServers
render() {
return this.define({
model: "openrouter/anthropic/claude-sonnet-4",
skills: [releaseNotesSkill, incidentResponseSkill],
mcpServers: {
policies: {
url: "https://mcp.example.com/policies",
transport: "streamable-http",
},
},
});
}
skills implement Cloudflare’s structural SkillSource contract. The Bun-driven emitter supports custom/importable sources and skills.fromManifest(...); it cannot currently load the Vite-only agents:skills module or env-bound skills.r2(...) sources. mcpServers is keyed by stable server name; each authored descriptor accepts an HTTP URL and optional auto, streamable-http, or sse transport.
mcpResolver(env, name, descriptor) may select a public URL, transport, OAuth callback settings, and non-secret configRevision. It must never return auth headers because Cloudflare Agents 0.20.1 persists MCP transport options. Callback hosts must be HTTP(S) origins, callback paths must be plain absolute paths, and credential-like query keys are rejected. Terminate bearer credentials in a proxy or service; use mcpConnectionTimeoutMs for the aggregate readiness wait.compileAgentClass(...)
const Reviewer = compileAgentClass(PolicyReviewer);
Lowers one authored class into a typed boundary component. Most projects consume generated companion modules and do not call this primitive by hand.
composeAgent(...)
composeAgent(
<Coordinator name="main">
{({ task, accept }) => (
<Worker name="worker" task={task} onResult={result(accept)} />
)}
</Coordinator>
);
Creates a root composition. The function child receives only the root’s getters and callable references. Nested boundaries define runtime hierarchy.
result(callable)
<Worker name="worker" onResult={result(accept)} />
Explicitly grants a child the authority to return its delegated result to a parent callable in targets that implement result routing. This is a visible capability binding, not a name-based convention. The model-driven Cloudflare target does not preserve parent callback, method, result, or render-prop continuation grants in a native child facet: agentTool returns child output to the parent model and the emitter reports each dropped capability kind.
Generated runtime
import {
emitCloudflare,
emitThink,
} from "@agent-jsx/core/compile/cloudflare";
Target plumbing is intentionally absent from the authored API:
getModel, optional deployment modelResolver, getSystemPrompt for definitions without skills or live beforeTurn composition for skill-bearing definitions, native tools and importable skills, runtime MCP clients, durable programmatic turns, and text/reasoning traces. Native child output returns to the parent model; parent-owned function and continuation bindings are diagnosed as unsupported.modelResolver(env, id) for SDK packages and secrets; neither agent names nor hierarchy select a provider.runTurnWithTrace bridge for progress indicators or thought bubbles. Authors do not implement stream callbacks manually.