Skip to main content

Optimizer Toolchain

This is the longest tutorial in the series. It connects the previous ideas:

  • use one of creates named context choices.
  • An optimizer is an ordinary AgentScript program.
  • host://optimizer gives that optimizer three tools: inspect, trial, and specialize.
  • The optimizer output is still normal .as source.
Optimizer Toolchain tutorial overview

The tutorial uses the runnable example in ../../../examples/optimizer/.

1. What We Are Optimizing​

The target program is ../../../examples/optimizer/triage.as:

import llm Qwen from "ollama://localhost:11434/qwen3.6"

main agent Triage {
model Qwen
role "Support triage"
description "Classify a support request with explicit selectable context policy."

main func(input {
request: string
}) {
use one of {
concise: "Use a concise one-paragraph triage style." selected
detailed: "Use a detailed triage style with rationale and next steps."
} as style

use input.request as "support request"

generate({ input: "Triage the support request", max_output: 500 }) -> {
priority
summary
next_steps: list[string]
}
}
}

There is one choice point:

use one of {
concise: "Use a concise one-paragraph triage style." selected
detailed: "Use a detailed triage style with rationale and next steps."
} as style

The source currently defaults to concise. The optimizer will trial detailed and preview the source rewrite that would move selected to that candidate.

2. The Optimizer Program​

The optimizer is ../../../examples/optimizer/optimizer.as:

import tool Optimizer from "host://optimizer"

main agent OptimizerAgent {
main func(input {
target: string
request: string
selection: json
write: string
trial_trace: string
output: string
dry_run: boolean
}) {
inspected = Optimizer.inspect({
target: input.target
})

trial = Optimizer.trial({
target: input.target,
input: {
request: input.request
},
selection: input.selection,
trace: input.trial_trace
})

write_mode = input.write
if input.dry_run {
write_mode = "preview"
}

specialized = Optimizer.specialize({
target: input.target,
selection: input.selection,
write: write_mode,
output: input.output
})

{
inspected: inspected,
trial: trial,
specialized: specialized
}
}
}

This is not a special runtime mode inside the language. It is a normal AgentScript program that imports one explicit host tool.

3. Understand Optimizer CLI Mode​

Optimizer mode starts when the CLI receives two positional .as files:

agentscript optimizer.as target.as --key value

The second file becomes input.target for the optimizer. Extra flags become input fields:

  • --request "..." becomes input.request
  • --selection '{...}' becomes input.selection
  • --trial-trace none becomes input.trial_trace
  • --write preview becomes input.write

Reserved runtime flags such as --max-trials, --max-llm-calls, --max-seconds, --run-dir, and --trace-file are used by the runner and are not passed into optimizer input.

4. Run a Preview​

From the repository root:

npm run agentscript -- examples/optimizer/optimizer.as examples/optimizer/triage.as \
--mock \
--request "Checkout is failing with 500 errors in production" \
--selection '{"examples/optimizer/triage.as#Triage.main[style]":"detailed"}' \
--write preview \
--output /tmp/triage.optimized.as \
--trial-trace none

With --mock, no real model call is made. This is the safest way to check the workflow shape, output fields, source diff, and CLI flag mapping.

5. Read inspect​

Optimizer.inspect parses the target without executing it. Its result includes the target files, snapshot id, variant sites, baseline selection, and warnings.

The important field is variant_sites. For this example you should see a site id like:

examples/optimizer/triage.as#Triage.main[style]

The format is:

path#Agent.func[label]

That stable id is what selection uses.

6. Read trial​

Optimizer.trial runs the target with a proposed selection:

{
"examples/optimizer/triage.as#Triage.main[style]": "detailed"
}

The result includes:

  • result: the target program's output
  • picked: which variants actually ran
  • unreached_selection: selected sites that were not reached
  • warnings: non-fatal issues
  • trace / trace_ref: optional trial trace data

In a real optimizer, this is where you would score the candidate using fixtures, an evaluator, an LLM judge, or downstream metrics.

7. Read specialize​

Optimizer.specialize rewrites source selection. In preview mode it does not write files; it returns a diff:

- concise: "Use a concise one-paragraph triage style." selected
- detailed: "Use a detailed triage style with rationale and next steps."
+ concise: "Use a concise one-paragraph triage style."
+ detailed: "Use a detailed triage style with rationale and next steps." selected

That is the key design point: the learning result is ordinary AgentScript source. There is no hidden database of prompt tweaks.

8. Write a Copy​

When the preview looks good, write an optimized copy:

npm run agentscript -- examples/optimizer/optimizer.as examples/optimizer/triage.as \
--mock \
--request "Checkout is failing with 500 errors in production" \
--selection '{"examples/optimizer/triage.as#Triage.main[style]":"detailed"}' \
--write copy \
--output /tmp/triage.optimized.as \
--trial-trace none \
--quiet

Use copy before in_place. It leaves the original target untouched.

9. Use Runtime Limits​

Optimizer runs can become expensive. The CLI provides hard limits:

agentscript optimizer.as target.as \
--max-trials 20 \
--max-llm-calls 100 \
--max-seconds 600

If a limit is exceeded, the runner raises BUDGET_EXCEEDED. These flags are not part of optimizer input; they guard the whole run.

10. Dry Run Convention​

--dry-run sets input.dry_run for the optimizer. The example uses that convention to force preview mode:

write_mode = input.write
if input.dry_run {
write_mode = "preview"
}

The CLI does not secretly rewrite your optimizer logic. Your optimizer decides how to interpret input.dry_run.

11. Safety Checklist​

Before writing optimized source:

  • Run inspect and check warnings.
  • Use trial with explicit selection.
  • Start with write: "preview".
  • Prefer write: "copy" before write: "in_place".
  • Keep runtime limits on real optimizer runs.
  • Review target imports, especially effectful tools.

12. Where to Go From Here​

This example does one manual selection. A fuller optimizer can:

  • inspect all variant sites
  • generate candidate selections
  • run many trial calls, possibly with parallel for
  • score each result against fixtures
  • choose a winner
  • call specialize once at the end

The important idea stays the same: optimization changes context choices in source code, not invisible prompt state.