Operate AML in a background job
This is an operational recipe, not a zero-credential demo. It shows the runtime boundary a Node job should own: provider construction, finite limits, redacted tracing, cancellation, and a clear result boundary. The live <Agent /> still needs its executable, model configuration, and credentials.
Create a job function that:
- accepts a caller-owned
AbortSignal; - uses an explicit OpenCode provider;
- limits Agent calls, concurrency, depth, state transitions, and turns;
- emits lifecycle traces without prompt content;
- returns only after AML has completed provider cleanup.
Prerequisites
Section titled “Prerequisites”- Node.js
>=26and an ESM TypeScript/TSX runtime; @aml-jsx/sdkand its OpenCode provider export;- the
opencodeexecutable available to the host or selected Sandbox; - model-provider credentials configured through environment or provider-native configuration;
- a structured logger in the surrounding job runner.
AML does not install the executable, provision a model account, or turn localSandbox() into a security boundary.
Complete source
Section titled “Complete source”import { Agent, AmlRuntime, createConsoleTracer, opencodeAgent } from "@aml-jsx/sdk"
const agentProvider = opencodeAgent({ model: process.env.AML_MODEL ?? "opencode-go/deepseek-v4-flash",})
const runtime = new AmlRuntime({ agentProvider, maxAgentCalls: 8, maxConcurrentAgents: 2, maxDepth: 12, maxTurnsPerAgent: 8, trace: createConsoleTracer({ captureContent: false, write(line) { process.stdout.write(`[aml] ` + line + `\n`) }, }),})
export async function runReview(input: string, signal: AbortSignal): Promise<string> { if (input.trim().length === 0) { throw new TypeError("Review input must not be empty") }
return await runtime.evaluate( <Agent system="Review only the supplied input. Do not claim to have inspected files you were not given."> Produce a concise review of this input: {input} </Agent>, { signal } )}
const signal = AbortSignal.timeout(120_000)console.log(await runReview("The authorization check occurs after the mutation.", signal))Run it
Section titled “Run it”Set up OpenCode and its model credentials first, save the complete source as recipe.tsx, then run that file through the TSX runner configured in Getting started:
npx vite-node recipe.tsxFrom an AML repository checkout, a separate maintained example proves a real OpenCode session can call an AML Tool:
AML_OPENCODE_MODEL=opencode-go/deepseek-v4-flash npm run example -- opencodeThat example additionally proves that a real OpenCode session can call an AML Tool. It does not provide a deployment image or credentials for you.
Expected output
Section titled “Expected output”The exact model prose is provider- and model-dependent. A successful run should produce one concise review and trace lines containing lifecycle identity, event name, and timing without prompt content. Treat model wording as nondeterministic; assert application-level structure or policy, not an exact sentence.
How it works
Section titled “How it works”- Construct the provider once at the job boundary. Provider options and credentials are not hidden in a component.
- Construct
AmlRuntimewith finite budgets. The defaults are finite too, but production jobs should make their workload profile explicit. - Pass the request’s cancellation signal to
runtime.evaluate. AML propagates cancellation to active providers and stops later frames; it cannot undo a side effect already completed by a Tool or provider. - Keep
captureContent: falsein ordinary logs. A trace sink can receive redacted lifecycle information while the job result remains application data.
Production checklist
Section titled “Production checklist”- Put credentials in the deployment secret store or environment; never write them into a Workspace or trace payload.
- If the workflow handles untrusted code, use a provider with an explicitly reviewed isolation configuration. Local execution is trusted host execution. Docker’s adapter does not itself configure network policy, capabilities, seccomp, CPU, memory, or user identity.
- Add a durable Workspace only when the job needs persistence. For S3 or revision-backed storage, plan for locks, conditional publication, retention, and conflict recovery.
- Retry only transient and idempotent boundaries. Do not blindly retry a Tool that already sent an email, mutated a repository, or published a revision.
- Record the AML run identity and provider failure cause in job metadata. Avoid recording prompts, secrets, or full model output by default.
- Set a job-level timeout shorter than the queue visibility or request deadline, and abort the runtime before the host forcibly kills the process.
Failure notes
Section titled “Failure notes”- Missing
opencodeor credentials fails at the provider boundary; it is not an AML syntax error. - An exceeded budget rejects the evaluation before more work is scheduled.
- Cancellation stops future work but cannot roll back external effects.
- A provider cleanup failure may be aggregated with the primary evaluation failure. Preserve both when reporting the job.
createConsoleTracer()is a dependency-free console sink, not a metrics backend. AdaptTraceSinkto your logger or telemetry system if you need durable event aggregation.