Repository navigation
Releases
v0.6.0
Minor Changes
-
f00872f: A Pattern that produces assets takes an optional
input.name, and the produced asset's handle is that name.Why. Handles were only ever minted, at record time and in completion order. A model that dispatched eleven images in parallel and then wrote
asset://image_4from its own call order got a real image — the wrong one — and nothing failed. A name bound for the dispatch makes a reference the model did not copy miss withHANDLE_NOT_FOUNDinstead of landing on a neighbour.What the model sends. Registration adds
nameto the tool inputs of every Pattern whose outputs carryassets[]— atomics, metas, plans and agents alike — sodispatch_pattern, always-load tools,find_patternand the agent loop all carry it. It is trimmed,asset://heroreads ashero, and a blank name means none. A name in any asset kind's mint grammar (image_3,video_1) is refused, so a chosen name can neither collide with a minted handle nor be read as a replay that moves the ledger's counter. One product takes the name; several take<name>-1…<name>-nin output order (deriveNamedHandles). Anameon a Pattern that produces no assets is refused withINPUT_VALIDATION_FAILEDrather than dropped.What the host does.
resolveAssetReferencesreads the name through the newproductNameOfand refuses one the context already holds — exactly, or as a<name>-<n>— with a newAssetResolutionErrorvariant,HANDLE_TAKEN, before anything else is evaluated; an exhaustiveswitchover the codes gains a case.AgentAssetBridge.recordOutputreceives the normalised name, and the agent loop runsresolveForDispatchfor a named dispatch even when the Pattern declares no asset slots. Just before writing a named call's products, a bridge runsresolveAssetReferences({ name }, [], index)again over the context as it stands, minus the assets this call is recording: a same-turn call may have taken the name since, and the store'sHANDLE_COLLISIONwould not noticeherobesidehero-1,hero-2, while a replay of the call's own products (a retried write, a dedupe hit) keeps the name. OnHANDLE_TAKENit records all of that call's products under minted handles and says so in a top-level notice in the tool result, as it does when a write collides.mintNext,parseMintedHandle,producesAssetsandRESERVED_INPUT_KEYSare exported, so a durableAssetStorewrites handles by the same rule asInMemoryAssetStoreand a host can refuse a user-authored schema before saving it.Breaking (0.x, no shims).
referencesandnameare reserved top-level input keys: registration derives both on a copy of the Pattern, and a hand-written top-levelreferencesornamethrowsINPUT_RESERVED_KEY(details.keynames it,details.reasonis'hand-written') — delete it, registration derives it. Inputs that are not az.objectare judged on their rendered JSON Schema, so the key counts in any member of a union or part of an intersection too. The same code with reason'undeclared'is new as well: it refuses a derived field the Pattern's own declaration no longer produces, which happens when a host clearsassetNeedson a factory-built Pattern (an override that still declares slots is re-derived instead) or re-registers a registered Pattern whose outputs no longer carryassets[].extendInputsWithReferencesno longer replaces a hand-writtenreferences; it throws the same error. Areferencesproduced byextendInputsWithReferences, or placed fromderiveReferencesSchema(...)unwrapped, is recognised and re-derived from the Pattern's ownassetNeeds. Nested keys are not reserved.AGENT_BASE_INPUT_SCHEMAno longer declaresreferences: an agent that declaresassetNeedsgets the derived field, and one that declares none has none — it was never resolved.AgentBaseInput,agentInputSchema's result andOrchestratorInputSchemachange type with it.agentInputSchema({ name: … })throws at construction, asagentInputSchema({ references: … })already did, with anAGENT_INPUT_RESERVED_FIELDerror — a plainErrorwith that message prefix and nodetails.key— notINPUT_RESERVED_KEY. An asset-producing Pattern whose tool inputs is not az.objectis refused at registration (EXTEND_NAME_UNSUPPORTED_INPUTS).Prompt caches miss once. Every asset-producing Pattern's tool schema gains a field, and agent schemas lose their hand-written
references, so provider-side prompt caches built on the old tool definitions invalidate once.Part of the work.
nameis hashed with the rest ofinput, with no special case: a retry repeats the name and still dedupes, and the same prompt under two names is two products. Nothing is added toJobSpec.meta_planreads its DAG without the reserved keys, so a named one-shot plan validates as before. Areferenceskey sent tometa_plan, which declares no slots, used to fail withPLAN_SCHEMA; it is now stripped and ignored, like a stray key on any Pattern without slots — except on the agent loop, where a call that also carries anamegoes through the bridge's resolution pass, which refuses any slot thatreferencesnames withUNKNOWN_SLOTbefore anything is dispatched.Plans. A
namein a plan step's input is refused with the newPlanProblemCodePLAN_STEP_NAME_NOT_ALLOWED: a step's products are never recorded under a name, so the plan names its own product instead. A step'sinput.referencesis unchanged.Known limitation. A hand-written meta's
composeis not validated, so anameit forwards into a sub-step input is never recorded and has no effect. -
9ca4d97: A
ctx.stepis keyed by where it sits in the dispatch tree, so a step that already succeeded is not paid for again because something beside it ran differently.Why. A step's durable key carried one number from a counter the whole dispatch tree shared, taken when the step was called. When two composes ran at once — parallel nested metas, a capped plan level — or a sibling dedupes on a resubmit and so never runs its compose, the same step drew a different number the next time, missed the row it had written, and ran again. A park (
ctx.askUser) drew from the same counter, so it moved the key of every step after it.What keys a step now. Its path: the ids of the steps that launched its compose, then its own —
panel-0/meta_image-best-of-n#0/text-to-image#1. A step named withstepIdis keyed by that name, so adding, removing or reordering other steps in its compose never re-keys it; it moves only if a step that launched its compose is renumbered, so name that one too. An unnamed step is${patternId}#${n}(a/in the pattern id is written%2F), wherencounts the unnamed calls to the same pattern earlier in the same compose: inserting a named step, or a call to another pattern, leaves it alone. The path travels asJobSpec.stepKey, andderiveIdempotencyKeyhashes{ patternId, input, assets, sessionId, stepKey }, withstepKey: nullwhen there is none — a host's directsubmitJob, an agent loop's tool call.ctx.askUserids keep their${rootJobId}:ask:prefix and are counted on their own, so a park moves no step's key. Aretryon a step whose child is a meta now finds the rows its failed attempt wrote, and the computes it settled; it used to fail withDUPLICATE_STEP_IDwhen the child named its steps, and run every finished step again when it did not. That holds because a meta whose compose fails, or whose output its gate refuses, now settles only once the steps andctx.submitJobchildren it had already started have settled, and refuses any step, submit or park asked of it after withSTEP_AFTER_COMPOSE_FAILED, so a failing meta takes as long as its slowest in-flight step — the trade a failing plan already makes for its independent branches. A step still in flight that is itself parked onctx.askUser, inside a nested meta, keeps the failing meta open until that park is answered or the job is cancelled. An adapter that ignores itsAbortSignalholds a cancelled failing meta open until it returns; deadlines stay the host's to impose. Identical work in one session is one unit of work: two different top-level metas whose first unnamed call to a pattern carries the same input and assets share that row, becausestepKeyseparates deliberate repeats inside a compose rather than partitioning a session by meta.Every stored key moves once. Rows written by
ctx.stepnow hash astepKeyand nostepIndex; rows with nostepKeylosestepIndex: 0and hashstepKey: null. The first resubmit after upgrading recomputes what it would have found, once. Nothing stored is lost, aJobStoreneeds no migration, and keys are stable from then on.Breaking (0.x, no shims).
StepOptions.identityis removed, withSTEP_IDENTITY_REQUIRES_STEP_ID: a named step is keyed by its name without asking, so delete the option. A caller the compiler does not stop — JavaScript, or options built in a variable — is not refused: the option is ignored, soidentity: 'id'without astepId, which threw, now dispatches, keyed by position.StepOptions.metadatais removed; nothing read it.JobSpec.stepIndex,ExecutionContext.stepIndexandDeriveIdempotencyKeyInput.stepIndexare removed. A default step id injob:stepandStepResult.meta.stepIdnames a step within its own compose only, so two subtrees can both reporttext-to-image#0— correlate onchildJobId. An unnamed call to a pattern whose id carries/reports its escaped id there:image-gen%2Ffancy-edit#0, notimage-gen/fancy-edit#0. An explicitstepIdspelled like a default id now collides with the first unnamed call to that pattern in the same compose (DUPLICATE_STEP_ID), and one containing/, which separates the ids in a step's path, is refused (STEP_ID_RESERVED_CHARACTER). So is a `ctx.compute...
v0.5.0
Minor Changes
-
073e433: Every AI SDK adapter now refuses a resolved asset slot it does not send to the provider.
Tightened (0.x, no shims):
fromVisionModel,fromTranscriptionModelandfromLanguageModelfail the call withASSET_SLOT_NOT_SUPPORTEDwhen it carries a resolved slot they do not map, before anything reaches the provider. Until now they ran the call and dropped the slot: a second slot beside image-to-text's or ASR'ssource, or any slot on atext-generationcall, never reached the model, and nothing in the output said so.fromImageModelandfromSpeechModelalready refused; the rule is now the same across all five. A host that relied on the silent drop removes the reference from the input, or wraps the adapter and sends the slot itself.Two changes landing alongside this one are internal and change no behaviour: the runtime reads core's
JOB_TERMINAL_STATUSESinstead of its own copy of the terminal set, and@orchestral/plan's two validation layers share one helper for a step's input schema.
v0.4.0
Minor Changes
-
cc7d6d6: A plan can now take media from its caller, key its own steps, and bound how wide a level runs; a step's failure no longer cancels branches that do not depend on it.
A plan is a media pattern like any other.
PlanToMetaOptions.assetNeedsdeclares the asset slots a plan takes. The pattern then carriesassetNeeds, so a host's resolution pass runs for it exactly as for an atomic, andtool.inputsgains the derivedreferencesfield, so a caller fills slots by handle in the schema it already knows instead of threading an asset id through as an untyped string. Inside the DAG the slots are addressable through a new production,$input.assets[slot=<name>]— the media counterpart of$input.<field>. An array slot fans in through a single ref. Two newPlanProblemCodes name the two ways it can be wrong:PLAN_INPUT_ASSET_NOT_ALLOWED(the plan declares no slots) andPLAN_INPUT_SLOT_UNKNOWN(the name is not one of them); modality, cardinality and required-ness are checked against the child slot with the existing codes.StepOptions.idempotencyKeylets a step inside a meta key its durable row on a string the caller derives, whichJobSpec.idempotencyKeyhas always allowed a host submitting directly. The engine's own derivation hashessessionIdon purpose, so reuse that outlives a session could not be expressed by choosing anidentitymode.RunPlanOptions.idempotencyKeyForis the same seam for a plan's steps, which the interpreter dispatches on the author's behalf. It is a pure derivation — it cannot skip a step, supply an output, or stop the walk — and what it changes is which row the dispatch lands on. The burden of "what is the same work" moves with the key, minus one collision the engine keeps: a key already held by a row for a DIFFERENT pattern is refused with the newIDEMPOTENCY_KEY_CROSS_PATTERN, because that row's output was gated against the other pattern's schema and never against this one's. Only a caller-supplied key can reach it — the derivation hashespatternId. Within one pattern the old rule stands: a key that omits something the step reads returns a stale-but-valid result, not an error. Within one level, two steps of the same pattern under one key collapse to one row and surface asPLAN_STEP_IN_FLIGHT, so a key derived from the input alone is not enough for a fan-out.parallel.limit(tasks, concurrency)bounds a fan-out. It takes thunks rather than promises, because a promise is already running by the time it is a value;parallelitself is unchanged.RunPlanOptions.concurrency(also onPlanToMetaOptionsandcreatePlanMeta) applies it to a plan's levels. Default unlimited. Turning it on has a cost worth reading before you do:ctx.stepadvances a tree-shared counter at call time, and that counter keys the internals of a nested meta run as one plan step — uncapped, a level's steps are all called synchronously and those inner rows land on the same indices every run; capped, a step starts when an earlier one settles, so that stability is given up. A plan's own steps are unaffected either way.PlanOutputSchema.assets[].modalitynow accepts core's wholeAssetKind—document,data,archiveandotherin addition to image/audio/video. A plan ending in a document was always writable and failed only at the dispatch exit, as anOUTPUT_SCHEMA_MISMATCHnaming the plan rather than the step that produced the value.assetKindField()is the single source both sides now read;ASSET_KINDSbacks it internally, with a two-way exhaustiveness lock between the two, and is not exported.Three behaviour changes, all deliberate:
- A failing step now invalidates exactly its transitive dependents. Previously the first rejection rejected its whole dependency level and no later level started, so a failure in one branch cancelled unrelated ones. The plan still fails, with the same error — but steps that do not read anything that failed now run and are banked in the JobStore, which is what makes the documented "the steps that succeeded are not re-run when you resubmit" pay off. Two costs: a failing plan now takes as long as its slowest independent branch rather than failing fast, and when several steps fail the error raised is the first in step-list order rather than whichever provider gave up first (previously non-deterministic).
PLAN_ASSET_REF_REno longer matches$input.…, so the two asset productions are disjoint. Nothing that used to run stops running: a step may not be calledinput(PLAN_STEP_ID_RESERVED), so those strings always resolved to nothing — they were merely refused by the walk instead of by the grammar. Step ids that only begin withinput($inputs.assets[0],$input-frames.assets[0]) are unaffected. If you match the exported regex yourself,$input.assets[0]now fails it.- An inner asset binding's
modalityis now narrowed, not cast. The interpreter used to assert that a producing step'smodalitystring was anAssetKind; any string flowed through silently and failed later, as the PLAN's own output parse. It now throwsPLAN_ASSET_MODALITY_UNKNOWNat the site it was read. A plan that used to run can now fail: one whose step names a pattern declaringmodality: z.string()in its outputs and returning something outside the seven kinds ('img'). That is the intended trade — a pattern contradicting its own declared outputs is not a value to launder into a valid-looking kind, and refusing at the read names the ref and the site instead of naming the plan after the money is spent.details.planStepIdis the CONSUMING step at a step binding, and is absent at anoutput.assetsentry, which carriespath; the producer is ondetails.refin both cases.
Everything else is additive and every default is unchanged: a plan that declares no
assetNeeds, passes noconcurrencyand supplies noidempotencyKeyForbehaves exactly as before, and the child specctx.stepbuilds is byte-identical when the new option is absent, so no stored idempotency key moves.planDagSchema({ inputAssets })is new alongside the existingPlanDagSchema, so the one-shot rendering path can ask for the grammar it can satisfy instead of the grammar plus one unsatisfiable production.
v0.3.0
Minor Changes
-
ab00fc3: Enforcement now matches the argued design:
buildAlwaysLoadDescriptorsfilters
throughresolveExposurebefore readingexposureMode; middleware
short-circuit outputs pass the same exit gate as adapter outputs
(OUTPUT_SCHEMA_MISMATCH), whatever the Pattern's kind — no finish tool ran
there, so a supplied value answers for itself, and a cache entry the schema now
rejects fails loudly instead of being served; an agent failure tool-result
carriesproduced_handlesinstead of raw asset ids. Single sources reclaimed:
toJsonSchemais the only outbound zod→JSON Schema edge (guarded by a static
test), handle minting and subagent-blocklist matching are single functions,
the orchestrator derives its tool list from the patterns package instead of a
hand copy, andbuildAgentInlineCorenow takes the owner pattern id and fails
loudly on allowlisted ids missing from the registry (internal signature
change — it is not on the@orchestral/runtimebarrel). AI SDK adapters fail
loudly on unsupported asset slots and no longer lose providerOptions under
namespaced or relayed provider ids. DESIGN.md citations are now anchors
verified by a static test.The per-Pattern opt-out from the sub-agent blocklist is gone. The blocklist
beatloop.toolPatternIdsat dispatch already; it now beats it at the catalog
too, so anagent_id an author lists is skipped when the inline core is built
rather than rendered as a tool whose every call comes backSUBAGENT_BLOCKED.
Listing one was never a widening — it was a way to advertise a tool that did
not work — and the catalog and the call side now say the same sentence.
Opening recursion means overridingDEFAULT_SUBAGENT_BLOCKLISTitself, which
is the honest place to argue for it: one decision, visible at the seam that
enforces it, instead of per-Pattern grants that only look like permission.New error codes.
AGENT_TOOL_PATTERN_NOT_REGISTEREDfails an agent
dispatch whoseloop.toolPatternIdsnames ids the registry does not have —
before the loop starts, since an unsatisfiable allowlist is an authoring error
and nothing has been dispatched yet to pay for it.ASSET_SLOT_NOT_SUPPORTED
is the loud half of the adapter change above: a slot the adapter cannot send is
refused by name instead of being dropped on the way to the provider.
NO_SOURCE_ASSETand
SOURCE_ASSET_NOT_LOADEDon theautomatic-speech-recognitionpath are now
carried ascodeon the thrown error, not just spelled in its message, so a
host narrows on them the way it narrows on every other orchestral failure.New public exports, all additive:
matchSubagentBlocklistand theSubagentBlocklisttype
(@orchestral/core) — the one matcher both the catalog and the call guard
ask, so a host that wants to predict a refusal asks it too rather than
re-implementing the prefix rule.buildAlwaysLoadDescriptorstakes asurfaceoption (@orchestral/core):
'chatTurn'(default, unchanged) or'agentLoop', so a sub-agent's inline
core admits anexposure: 'agent-tool'Pattern and excludes a chat-only one.FIRST_PARTY_PATTERN_IDS(@orchestral/patterns) — the shipped id catalog
as data, grouped by declared kind. This is what ended the orchestrator's hand
copy; a host registering a subset can read it too.ORCHESTRATOR_DEFAULT_PROMPTS,OrchestratorAgentInit,
OrchestratorPromptOverrides, and a widened
createOrchestratorAgent(init?)(@orchestral/agent) — prompt body, tool
universe and abort mode are defaults this package picked on your behalf, and
the alternative to overriding them was forking a package whose entire content
is one declaration. The no-argument call is unchanged.AgentAssetBridge.handlesFor(@orchestral/runtime) — optional, so an
existing bridge still type-checks. Implement it and a failed child dispatch
reports its partial work as handles the loop can cite; leave it out and the
loop is told a count, as before.
agent_orchestratorno longer declaresloop.asyncToolPatternIds. It has
one tool universe on purpose. The field prunes the catalog to
toolPatternIds ∩ asyncToolPatternIdsand only whendefaultExecutionModeis
'async', which this pattern never set — so the declaration bought no
behaviour and was a second list to keep in sync.image-to-text: an unknownmodeno longer throws. The AI SDK vision
adapter keeps a copy of the pattern'smodeenum (it does not depend on
@orchestral/patterns), and a mode with no entry there is now a mode it has no
default instruction for and nothing more: the call runs with no system text,
exactly as it does when the caller passes aprompt. This is the one place on
this branch where the change is toward silence rather than away from it, and
the reason is asymmetry — the failure it removes was "patterns added a word" to
becoming a hard outage in every host wrapping this adapter, for a mode whose
only effect is a sentence the caller could have written themselves. A test
asserts the table still covers the pattern's enum, so the drift shows up in CI
instead of in production.@orchestral/agentdropped its@orchestral/runtimedependency, which it
did not use: the package is a pure declaration and the runtime is where the
agent seam lives, not where the Pattern is authored. If you were relying on the
transitive install to get@orchestral/runtime, add it to your own
dependencies — you were always the one constructing the runtime. -
ab00fc3: Package boundaries. Four things that were split across packages, or bundled
into one, moved to where they belong: the plan feature became its own package,
retrieval became a seam a host injects, core's batteries moved one level down,
and the job state machine became a function. Breaking — this is 0.x, where a
minor may break — and every break is one import line or one call site.@orchestral/plan— the plan feature is one packageA plan used to be spread over three. The wire schema and
validatePlanwere in
@orchestral/core,planToMetain@orchestral/patterns,preflightPlanin
@orchestral/runtime. The primitive underneath all three — "read a$refoff a
step's input" — existed three times, with three depth rules and two head filters
between them, and two of the copies carried a comment asking a human to keep
them in step. What those comments guarded is the plan's central promise: the
string layer 1 validates is the string the interpreter substitutes and the
string preflight bills for. It is one function now, and the promise is a call
rather than a discipline. Core also sheds its largest file — a 1300-line wire
format validator that served exactly one Pattern.@orchestral/coreno longer exportsPlanDagSchema,PlanStepSchema,
PlanRetrySchema,PlanOutputSchema,PLAN_VALUE_REF_RE,
PLAN_ASSET_REF_RE,PLAN_STEP_ID_RE,validatePlan,assertPlanValid,
planRefine,PlanInvalidError, or thePlanDag/PlanStep/PlanRetry/
PlanOutput/PlanProblem/PlanProblemCode/PlanPatternLookup/
PlanValidateOptionstypes. Import them from@orchestral/plan; the shapes
are unchanged.@orchestral/runtimeno longer exportspreflightPlan,
formatPlanPreflight,PlanPreflightDeps,PlanPreflightReport,
PlanPreflightStep,PlanStepRoutingorPreflightAlternative. Import them
from@orchestral/planand add it to your dependencies. The signatures are
unchanged — includingdeps.resolveCtx, still the same provider you hand
InlineRuntimeInit.resolveCtxProvider.@orchestral/patternsno longer exportsplanToMeta,runPlan,
PLAN_TOOL_DESCRIPTION,PlanMetaPattern,PlanToMetaOptionsor
RunPlanOptions. Import them from@orchestral/plan. It keeps
createPlanMetaandPLAN_PATTERN_ID, because this package still ships
meta_plan— its manifest names that factory, and the id is a member of
FIRST_PARTY_PATTERN_IDS.meta. Both are re-exported from@orchestral/plan,
which this package depends on, so you get it transitively.
There is no deprecation cycle on any of these: the old names are gone, not
aliased, so a stale import fails at build time instead of resolving to a shim.One behaviour change, unreachable in a valid plan: the interpreter's dependency
walk used to have no depth limit while the other two capped at 64. All three cap
at 64 now, andvalidatePlan's rule 24 already refuses an input nested deeper
than that, so no plan that validates can tell the difference.Retrieval is a seam, so
find_patternis conditional@orchestral/runtimeno longer depends on@orchestral/discovery. Installing
the runtime no longer installs a search engine. Retrieval reaches an agent loop
throughInlineRuntimeInit.patternSearch, the fourth seam alongside
agentRunImpl,askUserandAgentAssetBridge.import { createPatternSearch, QUERY_SYNTAX_HINT } from '@orchestral/discovery' new InlineRuntime({ patternSearch: createPatternSearch(registry, { router }), catalogOptions: { querySyntaxHint: QUERY_SYNTAX_HINT }, })
- Without the seam, an agent loop gets no
find_patterndescriptor. Its
catalog is the always-load inline core plusdispatch_pattern(plus the finish
tool). A loop whoseloop.toolPatternIdsare allalways-loadis unaffected;
a loop that was meant to discover Patterns loses that ability until the host
adds the two lines above. FindPatternInputSchema.query'sdescribeno longer carries the query
mini-language (+term,select:,namespace:,<prefix>*, bare id) or the
tokenizer guidance. Core names the input contract; it stopped describing o...
v0.2.0
Minor Changes
-
b30b58b: Every meta in the shipped catalog now declares
MetaPattern.plannedDispatches— the pattern ids itscomposecan dispatch, readable before it runs. The seven hand-written pipelines and thevia-captionfallback joinmeta_plan, which already declared its step list:meta_script2video→text-generation,text-to-image,image-to-image,image-to-videometa_storyboard→text-generation,image-to-image,meta_image-best-of-nmeta_image-best-of-n→ theinnerPatternIdthe caller passed (text-to-imageorimage-to-image), plus theimage-to-textjudgemeta_ugc-testimonial→text-generation,text-to-speech,text-to-image,image-to-video,automatic-speech-recognitionmeta_explainer-short→text-generation,text-to-image,text-to-speechmeta_product-ad-short→text-generation,text-to-image,image-to-video,text-to-audiometa_product-photo-pack→text-generation,text-to-imagemeta_image-to-image-via-caption→image-to-text,text-to-image
Host ops (
concatVideos,addSubtitles,stillToVideo,addBackgroundAudio, …) are not dispatches and appear nowhere in these lists. No factory signature or return type changes.Minor rather than patch, because an agent host can see new refusals.
@orchestral/runtime's agent guard holds a declaring meta's inner ids to the calling loop'sloop.toolPatternIds— allowlist, blocklist and ancestor chain — before the child is submitted. A loop that lists a meta but not the patterns it is made of (meta_script2videowithouttext-to-image, say) now getsSUBAGENT_TOOL_OUT_OF_SCOPEup front, with the offending id invia, where the same call previously slipped past the guard and ran. What these metas dispatch has not changed; what changed is that they say so in time to be checked. The CHANGELOGs promise "pin~0.1for patch-only updates", and a behavioural tightening must not ride a patch.If an agent of yours dispatches one of these metas, widen its
loop.toolPatternIdsto include the ids above — granting the meta means granting what the meta is made of. Metas dispatched from a host, a chat turn, or another meta'scomposeare unaffected: the check lives on the agent-loop tool-call path and nowhere else.
v0.1.0
First public release of the @orchestral/* line — six packages, published
together and versioned together.
| Package | What it is |
|---|---|
@orchestral/core |
The vocabulary and contracts: Pattern / ModelCapability / Alternative, Job / JobStore / Runtime, the default capability router, the pattern registry. No execution engine, no provider SDK. |
@orchestral/runtime |
InlineRuntime, the in-process reference implementation of core's Runtime. |
@orchestral/patterns |
The first-party catalog: one atomic pattern per capability, plus meta pipelines with their prompts inlined. |
@orchestral/discovery |
Optional. The BM25 PatternSearchIndex and the find_pattern tool handler. |
@orchestral/agent |
Optional. The orchestrator agent pattern — a declaration; the tool loop is the AgentRunImpl you inject. |
@orchestral/adapters-ai-sdk |
Optional. Ready-made ModelCapability envelopes over a Vercel AI SDK model instance. |
This release predates changesets in this repo, so its notes are per-package
rather than one shared summary: each package's CHANGELOG.md carries its own
0.1.0 section describing the API it shipped with, and those are the detail
this page would otherwise only transcribe.
See README for the
three seams a host satisfies, and DESIGN.md
for what the library deliberately leaves out and why.