Skip to content

Release v1.13.0 - #399

Merged
sathish-mg merged 22 commits into
mainfrom
release/v1.13.0
Oct 20, 2026
Merged

sathish-mg merged 22 commits into
mainfrom
release/v1.13.0

Conversation

@sathish-mg

Copy link
Copy Markdown
Contributor

Release v1.13.0: a plan configures each LLM node, tools come from the run input, and locked parameters are applied.

Closes #391, closes #392, closes #393, closes #394, closes #396, closes #397.

What ships (see CHANGELOG [1.13.0])

Hardening from the branch reviews

  1. Without args_into, a dynamic entry's schema is closed: unnamed keys and locked keys are refused. With args_into, the entry's own additionalProperties decides.
  2. The model's arguments are validated against the schema it was shown (locked keys stripped), then the merged input against the Definition's.
  3. Dotted lock keys, and a lock on the args_into key, are refused at start.
  4. json_object mode adds "Answer with a JSON object." to a node system text that never says JSON. A json_schema that strict mode would reject is refused at start; the check walks nested properties, items, anyOf, a schema-valued additionalProperties and nullable object types.
  5. Fenced (```json) final answers are accepted.
  6. Under an egress policy, llm.system and a dynamic tool's prose are pseudonymized. The tools_from list is left out of the whole-state prompt.
  7. Shadow rehearses a run with the incumbent's frozen locks, so a 1.12 run still scores same on an unchanged plan.
  8. A dispatch pin that is another version of a bound or dispatch-pinned tool_name is refused.
  9. locked_params on client or decision tools produce a warning (RUN-W001), not an error, so 1.12 plans keep running.
  10. Transports report the temperature actually sent, and results record temperature_sent.
  11. Profiles reach the trigger paths and areev eval. The env twins are read only when a model is configured. off, no, 0 and false mean off, and a bare --llm-no-temperature takes no value. Note: the space form --llm-no-temperature false no longer means off; write --llm-no-temperature=false.
  12. The resume test now parks on a client gate and resumes against a superseded plan.
  13. The docs say where locks apply (areev-run, not loop/server/mcp).

Dependencies

  • rustls 0.23.45 → 0.23.46 (RUSTSEC-2026-0346 to 0349), a lockfile-only change in the root and areev-js lockfiles. No new dependencies.

Notes

  • The Linux CLI release assets carry a GLIBC 2.39 floor (the runner image). On older distributions they fail with a dynamic-linker error; use the PyPI wheel or npm package (glibc 2.31) or build from source there.
  • A node with no llm block journals byte-identically, so the scheduler epoch did not move.

Pre-flight (local)

cargo test --workspace --locked (3,468 passed), clippy -D warnings, cargo doc, cargo deny check, check_versions.py, repo_stats.py --check, the areev-js build plus node --test (115 passed), pytest (185 passed), cargo +nightly fuzz build, and cargo publish --workspace --dry-run (13 crates) all pass.

sathish-mg and others added 22 commits October 20, 2026 03:21
… omission; streamed turns record served_model (#391, #394)

ToolCallRequest gains response_format, parallel_tool_calls and
omit_temperature (and derives Default, so a literal can name only what it
sets). OpenAI-compatible bodies send response_format and parallel_tool_calls;
Anthropic states the schema in the system text and maps
parallel_tool_calls=false to disable_parallel_tool_use; Ollama sends format.
The three stream accumulators read the served model the way the whole-response
parsers do. RequestProfile parses the bindings' llm_profile JSON and can pin a
temperature value; resolve_toolcall_with_profile installs one on a transport.

Co-Authored-By: Claude <noreply@anthropic.com>
…mic tools (#391, #392, #393)

NodeExecutor::Abstract carries the node's frozen LlmNodeConfig. The first
message takes its instruction from the block (literal or a pointer into the
node's input, a miss failing the node SchemaValidationFailed, unretried) and
only the selected state keys; each turn journals the block's request fields
under input.llm (response_format already in wire shape); a node's max_tokens
is its reservation. A response declaration gets one corrective re-prompt,
then fails the node. tool_results_into collects every call of the attempt in
effect_seq order from the journaled outcomes.

OfferedTool gains locked (merged over the model's arguments, lock wins, the
strict check judging the merged input) and dynamic (a tools_from entry: its
own schema checked first, arguments optionally wrapped, dispatched as Host
under its own name with the Definition's address). A node with no block
builds byte-identical commands and state; no epoch bump.

Co-Authored-By: Claude <noreply@anthropic.com>
…cked_params (#391, #392, #393)

A plan's `llm: {node: {...}}` is validated at start (unknown keys, shapes,
a `tools` name or dispatch Definition the plan did not pin, duplicate or
colliding dynamic names — each refused naming the node and entry) and frozen
onto the abstract node's pin, `tools_from` resolved against the run input.
The driver builds each turn's request from the journaled `input.llm`: system
text, temperature or none, the node's ceiling, response_format and
parallel_tool_calls. Offered schemas lose their locked keys. A Definition's
locked_params are frozen with its pin.

A model-issued call now finds its Definition by frozen address rather than by
node, so a call to a code-carrying Definition from an abstract node runs the
pinned blob instead of falling through to --tool-cmd; a dynamic tool journals
under its own name and executes as the Definition it dispatches (exec_name).
run inspect shows the frozen block and locks.

Co-Authored-By: Claude <noreply@anthropic.com>
…e; the CLI reads its --llm-* profile flags (#394)

A trailing JSON-string argument (appended, so every positional caller keeps
its meaning): {"temperature": "omit" | n, "token_field": ..., "extra_body":
{...}}, parsed by RequestProfile::from_json and installed through
resolve_toolcall_with_profile. Unknown keys, a profile without a model, and a
profile the ollama transport cannot honour are refused before a run exists.
The run pins the profile digest, so a resume passes the same one.

The CLI's USAGE has listed --llm-token-field, --llm-no-temperature and
--llm-extra-body since #285 but nothing read them; run_stack now builds the
same profile from them (with $AREEV_RUN_LLM_* twins).

Co-Authored-By: Claude <noreply@anthropic.com>
…; the merged input is judged by the Definition's schema (#392)

`llm.<node>.dispatch: [name | hash]` resolves each entry as an unbound
node's same-named Definition is resolved (the run's namespace, then the plan
grain's; RUN-E004 naming the entry on a miss), pins it into the manifest's
dispatch_pins with its code address, runtime, capabilities and locks, checks
it at start like a binding, and never offers it to the model. A tools_from
entry may dispatch through those pins or a host pin of the plan, nothing else.

dispatch.arguments_into is renamed args_into (the shape the first pack is
written against). The Definition's input_schema is frozen beside each entry
and the merged input {...locked, [args_into]: args} is validated against it
whether or not the Definition is strict. Tests cover a nested
instruction_from pointer (/prompt/text).

Co-Authored-By: Claude <noreply@anthropic.com>
…1.13 Unreleased entries (#391-#394)

docs/run.md gains "Configuring an LLM node (llm)" under LLM nodes, with
every key, the dispatch list and tools_from, what is journaled, the start
refusals, the locked_params rule and the bindings' llm_profile.
docs/blessed-tools.md shows mcp.call behind tools_from. ARCHITECTURE.md §10
names the decision; both run crates' notes record the pinned rules. The
console opens a plan carrying an llm block view-only, as it does for reads,
since a resave would drop the block.

Co-Authored-By: Claude <noreply@anthropic.com>
… dependency requirements

The workspace, areev-js (package.json, Cargo.toml, the generated index.js),
areev-py's pyproject, areev-sandbox and the three lockfiles move to 1.13.0,
and so do the crates' internal requirements, as a minor release needs. The
CHANGELOG's Unreleased section becomes "1.13.0 — unreleased" with a fresh
Unreleased above it and the compare links updated. Not tagged, not published.

Co-Authored-By: Claude <noreply@anthropic.com>
…cribed in the ask (#396)

llm.<node>.narrow: false keeps a node's whole offer under a calibrated
decision backend; narrow: {top_k: n} (1-254) moves the K for that node; true
(the default) normalizes to nothing, so no manifest changes bytes. Frozen in
the manifest with the rest of the block; a malformed value is RUN-E019.

The narrowing question describes a tools_from tool by the first line of its
own description, read off the node's offer (two nodes may declare one name),
exactly as a pinned Definition's tool_description is carried; the run-wide
table no longer carries dynamic names.

Co-Authored-By: Claude <noreply@anthropic.com>
A tools_from entry's input_schema carrying $schema (as MCP servers publish
them) was refused RUN-E019. json_schema_subset::strip_annotations removes
$schema, $id, $comment, deprecated, readOnly, writeOnly and x-* at every
keyword position (a property NAMED $id survives) before the subset check, for
dynamic tool schemas and response.json_schema at run start and for a
Definition's input/output schema at write time. title, description, examples
and default stay (already portable); $ref/oneOf/anyOf/allOf/patternProperties
are still refused.

Co-Authored-By: Claude <noreply@anthropic.com>
…fe locks and strict-mode schemas at start; JSON-mode, fences, tools_from out of the prompt (review 1-5, 6b)

1. A dynamic entry's schema is closed: a key it does not name, or (without
   args_into) a key the host locked, is an argument violation and re-prompts.
2. The model's arguments are validated against the schema it was SHOWN
   (locked keys stripped, run-core DynamicTool::model_schema, shared with the
   driver's offer), then the merged input against the Definition's.
3. A lock key equal to args_into, or a dotted lock key (entry or Definition),
   is RUN-E019 naming the entry: locks are top-level keys only.
4. response {json: true} with a node system text and instruction that never
   say JSON gets one sentence appended (OpenAI json_object mode 400s
   otherwise); a json_schema strict mode would refuse is RUN-E019 at start,
   naming the first violation by pointer.
5. A fenced final answer (```json ... ```) satisfies a response
   declaration and merges.
6b. Under the whole-state default, the value tools_from points at (and the
   locks inside it) is removed from messages[0].

Co-Authored-By: Claude <noreply@anthropic.com>
…boundary pseudonymized (review 6a)

The request's system text was read off the raw turn input, not the masked
copy the messages are built from, so under an egress policy an llm.system
naming a person reached the provider in the clear; a tools_from entry's
description and schema prose (description, title, default, examples) did
too. Both now go through pseudonymize_for_model; structural schema strings and
the response schema are sent as declared, because arguments and answers are
checked against them as declared.

Co-Authored-By: Claude <noreply@anthropic.com>
…adow a bound Definition's name; client/decision locked_params are a warning (review 7-9)

7. shadow_plan re-resolved the candidate manifest and froze the Definition's
   locked_params even for an incumbent that never froze any (every 1.12 run),
   so an unchanged plan rehearsed a different validation and went out of
   support. Locks now come from the incumbent's own pins by hash (none when
   absent).
8. An llm.dispatch entry by content address could pin another version of a
   Definition a node binds under the same tool_name and overwrite its schema
   in the strict table. RUN-E019 at start, naming both hashes.
9. A client or decision Definition with locked_params was refused at start —
   a break for plans 1.12 ran. The locks are ignored, as before, and the start
   records RUN-W001 in the manifest's new `warnings` (shown by run inspect).

Co-Authored-By: Claude <noreply@anthropic.com>
…view 10)

OpenAiCompat never overrode effective_temperature, and Anthropic's ignored the
profile, so under an llm_profile that omits or pins a temperature the span's
gen_ai.request.temperature (and the intent's llm.temperature, which is the
plan's ask) claimed a value that was not sent. Both transports now answer from
RequestProfile::effective_temperature, and an LLM result records
temperature_sent (null when none went out) whenever the turn carries an llm
block or the transport a non-default profile — every other turn's result is
unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
…eev eval; off means off; a bare switch takes no value (review 11)

- triggerRun/triggerDeliver (Node) and trigger_run/trigger_deliver (Python)
  take a trailing llm_profile like runStart/run_start.
- With no llm_profile, the bindings read $AREEV_RUN_LLM_TOKEN_FIELD,
  $AREEV_RUN_LLM_NO_TEMPERATURE and $AREEV_RUN_LLM_EXTRA_BODY
  (RequestProfile::from_env), as the CLI does.
- areev eval --model builds the same profile as areev run.
- profile::is_truthy: false, 0, off and no (any case) are off, for the flag,
  its env twin and the bindings.
- parse_args: --llm-no-temperature never swallows the next positional;
  --llm-no-temperature=off spells it off.

Co-Authored-By: Claude <noreply@anthropic.com>
… apply; the review hardening documented (review 12, 13)

12. a_resume_uses_the_pinned_block_not_the_live_input now parks on a client
    gate before the agent runs, supersedes the plan with a different block and
    publishes a newer mcp_call of the same name, then resumes: the agent sends
    the frozen system text and tool list and runs the Definition pinned at
    start.
13. docs/run.md says locked_params are applied by run dispatch (areev-run)
    and not by areev-loop, areev-server or areev-mcp; RUN-W001; the review's
    rules (closed entries, top-level locks, strict-mode schemas, the JSON
    sentence, fences, the pruned prompt, pseudonymized system text,
    temperature_sent, profile coverage). CHANGELOG #393's note updated.

Co-Authored-By: Claude <noreply@anthropic.com>
…river rules

CHANGELOG [1.13.0] dated 2026-10-20 under a fresh empty [Unreleased], compare
links current. crates/areev-run/CLAUDE.md records the shared model schema,
shadow's incumbent locks, manifest warnings (RUN-W001) and the pseudonymized
system text. Lockfiles and crates/areev-js/index.js were already at 1.13.0
(cargo metadata x3 and napi build left them unchanged). Not tagged.

Co-Authored-By: Claude <noreply@anthropic.com>
cargo deny check failed on four rustls 0.23.45 advisories (published after
the base tag; the lockfile is unchanged from v1.12.2 there). A lockfile-only
patch update in the root and areev-js lockfiles (areev-sandbox does not use
rustls); no manifest or license change, so THIRD-PARTY-NOTICES.md (which lists
licenses, not versions) is unchanged.

Co-Authored-By: Claude <noreply@anthropic.com>
…is closed (delta review 1)

With args_into the arguments are the remote tool's, and an MCP tool's
published {"type": "object"} refused every key. The closed-schema rule now
applies only when args_into is unset (where an unnamed key is a Definition
parameter the host never offered); with it, only additionalProperties: false
closes the entry.

Co-Authored-By: Claude <noreply@anthropic.com>
…name (delta review 2)

Within a node or across nodes: the strict-argument table is keyed by
tool_name, so the second version overwrote the first's schema. RUN-E019 at
start, naming both hashes and both nodes.

Co-Authored-By: Claude <noreply@anthropic.com>
…rties and nullable object types (delta review 3)

strict_mode_violation treated only type: "object" (or a properties key) as an
object and descended only into properties and items, so a nullable
["object", "null"] object, an anyOf alternative or a schema under
additionalProperties reached OpenAI unchecked and 400'd on the first turn.

Co-Authored-By: Claude <noreply@anthropic.com>
…red (delta review 4)

A stale, malformed variable (AREEV_RUN_LLM_TOKEN_FIELD=tokens, say) failed
every run_start/runStart, including runs that call no model. The twins are
now parsed only when a model spec is given; an explicit llm_profile is still
refused without one.

Co-Authored-By: Claude <noreply@anthropic.com>
…f (delta review 5)

Co-Authored-By: Claude <noreply@anthropic.com>
@sathish-mg
sathish-mg requested a review from a team as a code owner October 20, 2026 04:28
@sathish-mg
sathish-mg merged commit 809c0dc into main Oct 20, 2026
21 of 23 checks passed
@sathish-mg
sathish-mg deleted the release/v1.13.0 branch October 20, 2026 04:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment