Skip to content
2 min read · 477 words

@nhtio/adk/batteries/orchestration/forge

The model-facing tool forge for the orchestration battery.

Remarks

This file is the ONLY place the wire↔IR conversion happens, and the ONLY place a model-facing tool is constructed for orchestration. A tool call cannot transmit a class instance, so on the wire a reference is {$ref: {node, select, path?, branchId?}} and a template hole is {$param: {path}} — single-key wrappers whose keys are RESERVED — and the IR uses real NodeRef/ParamRef instances. hydrateRefs converts wire→IR on the way in and dehydrateRefs converts IR→wire on the way out, so a model reading a plan back sees the same $ref/$param shape it writes. Nothing else in the battery ever sees the wire form.

Three surfaces, three threat models:

  • Tier A — 'front', what a conversational agent sees: list_templates, instantiate_plan, author_plan. The from-scratch path passes the owner's request VERBATIM and UNPARSED — pre-parsing their words into categories is what discarded "at the Holly Springs Walgreens" in the prior art — and every return is RENDERED PROSE, never raw JSON, because a model that re-reads its own JSON echo tends to re-plan rather than continue.
  • Tier B — 'authoring', graph mechanics, exposed only inside an authoring sub-dispatch: create_plan, add_node, set_node_config, connect_nodes, remove_node, disconnect_edge, clone_plan, get_plan, validate_plan, freeze_plan, unfreeze_plan, submit_plan, plan_status, raw_plan, raw_diff, plus the scoped reading pair plan_outline / plan_read.
  • Tier C is NOT a tool tier — it is runtime.invocable, the allowlist of what a staged call may invoke. Deliberately separate from the agent's tool surface: adding an agent tool never adds it here. The allowlist and the registry are the SAME object — the prior art's worst wart was ten names listed against a registry with zero callers, so author-time validation passed and fire-time threw "not registered". There is no second list.

Mutation tools return SCOPED PROSE, not the whole projected plan. The prior art returned everything so the model always re-read current state; that was written for a large window and is precisely the context problem here — 40 nodes echoed on every edit. Each mutation returns what changed, what it now connects to, and any new issues, BOUNDED regardless of plan size.

submit_plan/freeze_plan call freezePlan and surface each refusal with its model-addressed message. The prior art's "the dry run produced no finding" refusal is ABSENT — there is no dry run — and the reachability plus unedited-placeholder checks carry the weight it used to.

Interfaces

InterfaceDescription
ForgeOrchestrationOptionsTier selection and optional per-tool overrides + a mutating-tool gate.
ForgeOrchestrationRuntimeThe runtime a forge call is handed: the store, the tier-C allowlist, the wired predicate cells, and any registered templates.

Functions

FunctionDescription
forgeOrchestrationToolsForge the model-facing orchestration tools for a configured runtime and tier.