@rulvar/core 1.70.0 → 1.71.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 +24 -1
- package/dist/index.js +99 -4
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -8646,6 +8646,15 @@ interface PreflightSpawnReport {
|
|
|
8646
8646
|
turnFloorUsd?: number;
|
|
8647
8647
|
/** Executed-call ceiling across any tool mix; null = unlimited. */
|
|
8648
8648
|
executedToolCallCeiling: number | null;
|
|
8649
|
+
/**
|
|
8650
|
+
* The provider-call ceiling of ONE spawn's whole loop: maxTurns
|
|
8651
|
+
* bounded by the executed-call ceiling plus its final no-tool turn,
|
|
8652
|
+
* plus the finalization summary turn when a tool budget limiter arms
|
|
8653
|
+
* it. Every provider turn is one wire request and one quota
|
|
8654
|
+
* reservation, so this is the per-spawn multiplier of quota demand;
|
|
8655
|
+
* retries sit on top of it.
|
|
8656
|
+
*/
|
|
8657
|
+
projectedProviderTurns: number;
|
|
8649
8658
|
/** Per-tool ceilings for every tool a cap or a unit cost names. */
|
|
8650
8659
|
toolCeilings: PreflightToolCeiling[];
|
|
8651
8660
|
}
|
|
@@ -8672,7 +8681,8 @@ interface PreflightReport {
|
|
|
8672
8681
|
/** min(capUsd, (capFraction ?? 0.2) x ceiling); absent when unresolvable. */effectiveCapUsd?: number;
|
|
8673
8682
|
finalizeReserveUsd: number;
|
|
8674
8683
|
finalizeTurns: number; /** Whether the finalize reserve is committed against the run root (extension runs). */
|
|
8675
|
-
reserveCommitted: boolean;
|
|
8684
|
+
reserveCommitted: boolean; /** The orchestrator agent's own loop ceiling, derived exactly like a spawn's. */
|
|
8685
|
+
projectedProviderTurns: number;
|
|
8676
8686
|
};
|
|
8677
8687
|
};
|
|
8678
8688
|
quota: {
|
|
@@ -8704,6 +8714,19 @@ interface PreflightReport {
|
|
|
8704
8714
|
requestsPerWave: number;
|
|
8705
8715
|
tokensPerWaveFloor: number;
|
|
8706
8716
|
}>;
|
|
8717
|
+
/**
|
|
8718
|
+
* The declared wave run to its derived turn ceilings, at the
|
|
8719
|
+
* declared estimates (the second experiment report, rec 9): total
|
|
8720
|
+
* provider calls (fan-out times per-spawn projected turns, before
|
|
8721
|
+
* any retries) and the cumulative token demand with the context
|
|
8722
|
+
* regrowing every turn (turn k re-sends the declared prompt plus
|
|
8723
|
+
* the k-1 prior output bounds, so K turns cost K x est +
|
|
8724
|
+
* outputBound x K(K+1)/2). Absent when nothing is declared.
|
|
8725
|
+
*/
|
|
8726
|
+
runCeiling?: {
|
|
8727
|
+
requests: number;
|
|
8728
|
+
tokens: number;
|
|
8729
|
+
};
|
|
8707
8730
|
};
|
|
8708
8731
|
findings: PreflightFinding[];
|
|
8709
8732
|
}
|
package/dist/index.js
CHANGED
|
@@ -16722,6 +16722,30 @@ function orchestrate(engine, goal, opts, runOptions) {
|
|
|
16722
16722
|
}
|
|
16723
16723
|
//#endregion
|
|
16724
16724
|
//#region src/engine/preflight.ts
|
|
16725
|
+
/**
|
|
16726
|
+
* The overall executed-call ceiling across any tool mix: the cheapest
|
|
16727
|
+
* single-tool strategy bounds it from above; maxToolCalls bounds it
|
|
16728
|
+
* regardless of mix. A free tool (unit cost 0) lifts the units bound
|
|
16729
|
+
* entirely for calls of that tool.
|
|
16730
|
+
*/
|
|
16731
|
+
function overallExecutedCeiling(limits, toolCeilings) {
|
|
16732
|
+
const overall = toolCeilings.reduce((best, row) => row.ceiling === null ? best : best === null ? row.ceiling : Math.max(best, row.ceiling), null);
|
|
16733
|
+
return limits.maxToolCalls !== void 0 && (overall === null || limits.maxToolCalls < overall) ? limits.maxToolCalls : overall;
|
|
16734
|
+
}
|
|
16735
|
+
/**
|
|
16736
|
+
* The provider-call ceiling of one whole loop: maxTurns bounded by the
|
|
16737
|
+
* executed-call ceiling plus the final no-tool turn, plus the
|
|
16738
|
+
* finalization summary turn when a tool budget limiter arms it.
|
|
16739
|
+
*/
|
|
16740
|
+
function projectedProviderTurnsOf(limits, executedToolCallCeiling) {
|
|
16741
|
+
const toolBound = executedToolCallCeiling === null ? void 0 : executedToolCallCeiling + 1;
|
|
16742
|
+
const finalizeTurn = limits.finalizationReserve !== void 0 && (limits.maxToolCalls !== void 0 || limits.toolUnits !== void 0) ? 1 : 0;
|
|
16743
|
+
return (toolBound === void 0 ? limits.maxTurns : Math.min(limits.maxTurns, toolBound)) + finalizeTurn;
|
|
16744
|
+
}
|
|
16745
|
+
/** Cumulative token demand of one whole loop at the declared estimates. */
|
|
16746
|
+
function shapeRunTokens(shape) {
|
|
16747
|
+
return shape.turns * shape.inputFloor + shape.outputBound * shape.turns * (shape.turns + 1) / 2;
|
|
16748
|
+
}
|
|
16725
16749
|
const ANY_TOOL = "(any)";
|
|
16726
16750
|
function resolveServing(spec) {
|
|
16727
16751
|
if (spec === void 0) return;
|
|
@@ -16828,11 +16852,13 @@ function preflightEstimate(input) {
|
|
|
16828
16852
|
const finalizeReserveUsd = spec?.finalizeReserveUsd ?? finalizeTurns * flatReserveUsd;
|
|
16829
16853
|
const reserveCommitted = input.orchestrator.extension === true;
|
|
16830
16854
|
if (reserveCommitted) reservedForFinalizationUsd = finalizeReserveUsd;
|
|
16855
|
+
const echoLimits = mergeUsageLimits(input.orchestrator.limits, void 0, defaults.limits);
|
|
16831
16856
|
orchestratorEcho = {
|
|
16832
16857
|
...effectiveCapUsd === void 0 ? {} : { effectiveCapUsd },
|
|
16833
16858
|
finalizeReserveUsd,
|
|
16834
16859
|
finalizeTurns,
|
|
16835
|
-
reserveCommitted
|
|
16860
|
+
reserveCommitted,
|
|
16861
|
+
projectedProviderTurns: projectedProviderTurnsOf(echoLimits, overallExecutedCeiling(echoLimits, toolCeilingsOf(echoLimits)))
|
|
16836
16862
|
};
|
|
16837
16863
|
if (spec?.capUsd !== void 0 && spec.capFraction === void 0 && effectiveCapUsd !== void 0 && effectiveCapUsd < spec.capUsd) say({
|
|
16838
16864
|
severity: "warning",
|
|
@@ -16856,6 +16882,7 @@ function preflightEstimate(input) {
|
|
|
16856
16882
|
*/
|
|
16857
16883
|
const waveGateInputs = [];
|
|
16858
16884
|
const units = [];
|
|
16885
|
+
const shapes = [];
|
|
16859
16886
|
for (const spec of spawnSpecs) {
|
|
16860
16887
|
const role = spec.role ?? "loop";
|
|
16861
16888
|
const label = spec.label ?? role;
|
|
@@ -16908,8 +16935,8 @@ function preflightEstimate(input) {
|
|
|
16908
16935
|
cacheWriteTokens: 0
|
|
16909
16936
|
});
|
|
16910
16937
|
const toolCeilings = toolCeilingsOf(limits);
|
|
16911
|
-
const
|
|
16912
|
-
const
|
|
16938
|
+
const executedToolCallCeiling = overallExecutedCeiling(limits, toolCeilings);
|
|
16939
|
+
const projectedProviderTurns = projectedProviderTurnsOf(limits, executedToolCallCeiling);
|
|
16913
16940
|
for (const row of toolCeilings) {
|
|
16914
16941
|
if (row.tool === ANY_TOOL) continue;
|
|
16915
16942
|
const cost = limits.toolUnits?.costs?.[row.tool];
|
|
@@ -16976,6 +17003,7 @@ function preflightEstimate(input) {
|
|
|
16976
17003
|
...outputBound === void 0 ? {} : { maxOutputTokensPerTurn: outputBound },
|
|
16977
17004
|
...turnFloorUsd === void 0 ? {} : { turnFloorUsd },
|
|
16978
17005
|
executedToolCallCeiling,
|
|
17006
|
+
projectedProviderTurns,
|
|
16979
17007
|
toolCeilings
|
|
16980
17008
|
});
|
|
16981
17009
|
{
|
|
@@ -16998,6 +17026,21 @@ function preflightEstimate(input) {
|
|
|
16998
17026
|
if (turnFloorUsd !== void 0) unit.turnFloorUsd = turnFloorUsd;
|
|
16999
17027
|
units.push(unit);
|
|
17000
17028
|
}
|
|
17029
|
+
{
|
|
17030
|
+
const shape = {
|
|
17031
|
+
label,
|
|
17032
|
+
inputFloor: spec.estInputTokens ?? 0,
|
|
17033
|
+
outputBound: outputBound ?? 0,
|
|
17034
|
+
turns: projectedProviderTurns,
|
|
17035
|
+
count
|
|
17036
|
+
};
|
|
17037
|
+
if (servedBy !== void 0) {
|
|
17038
|
+
const { adapterId, model } = parseModelRef(servedBy);
|
|
17039
|
+
shape.provider = adapterId;
|
|
17040
|
+
shape.model = model;
|
|
17041
|
+
}
|
|
17042
|
+
shapes.push(shape);
|
|
17043
|
+
}
|
|
17001
17044
|
}
|
|
17002
17045
|
let orchestratorReserveUsd;
|
|
17003
17046
|
if (input.orchestrator !== void 0) {
|
|
@@ -17027,6 +17070,15 @@ function preflightEstimate(input) {
|
|
|
17027
17070
|
cacheWriteTokens: 0
|
|
17028
17071
|
});
|
|
17029
17072
|
units.push(unit);
|
|
17073
|
+
shapes.push({
|
|
17074
|
+
label: "orchestrator",
|
|
17075
|
+
provider: adapterId,
|
|
17076
|
+
model,
|
|
17077
|
+
inputFloor: input.orchestrator.estInputTokens ?? 0,
|
|
17078
|
+
outputBound: outputBound ?? 0,
|
|
17079
|
+
turns: projectedProviderTurnsOf(orchLimits, overallExecutedCeiling(orchLimits, toolCeilingsOf(orchLimits))),
|
|
17080
|
+
count: 1
|
|
17081
|
+
});
|
|
17030
17082
|
if (effectiveCapUsd !== void 0) orchestratorReserveUsd = Math.max(0, orchestratorAdmissionEstCostUsd(effectiveCapUsd, reservedForFinalizationUsd));
|
|
17031
17083
|
else if (pricing === void 0) orchestratorReserveUsd = 0;
|
|
17032
17084
|
else orchestratorReserveUsd = admissionReserveUsd({
|
|
@@ -17180,6 +17232,48 @@ function preflightEstimate(input) {
|
|
|
17180
17232
|
code: "quota-tokens-below-wave",
|
|
17181
17233
|
message: `${name}: the declared wave demands at least ${String(tokens)} tokens against tokensPerMinute ${String(rule.tokensPerMinute)}: expect estimate-driven throttling inside one window`
|
|
17182
17234
|
});
|
|
17235
|
+
let runRequests = 0;
|
|
17236
|
+
let runTokens = 0;
|
|
17237
|
+
for (const shape of shapes) {
|
|
17238
|
+
if (shape.provider === void 0 || shape.model === void 0) continue;
|
|
17239
|
+
if (!quotaRuleMatches(rule, {
|
|
17240
|
+
provider: shape.provider,
|
|
17241
|
+
model: shape.model,
|
|
17242
|
+
...engine.quota?.tenant === void 0 ? {} : { tenant: engine.quota.tenant },
|
|
17243
|
+
estimate: {
|
|
17244
|
+
requests: 1,
|
|
17245
|
+
inputTokens: 0
|
|
17246
|
+
}
|
|
17247
|
+
})) continue;
|
|
17248
|
+
runRequests += shape.count * shape.turns;
|
|
17249
|
+
runTokens += shape.count * shapeRunTokens(shape);
|
|
17250
|
+
if (rule.tokensPerMinute !== void 0 && shape.outputBound > 0) {
|
|
17251
|
+
const k = Math.max(1, Math.floor((rule.tokensPerMinute - shape.inputFloor) / shape.outputBound) + 1);
|
|
17252
|
+
if (k <= shape.turns) say({
|
|
17253
|
+
severity: "warning",
|
|
17254
|
+
code: "quota-turn-never-fits",
|
|
17255
|
+
message: `spawn '${shape.label}': by turn ${String(k)} of ${String(shape.turns)} the context-grown reservation (about ${String(shape.inputFloor + k * shape.outputBound)} tokens) exceeds ${name} tokensPerMinute ${String(rule.tokensPerMinute)} outright: the limiter denies it as never fitting the window (no wait helps) and the invocation fails after paying for the earlier turns`,
|
|
17256
|
+
spawn: shape.label
|
|
17257
|
+
});
|
|
17258
|
+
}
|
|
17259
|
+
}
|
|
17260
|
+
if (rule.requestsPerMinute !== void 0 && requests <= rule.requestsPerMinute && runRequests > rule.requestsPerMinute) say({
|
|
17261
|
+
severity: "warning",
|
|
17262
|
+
code: "quota-requests-below-run",
|
|
17263
|
+
message: `${name}: the declared wave fits ${String(requests)} dispatches under requestsPerMinute ${String(rule.requestsPerMinute)}, but run to its turn ceilings it projects up to ${String(runRequests)} provider calls (fan-out times per-spawn turns, before any retries): expect synthetic rate-limit denials and backoff across about ${String(Math.ceil(runRequests / rule.requestsPerMinute))} windows`
|
|
17264
|
+
});
|
|
17265
|
+
if (rule.tokensPerMinute !== void 0 && tokens <= rule.tokensPerMinute && runTokens > rule.tokensPerMinute) say({
|
|
17266
|
+
severity: "warning",
|
|
17267
|
+
code: "quota-tokens-below-run",
|
|
17268
|
+
message: `${name}: the declared wave demands ${String(tokens)} tokens up front, but with the context regrowing every turn its loops project about ${String(runTokens)} tokens against tokensPerMinute ${String(rule.tokensPerMinute)}: expect estimate-driven throttling across about ${String(Math.ceil(runTokens / rule.tokensPerMinute))} windows`
|
|
17269
|
+
});
|
|
17270
|
+
});
|
|
17271
|
+
const runCeiling = shapes.length === 0 ? void 0 : shapes.reduce((sum, shape) => ({
|
|
17272
|
+
requests: sum.requests + shape.count * shape.turns,
|
|
17273
|
+
tokens: sum.tokens + shape.count * shapeRunTokens(shape)
|
|
17274
|
+
}), {
|
|
17275
|
+
requests: 0,
|
|
17276
|
+
tokens: 0
|
|
17183
17277
|
});
|
|
17184
17278
|
const severityRank = {
|
|
17185
17279
|
error: 0,
|
|
@@ -17217,7 +17311,8 @@ function preflightEstimate(input) {
|
|
|
17217
17311
|
exposure: {
|
|
17218
17312
|
maxInFlight,
|
|
17219
17313
|
...overshootOneTurnFloorUsd === void 0 ? {} : { overshootOneTurnFloorUsd },
|
|
17220
|
-
perProvider
|
|
17314
|
+
perProvider,
|
|
17315
|
+
...runCeiling === void 0 ? {} : { runCeiling }
|
|
17221
17316
|
},
|
|
17222
17317
|
findings
|
|
17223
17318
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.71.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",
|