@rulvar/core 1.92.0 → 1.93.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
@@ -4110,6 +4110,24 @@ interface UsageLimits {
4110
4110
  costs?: Record<string, number>;
4111
4111
  };
4112
4112
  /**
4113
+ * The mid-batch checkpoint boundary (RV408, the eighth-experiment
4114
+ * review): checkpoints normally write once per COMPLETED tool turn,
4115
+ * so a kill inside one large parallel batch re-pays every executed
4116
+ * call of that batch on resume; with the whole executed-call budget
4117
+ * fitting into a single batch (the `tool-cap-before-checkpoint`
4118
+ * preflight warning), the re-paid window is the entire budget. Set to
4119
+ * K to bound it: after every K EXECUTED calls within a batch the loop
4120
+ * durably writes the same pending state the ask suspension already
4121
+ * checkpoints (the executed prefix verbatim, the next call, the
4122
+ * remaining tail), so a resume reuses the prefix and re-runs at most
4123
+ * the calls since the last boundary. Denied and skipped calls do not
4124
+ * advance the cadence, and the batch tail writes no extra boundary
4125
+ * (the turn checkpoint follows immediately). Off by default: the
4126
+ * boundary writes extra transcript blobs, and enabling it changes no
4127
+ * journal bytes and no model requests, only the checkpoint cadence.
4128
+ */
4129
+ checkpointEveryToolCalls?: number;
4130
+ /**
4113
4131
  * The guaranteed finalization turn (the experiment-review P1.1): when
4114
4132
  * a TOOL budget limiter (maxToolCalls or toolUnits) expires, the
4115
4133
  * runtime closes the current batch's remaining calls with explicit
@@ -4191,6 +4209,8 @@ interface EffectiveUsageLimits {
4191
4209
  max: number;
4192
4210
  costs?: Record<string, number>;
4193
4211
  };
4212
+ /** RV408 mid-batch checkpoint cadence; absent = per-turn only. */
4213
+ checkpointEveryToolCalls?: number;
4194
4214
  finalizationReserve?: {
4195
4215
  maxOutputTokens?: number;
4196
4216
  };
package/dist/index.js CHANGED
@@ -9122,6 +9122,8 @@ function mergeUsageLimits(call, profile, engine) {
9122
9122
  if (maxCallsPerTool !== void 0) merged.maxCallsPerTool = maxCallsPerTool;
9123
9123
  const toolUnits = pick("toolUnits");
9124
9124
  if (toolUnits !== void 0) merged.toolUnits = toolUnits;
9125
+ const checkpointEveryToolCalls = pick("checkpointEveryToolCalls");
9126
+ if (checkpointEveryToolCalls !== void 0) merged.checkpointEveryToolCalls = checkpointEveryToolCalls;
9125
9127
  const finalizationReserve = pick("finalizationReserve");
9126
9128
  if (finalizationReserve !== void 0) merged.finalizationReserve = finalizationReserve;
9127
9129
  const toolBudgetExtension = pick("toolBudgetExtension");
@@ -9167,6 +9169,7 @@ function validateUsageLimits(limits, site) {
9167
9169
  for (const [name, cost] of Object.entries(costs)) requireNonNegativeInteger(cost, `${site}.toolUnits.costs['${name}']`);
9168
9170
  }
9169
9171
  }
9172
+ if (limits.checkpointEveryToolCalls !== void 0) requirePositiveInteger(limits.checkpointEveryToolCalls, `${site}.checkpointEveryToolCalls`);
9170
9173
  if (limits.finalizationReserve !== void 0) {
9171
9174
  const reserve = limits.finalizationReserve;
9172
9175
  if (typeof reserve !== "object" || reserve === null || Array.isArray(reserve)) throw new ConfigError(`${site}.finalizationReserve must be { maxOutputTokens? }`);
@@ -11068,6 +11071,7 @@ async function runAgent(options) {
11068
11071
  }));
11069
11072
  };
11070
11073
  let terminalAdmitted = false;
11074
+ let executedSinceBoundary = 0;
11071
11075
  for (const [index, call] of calls.entries()) {
11072
11076
  const expiryOf = () => {
11073
11077
  const cap = effectiveMaxToolCalls();
@@ -11319,6 +11323,21 @@ async function runAgent(options) {
11319
11323
  guardTrip: true
11320
11324
  };
11321
11325
  }
11326
+ executedSinceBoundary += 1;
11327
+ const boundaryCadence = limits.checkpointEveryToolCalls;
11328
+ const next = calls[index + 1];
11329
+ if (boundaryCadence !== void 0 && executedSinceBoundary >= boundaryCadence && next !== void 0) {
11330
+ executedSinceBoundary = 0;
11331
+ await saveBoundary({
11332
+ executed: toPendingRecords(parts),
11333
+ awaiting: {
11334
+ id: next.id,
11335
+ name: next.name,
11336
+ args: next.args
11337
+ },
11338
+ remaining: calls.slice(index + 2)
11339
+ });
11340
+ }
11322
11341
  }
11323
11342
  maybeMarkWindowEntry();
11324
11343
  return {
@@ -18767,10 +18786,10 @@ function preflightEstimate(input) {
18767
18786
  spawn: label
18768
18787
  });
18769
18788
  }
18770
- if (executedToolCallCeiling !== null && executedToolCallCeiling > 0 && caps?.supportsParallelTools === true) say({
18789
+ if (executedToolCallCeiling !== null && executedToolCallCeiling > 0 && caps?.supportsParallelTools === true && (limits.checkpointEveryToolCalls === void 0 || limits.checkpointEveryToolCalls >= executedToolCallCeiling)) say({
18771
18790
  severity: "warning",
18772
18791
  code: "tool-cap-before-checkpoint",
18773
- message: `spawn '${label}': the whole executed-call budget (${String(executedToolCallCeiling)} calls) fits into one parallel tool batch, and checkpoints write once per completed tool turn: the cap can be reached before any checkpoint exists, and a kill mid-batch re-pays every executed call on resume`,
18792
+ message: `spawn '${label}': the whole executed-call budget (${String(executedToolCallCeiling)} calls) fits into one parallel tool batch, and checkpoints write once per completed tool turn: the cap can be reached before any checkpoint exists, and a kill mid-batch re-pays every executed call on resume; bound the window with limits.checkpointEveryToolCalls (RV408)`,
18774
18793
  spawn: label
18775
18794
  });
18776
18795
  if (limits.toolBudgetExtension !== void 0) if (limits.maxToolCalls === void 0) say({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/core",
3
- "version": "1.92.0",
3
+ "version": "1.93.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",