@rulvar/core 1.193.0 → 1.195.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2389,6 +2389,16 @@ type AgentEvents = {
2389
2389
  reason?: string;
2390
2390
  retryAfterMs?: number;
2391
2391
  willRetry: true;
2392
+ } | {
2393
+ type: "budget:exposure-wait";
2394
+ agentType: string;
2395
+ label?: string; /** The refused model ref. */
2396
+ model?: string; /** The refusal arithmetic, verbatim from the typed refusal. */
2397
+ capUsd?: number;
2398
+ spentUsd?: number;
2399
+ inFlightUsd?: number;
2400
+ estimateUsd?: number;
2401
+ willWait: boolean;
2392
2402
  } | {
2393
2403
  type: "agent:schema-retry";
2394
2404
  agentType: string;
@@ -5107,6 +5117,16 @@ interface BudgetHooks {
5107
5117
  */
5108
5118
  assertPricedDispatch?: (servedBy: ModelRef) => void;
5109
5119
  admitTurnExposure?: (servedBy: ModelRef, estimatedInputTokens: number, plannedOutputTokens: number) => (() => void) | undefined;
5120
+ /**
5121
+ * Parks until the next in-flight exposure hold releases (RV1902):
5122
+ * 'released' on that wake, 'drained' immediately when no hold is
5123
+ * live, 'aborted' when the signal fires first. Wired beside
5124
+ * admitTurnExposure when the cap is configured; consumed only by
5125
+ * invocations that opted into the exposure wait.
5126
+ */
5127
+ awaitExposureRelease?: (signal?: AbortSignal) => Promise<"released" | "drained" | "aborted">;
5128
+ /** Live in-flight exposure currently held by open dispatches (RV1902). */
5129
+ liveExposureUsd?: () => number;
5110
5130
  /** Live usage accounting; layer 3 may respond by aborting `signal`. */
5111
5131
  onUsage(usage: Usage, servedBy: ModelRef): void;
5112
5132
  /**
@@ -5391,6 +5411,15 @@ interface RunAgentOptions<S extends SchemaSpec = JsonSchema> {
5391
5411
  /** Host or sibling cancellation. */
5392
5412
  signal?: AbortSignal;
5393
5413
  budget?: BudgetHooks;
5414
+ /**
5415
+ * The exposure-wait posture (RV1902): an in-flight exposure refusal
5416
+ * on this invocation parks until a live hold releases and retries
5417
+ * pre-wire, instead of settling a budget error. Set only by the
5418
+ * orchestrate-owned root dispatches (the coordination loop, the
5419
+ * synthesis invocation, the forced-finish wake), whose settle would
5420
+ * tear down the run its own admitted children are still funding.
5421
+ */
5422
+ exposureWait?: boolean;
5394
5423
  events?: RuntimeEventSink;
5395
5424
  transcript?: {
5396
5425
  mintRef(): string;
@@ -6094,6 +6123,13 @@ declare class RunBudget {
6094
6123
  private exhaustedInternal;
6095
6124
  /** Live dispatch estimates held by reserveTurnExposure (RV711). */
6096
6125
  private inFlightExposureUsd;
6126
+ /**
6127
+ * Waiters parked on the next exposure release (RV1902): the
6128
+ * orchestrate root's dispatch waits out a transient refusal here
6129
+ * instead of settling a budget error. Notified (and self-removed)
6130
+ * on every hold release; never on spend, which only grows.
6131
+ */
6132
+ private readonly exposureWaiters;
6097
6133
  /** Models already warned about; the warning fires once per model per run. */
6098
6134
  private readonly unpricedWarned;
6099
6135
  /** Models whose price function already returned an invalid USD once. */
@@ -6308,6 +6344,19 @@ declare class RunBudget {
6308
6344
  * lifetime reserve and its own turn exposure would double-count.
6309
6345
  */
6310
6346
  reserveTurnExposure(servedBy: ModelRef, estimatedInputTokens: number, plannedOutputTokens: number): (() => void) | undefined;
6347
+ /** Live in-flight exposure currently held by open dispatches (RV1902). */
6348
+ get liveExposureUsd(): number;
6349
+ /**
6350
+ * Parks until the NEXT in-flight exposure hold releases (RV1902):
6351
+ * resolves 'released' on that wake, 'drained' immediately when no
6352
+ * hold is live (there is nothing to wait out, so the caller's refusal
6353
+ * is terminal for its turn), and 'aborted' when the signal fires
6354
+ * first. The waiter registers BEFORE any check, so a release racing
6355
+ * the caller's refusal is never lost; spend never shrinks, so
6356
+ * releases are the only wake source that can turn a refusal into a
6357
+ * fit.
6358
+ */
6359
+ awaitExposureRelease(signal?: AbortSignal): Promise<"released" | "drained" | "aborted">;
6311
6360
  /** Layer 2: the per-turn guard. A turn that would cross any ceiling in the chain is not dispatched. */
6312
6361
  beforeTurn(accountScope?: string): void;
6313
6362
  /**
@@ -7241,8 +7290,12 @@ interface RunOptions {
7241
7290
  * settles, and the dispatch whose estimate does not fit
7242
7291
  * spent + finalize/synthesis reserves + live estimates is refused
7243
7292
  * with a typed BudgetExhaustedError (data.reason
7244
- * 'in-flight-exposure') instead of waiting; the refused agent
7245
- * settles as a budget error. Worst concurrent overshoot past the cap
7293
+ * 'in-flight-exposure'). A plain agent settles the refusal as a
7294
+ * budget error; an orchestrate-owned root dispatch waits it out
7295
+ * (RV1902): it parks until a live hold releases, retries pre-wire,
7296
+ * and emits budget:exposure-wait, while a drained refusal settles
7297
+ * the documented forced-finish partial instead of tearing the run
7298
+ * down. Worst concurrent overshoot past the cap
7246
7299
  * is thereby the estimate error of the in-flight turns, not one
7247
7300
  * whole turn per agent. Absent by default: wire traffic, journals,
7248
7301
  * and hooks stay byte-identical. Recorded in RunMeta at genesis
@@ -9276,6 +9329,23 @@ interface OrchestrateOptions {
9276
9329
  /** The opt in child completion policy; see {@link OrchestrateAcceptance}. */
9277
9330
  acceptance?: OrchestrateAcceptance;
9278
9331
  /**
9332
+ * The terminal child barrier policy (RV1903, the four-role
9333
+ * benchmark's recovery arm): what happens to children still running
9334
+ * when the orchestration exits, on EVERY exit path (an accepted or
9335
+ * rejected finish, a typed failure, a budget or exposure terminal).
9336
+ * 'cancel' (the default) aborts them and awaits their journaled
9337
+ * cancelled terminals; 'drain' awaits their natural terminals,
9338
+ * bounded by their own limits and budgets, preserving their evidence
9339
+ * at the price of the wait. Either way the orchestration returns
9340
+ * only after every spawned child has a terminal journal entry, so
9341
+ * `run_settle` can never precede a child's billing row again: the
9342
+ * benchmark's recovery journal recorded three child terminals AFTER
9343
+ * the settle decision, and four mutually inconsistent cost views
9344
+ * followed. The verdict the run settled with is already frozen
9345
+ * before the barrier runs, so late children never change it.
9346
+ */
9347
+ onUnsettledAtExit?: "cancel" | "drain";
9348
+ /**
9279
9349
  * The opt in deterministic host validation of the finish result, with
9280
9350
  * bounded repair; see {@link FinishValidationSpec}.
9281
9351
  */
package/dist/index.js CHANGED
@@ -12308,10 +12308,33 @@ async function runAgent(options) {
12308
12308
  return dispatchWithQuota(options.quota);
12309
12309
  };
12310
12310
  let outcome;
12311
- try {
12312
- outcome = await (options.providerSlot === void 0 ? dispatch() : options.providerSlot(target.adapter.id, dispatch, options.signal));
12313
- } finally {
12314
- releaseExposure?.();
12311
+ for (;;) {
12312
+ try {
12313
+ outcome = await (options.providerSlot === void 0 ? dispatch() : options.providerSlot(target.adapter.id, dispatch, options.signal));
12314
+ } catch (thrown) {
12315
+ const refusalData = thrown instanceof BudgetExhaustedError ? thrown.data : void 0;
12316
+ const awaitRelease = options.budget?.awaitExposureRelease;
12317
+ if (options.exposureWait !== true || refusalData?.reason !== "in-flight-exposure" || awaitRelease === void 0) throw thrown;
12318
+ const willWait = (options.budget?.liveExposureUsd?.() ?? 0) > 0;
12319
+ events?.emit({
12320
+ type: "budget:exposure-wait",
12321
+ agentType,
12322
+ label: options.label,
12323
+ model: target.resolved.ref,
12324
+ ...typeof refusalData.capUsd === "number" ? { capUsd: refusalData.capUsd } : {},
12325
+ ...typeof refusalData.spentUsd === "number" ? { spentUsd: refusalData.spentUsd } : {},
12326
+ ...typeof refusalData.inFlightUsd === "number" ? { inFlightUsd: refusalData.inFlightUsd } : {},
12327
+ ...typeof refusalData.estimateUsd === "number" ? { estimateUsd: refusalData.estimateUsd } : {},
12328
+ willWait
12329
+ });
12330
+ if (!willWait) throw thrown;
12331
+ const waitSignals = [options.signal, options.budget?.signal].filter((candidate) => candidate !== void 0);
12332
+ await awaitRelease(waitSignals.length === 0 ? void 0 : AbortSignal.any(waitSignals));
12333
+ continue;
12334
+ } finally {
12335
+ releaseExposure?.();
12336
+ }
12337
+ break;
12315
12338
  }
12316
12339
  if (reservationId !== void 0 && options.quota !== void 0) {
12317
12340
  const rawWireCount = (outcome.providerMetadata?.[target.adapter.id])?.wireRequests?.count;
@@ -13445,6 +13468,13 @@ var RunBudget = class {
13445
13468
  exhaustedInternal = false;
13446
13469
  /** Live dispatch estimates held by reserveTurnExposure (RV711). */
13447
13470
  inFlightExposureUsd = 0;
13471
+ /**
13472
+ * Waiters parked on the next exposure release (RV1902): the
13473
+ * orchestrate root's dispatch waits out a transient refusal here
13474
+ * instead of settling a budget error. Notified (and self-removed)
13475
+ * on every hold release; never on spend, which only grows.
13476
+ */
13477
+ exposureWaiters = /* @__PURE__ */ new Set();
13448
13478
  /** Models already warned about; the warning fires once per model per run. */
13449
13479
  unpricedWarned = /* @__PURE__ */ new Set();
13450
13480
  /** Models whose price function already returned an invalid USD once. */
@@ -13862,8 +13892,42 @@ var RunBudget = class {
13862
13892
  if (released) return;
13863
13893
  released = true;
13864
13894
  this.inFlightExposureUsd = Math.max(0, this.inFlightExposureUsd - estimateUsd);
13895
+ for (const waiter of [...this.exposureWaiters]) waiter();
13865
13896
  };
13866
13897
  }
13898
+ /** Live in-flight exposure currently held by open dispatches (RV1902). */
13899
+ get liveExposureUsd() {
13900
+ return this.inFlightExposureUsd;
13901
+ }
13902
+ /**
13903
+ * Parks until the NEXT in-flight exposure hold releases (RV1902):
13904
+ * resolves 'released' on that wake, 'drained' immediately when no
13905
+ * hold is live (there is nothing to wait out, so the caller's refusal
13906
+ * is terminal for its turn), and 'aborted' when the signal fires
13907
+ * first. The waiter registers BEFORE any check, so a release racing
13908
+ * the caller's refusal is never lost; spend never shrinks, so
13909
+ * releases are the only wake source that can turn a refusal into a
13910
+ * fit.
13911
+ */
13912
+ awaitExposureRelease(signal) {
13913
+ if (signal?.aborted === true) return Promise.resolve("aborted");
13914
+ if (this.inFlightExposureUsd <= 0) return Promise.resolve("drained");
13915
+ return new Promise((resolve) => {
13916
+ const settle = (outcome) => {
13917
+ this.exposureWaiters.delete(waiter);
13918
+ signal?.removeEventListener("abort", onAbort);
13919
+ resolve(outcome);
13920
+ };
13921
+ const waiter = () => {
13922
+ settle("released");
13923
+ };
13924
+ const onAbort = () => {
13925
+ settle("aborted");
13926
+ };
13927
+ this.exposureWaiters.add(waiter);
13928
+ signal?.addEventListener("abort", onAbort, { once: true });
13929
+ });
13930
+ }
13867
13931
  /** Layer 2: the per-turn guard. A turn that would cross any ceiling in the chain is not dispatched. */
13868
13932
  beforeTurn(accountScope = "run") {
13869
13933
  for (const account of this.chainOf(accountScope)) if (account.ceilingUsd !== void 0 && account.spentUsd >= account.ceilingUsd) {
@@ -16270,6 +16334,19 @@ const kBootCheckpoint = Symbol("rulvar.bootCheckpoint");
16270
16334
  * attribution so the journal fold reproduces reserveUsedUsd.
16271
16335
  */
16272
16336
  const kFinalizeReserve = Symbol("rulvar.finalizeReserve");
16337
+ /**
16338
+ * Internal AgentOpts channel (RV1902): marks an orchestrate-owned root
16339
+ * dispatch (the coordination loop, the synthesis invocation, the
16340
+ * forced-finish wake) as one that WAITS OUT a transient in-flight
16341
+ * exposure refusal instead of settling a budget error. The four-role
16342
+ * benchmark's recovery arm died exactly there: the refusal is transient
16343
+ * by contract (budgets guide), but the refused agent was the workflow's
16344
+ * coordinating root, so its settle tore down the whole run while four
16345
+ * admitted children were still finalizing. Never part of the public
16346
+ * AgentOpts surface; plain agents keep the documented settle-as-budget-
16347
+ * error behavior, because their caller can catch and decide.
16348
+ */
16349
+ const kExposureWait = Symbol("rulvar.exposureWait");
16273
16350
  /** Typed accessor used by the in-package consumers. */
16274
16351
  function runtimeOf(ctx) {
16275
16352
  const runtime = ctxRuntimes.get(ctx);
@@ -17607,7 +17684,11 @@ function createCtx(internals, rootWorkflow) {
17607
17684
  maxAffordableOutputTokens: (servedBy, estimatedInputTokens) => internals.budget.maxAffordableOutputTokens(servedBy, estimatedInputTokens, budgetAccount),
17608
17685
  remainingUsd: () => internals.budget.remainingUsd(budgetAccount),
17609
17686
  ...internals.budget.strictPricing === void 0 ? {} : { assertPricedDispatch: (servedBy) => internals.budget.assertPricedDispatch(servedBy) },
17610
- ...internals.budget.maxInFlightExposureUsd === void 0 ? {} : { admitTurnExposure: (servedBy, estimatedInputTokens, plannedOutputTokens) => internals.budget.reserveTurnExposure(servedBy, estimatedInputTokens, plannedOutputTokens) },
17687
+ ...internals.budget.maxInFlightExposureUsd === void 0 ? {} : {
17688
+ admitTurnExposure: (servedBy, estimatedInputTokens, plannedOutputTokens) => internals.budget.reserveTurnExposure(servedBy, estimatedInputTokens, plannedOutputTokens),
17689
+ awaitExposureRelease: (signal) => internals.budget.awaitExposureRelease(signal),
17690
+ liveExposureUsd: () => internals.budget.liveExposureUsd
17691
+ },
17611
17692
  onUsage: (usage, servedBy) => internals.budget.onUsage(usage, servedBy, budgetAccount),
17612
17693
  openCallMeter: (servedBy) => internals.budget.openCallMeter(servedBy, budgetAccount),
17613
17694
  signal: budgetAccount === "run" ? internals.budget.signal : AbortSignal.any([internals.budget.signal, internals.budget.signalOf(budgetAccount)].filter((signal) => signal !== void 0))
@@ -17621,6 +17702,7 @@ function createCtx(internals, rootWorkflow) {
17621
17702
  if (escalation !== void 0) runAgentOptions.escalation = { minSpendUsd: escalation.minSpendUsd ?? 0 };
17622
17703
  const terminalTool = opts[kTerminalTool];
17623
17704
  if (terminalTool !== void 0) runAgentOptions.terminalTool = terminalTool;
17705
+ if (opts[kExposureWait] === true) runAgentOptions.exposureWait = true;
17624
17706
  runAgentOptions.checkpoint = checkpointPlumbing;
17625
17707
  if (opts.schema !== void 0) runAgentOptions.schema = opts.schema;
17626
17708
  if (canonicalSchema !== void 0) runAgentOptions.canonicalSchema = canonicalSchema;
@@ -20658,6 +20740,7 @@ function validateOrchestrateOptions(opts) {
20658
20740
  if (opts === void 0) return;
20659
20741
  if (opts.maxSpawns !== void 0) requireNonNegativeInteger(opts.maxSpawns, "orchestrate maxSpawns");
20660
20742
  if (opts.renderBudgetChars !== void 0) requireNonNegativeInteger(opts.renderBudgetChars, "orchestrate renderBudgetChars");
20743
+ if (opts.onUnsettledAtExit !== void 0 && opts.onUnsettledAtExit !== "cancel" && opts.onUnsettledAtExit !== "drain") throw new ConfigError(`orchestrate onUnsettledAtExit must be 'cancel' or 'drain'; got ${String(opts.onUnsettledAtExit)}`);
20661
20744
  if (opts.acceptance !== void 0) {
20662
20745
  const policy = opts.acceptance.childPolicy;
20663
20746
  const minSuccessful = typeof policy === "object" && policy !== null && !Array.isArray(policy) ? policy.minSuccessful : void 0;
@@ -20969,7 +21052,7 @@ function filterProfiles(registered, names) {
20969
21052
  */
20970
21053
  function makeOrchestratorWorkflow(goal, opts) {
20971
21054
  validateOrchestrateOptions(opts);
20972
- return defineWorkflow({ name: ORCHESTRATE_WORKFLOW_NAME }, async (ctx) => {
21055
+ const orchestrationBody = async (ctx, barrier) => {
20973
21056
  const runtime = runtimeOf(ctx);
20974
21057
  const { internals } = runtime;
20975
21058
  if (internals.admission === void 0) throw new ConfigError("orchestrate requires the engine run context (createEngine)");
@@ -21070,6 +21153,28 @@ function makeOrchestratorWorkflow(goal, opts) {
21070
21153
  const byOrdinal = /* @__PURE__ */ new Map();
21071
21154
  const rejectedByOrdinal = /* @__PURE__ */ new Map();
21072
21155
  /**
21156
+ * The terminal child barrier (RV1903): every exit of this
21157
+ * orchestration, returned or thrown, passes through the finally
21158
+ * below, so a child still running when the verdict froze reaches a
21159
+ * journaled terminal BEFORE the workflow settles. The benchmark's
21160
+ * recovery journal recorded run_settle at sequence 18 and three
21161
+ * child terminals at 19..21; the returned outcome, the terminal
21162
+ * invoice and the event snapshot all disagreed with the final
21163
+ * journal. 'cancel' (default) aborts the stragglers and awaits
21164
+ * their cancelled terminals; 'drain' awaits their natural
21165
+ * terminals, bounded by their own limits. The frozen verdict is
21166
+ * journaled before the barrier runs, so late children never change
21167
+ * it; result promises never reject (SpawnRecord contract), so the
21168
+ * barrier never masks the exit's own error.
21169
+ */
21170
+ const exitBarrier = async () => {
21171
+ const live = [...byOrdinal.values()].filter((record) => record.settled === void 0);
21172
+ if (live.length === 0) return;
21173
+ if ((opts?.onUnsettledAtExit ?? "cancel") === "cancel") for (const record of live) record.abort();
21174
+ await Promise.allSettled(live.map((record) => record.result));
21175
+ };
21176
+ barrier.run = exitBarrier;
21177
+ /**
21073
21178
  * The journaled spec behind each recovered ordinal: the idempotent
21074
21179
  * re-execution guard compares it against the incoming call, because
21075
21180
  * after a cross-attempt resume a REGENERATED turn (the boundary
@@ -22235,6 +22340,7 @@ function makeOrchestratorWorkflow(goal, opts) {
22235
22340
  role: "orchestrate",
22236
22341
  result: "full",
22237
22342
  tools,
22343
+ [kExposureWait]: true,
22238
22344
  ...capState === void 0 ? {} : { estCost: orchestratorAdmissionEstCostUsd(capState.effectiveCapUsd, orchestratorAccount === void 0 ? 0 : (internals.budget.accountView(orchestratorAccount)?.finalizeReserveUsd ?? 0) + (internals.budget.accountView(orchestratorAccount)?.synthesisReserveUsd ?? 0)) },
22239
22345
  ...opts?.model === void 0 ? {} : { model: opts.model },
22240
22346
  ...opts?.limits === void 0 ? {} : { limits: opts.limits },
@@ -22293,11 +22399,13 @@ function makeOrchestratorWorkflow(goal, opts) {
22293
22399
  const fallbackKey = deriverV2.deriveKey({ kind: "orchestrator-finalize-fallback" });
22294
22400
  const priorFallback = internals.replayer.snapshot().find((entry) => entry.kind === "decision" && entry.key === fallbackKey);
22295
22401
  const priorFinalize = internals.replayer.snapshot().filter((entry) => entry.kind === "agent" && entry.scope === callingState.scope && entry.seq > (capDecisionRef ?? -1) && entry.status !== "running" && entry.costAttribution?.finalizeReserve === true).at(-1);
22402
+ const finalizeTurns = capState?.finalizeTurns ?? 2;
22296
22403
  const finalOpts = {
22297
22404
  role: "orchestrate",
22298
22405
  result: "full",
22299
22406
  tools: finishOnly,
22300
- limits: { maxTurns: capState?.finalizeTurns ?? 2 },
22407
+ [kExposureWait]: true,
22408
+ limits: { maxTurns: finalizeTurns },
22301
22409
  ...capState === void 0 ? {} : { estCost: capState.finalizeReserveUsd },
22302
22410
  ...opts?.model === void 0 ? {} : { model: opts.model },
22303
22411
  [kTerminalTool]: {
@@ -23202,6 +23310,7 @@ function makeOrchestratorWorkflow(goal, opts) {
23202
23310
  role: "synthesize",
23203
23311
  result: "full",
23204
23312
  tools: synthesisTools,
23313
+ [kExposureWait]: true,
23205
23314
  limits: spec.limits ?? { maxTurns: 4 },
23206
23315
  ...spec.model === void 0 ? {} : { model: spec.model },
23207
23316
  ...spec.effort === void 0 ? {} : { effort: spec.effort },
@@ -23340,7 +23449,37 @@ function makeOrchestratorWorkflow(goal, opts) {
23340
23449
  ...finishValidationPromptLines(validationSpec, coordSectionalFinish ? "rejected-attempt" : void 0),
23341
23450
  ...acceptancePromptLines(opts?.acceptance)
23342
23451
  ];
23343
- const result = await runtime.runInScope(orchestratorState, () => ctx.agent(orchestratorPrompt(goal, opts?.maxSpawns, promptLines.length === 0 ? void 0 : promptLines), agentOpts));
23452
+ let result;
23453
+ try {
23454
+ result = await runtime.runInScope(orchestratorState, () => ctx.agent(orchestratorPrompt(goal, opts?.maxSpawns, promptLines.length === 0 ? void 0 : promptLines), agentOpts));
23455
+ } catch (thrown) {
23456
+ if (!(thrown instanceof BudgetExhaustedError) || thrown.data?.reason !== "in-flight-exposure") throw thrown;
23457
+ const exposureKey = deriverV2.deriveKey({ kind: "orchestrator-exposure-fallback" });
23458
+ if (!internals.replayer.snapshot().some((entry) => entry.kind === "decision" && entry.key === exposureKey)) await internals.replayer.appendSinglePhase({
23459
+ scope: callingState.scope,
23460
+ key: exposureKey,
23461
+ kind: "decision",
23462
+ status: "ok",
23463
+ spanId: internals.spans.mint(callingState.spanId),
23464
+ site: "orchestrator-budget",
23465
+ value: {
23466
+ decisionType: "orchestrator_finalize_fallback",
23467
+ reason: "exposure-abort",
23468
+ turnsUsed: 0,
23469
+ foldParams: {
23470
+ planHash: "",
23471
+ digestOrdinalMax: wakeOrdinal
23472
+ }
23473
+ }
23474
+ });
23475
+ internals.budget.markExhausted();
23476
+ return {
23477
+ forcedFinishFallback: true,
23478
+ completion: "partial",
23479
+ planHash: "",
23480
+ completed: [...byOrdinal.values()].filter((record) => record.settled !== void 0).sort((a, b) => a.spawnOrdinal - b.spawnOrdinal).map((record) => digestOf(record, record.settled))
23481
+ };
23482
+ }
23344
23483
  const liveTermination = extensionTermination;
23345
23484
  if (liveTermination !== void 0) throw liveTermination;
23346
23485
  if (capDecisionRef !== void 0) return await settleCapOutcome();
@@ -23594,6 +23733,14 @@ function makeOrchestratorWorkflow(goal, opts) {
23594
23733
  claimConsistencyMeta
23595
23734
  }
23596
23735
  };
23736
+ };
23737
+ return defineWorkflow({ name: ORCHESTRATE_WORKFLOW_NAME }, async (ctx) => {
23738
+ const barrier = {};
23739
+ try {
23740
+ return await orchestrationBody(ctx, barrier);
23741
+ } finally {
23742
+ await barrier.run?.();
23743
+ }
23597
23744
  });
23598
23745
  }
23599
23746
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.193.0",
3
+ "version": "1.195.0",
4
4
  "description": "Rulvar core: L0 contracts, journal kernel, ctx primitives, agent runtime, model router, tool system, dynamic orchestrator, InMemory and JSONL stores, event stream.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",