@rulvar/core 1.28.0 → 1.29.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 +10 -5
- package/dist/index.js +94 -11
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2465,11 +2465,16 @@ declare const DEFAULT_RETRY_POLICY: RetryPolicy;
|
|
|
2465
2465
|
*/
|
|
2466
2466
|
declare function retryClassOf(error: WireError): RetryClass | undefined;
|
|
2467
2467
|
/**
|
|
2468
|
-
* The delay before retry number `retryIndex` (
|
|
2469
|
-
* the first failed attempt has index 0). A provider
|
|
2470
|
-
* retryAfterMs
|
|
2471
|
-
*
|
|
2472
|
-
*
|
|
2468
|
+
* The delay before retry number `retryIndex` (zero based: the delay
|
|
2469
|
+
* after the first failed attempt has index 0). A VALID provider
|
|
2470
|
+
* supplied retryAfterMs (finite and nonnegative) REPLACES the
|
|
2471
|
+
* computed delay (Appendix A); anything else (NaN, Infinity, a
|
|
2472
|
+
* negative) is ignored as adapter noise and the policy backoff
|
|
2473
|
+
* applies, so this boundary stays defensive against custom adapters
|
|
2474
|
+
* (v1.28.0 review P2). Jitter is equal jitter: half the backoff is
|
|
2475
|
+
* deterministic, half random, so a jittered delay never collapses to
|
|
2476
|
+
* zero. The result is always a finite nonnegative integer clamped to
|
|
2477
|
+
* the Node timer maximum (2147483647 ms).
|
|
2473
2478
|
*/
|
|
2474
2479
|
declare function retryDelayMs(policy: RetryPolicy, retryIndex: number, retryAfterMs?: number, random?: () => number): number;
|
|
2475
2480
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -7033,18 +7033,35 @@ function retryClassOf(error) {
|
|
|
7033
7033
|
return "transport";
|
|
7034
7034
|
}
|
|
7035
7035
|
/**
|
|
7036
|
-
* The delay
|
|
7037
|
-
*
|
|
7038
|
-
*
|
|
7039
|
-
*
|
|
7040
|
-
|
|
7036
|
+
* The largest delay a Node timer represents exactly (2^31 above that
|
|
7037
|
+
* a timer overflows and fires almost immediately); every returned
|
|
7038
|
+
* delay is clamped to it so a huge provider value can never turn
|
|
7039
|
+
* into an instant retry storm.
|
|
7040
|
+
*/
|
|
7041
|
+
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
7042
|
+
/** Bounds a delay to a finite nonnegative integer a Node timer can honor. */
|
|
7043
|
+
function timerSafe(ms) {
|
|
7044
|
+
if (!Number.isFinite(ms) || ms <= 0) return 0;
|
|
7045
|
+
return Math.min(Math.round(ms), MAX_TIMER_DELAY_MS);
|
|
7046
|
+
}
|
|
7047
|
+
/**
|
|
7048
|
+
* The delay before retry number `retryIndex` (zero based: the delay
|
|
7049
|
+
* after the first failed attempt has index 0). A VALID provider
|
|
7050
|
+
* supplied retryAfterMs (finite and nonnegative) REPLACES the
|
|
7051
|
+
* computed delay (Appendix A); anything else (NaN, Infinity, a
|
|
7052
|
+
* negative) is ignored as adapter noise and the policy backoff
|
|
7053
|
+
* applies, so this boundary stays defensive against custom adapters
|
|
7054
|
+
* (v1.28.0 review P2). Jitter is equal jitter: half the backoff is
|
|
7055
|
+
* deterministic, half random, so a jittered delay never collapses to
|
|
7056
|
+
* zero. The result is always a finite nonnegative integer clamped to
|
|
7057
|
+
* the Node timer maximum (2147483647 ms).
|
|
7041
7058
|
*/
|
|
7042
7059
|
function retryDelayMs(policy, retryIndex, retryAfterMs, random = nativeRandom) {
|
|
7043
|
-
if (retryAfterMs !== void 0) return retryAfterMs;
|
|
7060
|
+
if (retryAfterMs !== void 0 && Number.isFinite(retryAfterMs) && retryAfterMs >= 0) return timerSafe(retryAfterMs);
|
|
7044
7061
|
const { initialMs, factor, maxMs, jitter } = policy.backoff;
|
|
7045
7062
|
const base = Math.min(maxMs, initialMs * factor ** retryIndex);
|
|
7046
|
-
if (jitter !== true) return base;
|
|
7047
|
-
return base / 2 + random() * (base / 2);
|
|
7063
|
+
if (jitter !== true) return timerSafe(base);
|
|
7064
|
+
return timerSafe(base / 2 + random() * (base / 2));
|
|
7048
7065
|
}
|
|
7049
7066
|
//#endregion
|
|
7050
7067
|
//#region src/model/roles.ts
|
|
@@ -8623,14 +8640,70 @@ async function runAgent(options) {
|
|
|
8623
8640
|
};
|
|
8624
8641
|
const retryPolicy = options.retry?.policy ?? DEFAULT_RETRY_POLICY;
|
|
8625
8642
|
const retryOn = retryPolicy.retryOn ?? DEFAULT_RETRY_POLICY.retryOn ?? [];
|
|
8626
|
-
const
|
|
8643
|
+
const injectedSleep = options.retry?.sleep;
|
|
8627
8644
|
const retryRandom = options.retry?.random ?? Math.random;
|
|
8645
|
+
const abortKind = () => options.budget?.signal?.aborted === true ? "budget" : options.signal?.aborted === true ? "external" : void 0;
|
|
8646
|
+
const abortedOutcome = (aborted) => ({
|
|
8647
|
+
turn: {
|
|
8648
|
+
text: "",
|
|
8649
|
+
toolCalls: []
|
|
8650
|
+
},
|
|
8651
|
+
usage: ZERO_USAGE$1,
|
|
8652
|
+
reported: ZERO_USAGE$1,
|
|
8653
|
+
usageApprox: true,
|
|
8654
|
+
aborted
|
|
8655
|
+
});
|
|
8656
|
+
const backoffWait = async (ms) => {
|
|
8657
|
+
const signals = [];
|
|
8658
|
+
if (options.signal !== void 0) signals.push(options.signal);
|
|
8659
|
+
if (options.budget?.signal !== void 0) signals.push(options.budget.signal);
|
|
8660
|
+
const combined = signals.length === 0 ? void 0 : AbortSignal.any(signals);
|
|
8661
|
+
if (combined?.aborted === true) return;
|
|
8662
|
+
if (injectedSleep === void 0) {
|
|
8663
|
+
await new Promise((resolve) => {
|
|
8664
|
+
let unhook = () => {};
|
|
8665
|
+
const timer = setTimeout(() => {
|
|
8666
|
+
unhook();
|
|
8667
|
+
resolve();
|
|
8668
|
+
}, ms);
|
|
8669
|
+
if (combined !== void 0) {
|
|
8670
|
+
const onAbort = () => {
|
|
8671
|
+
clearTimeout(timer);
|
|
8672
|
+
resolve();
|
|
8673
|
+
};
|
|
8674
|
+
combined.addEventListener("abort", onAbort, { once: true });
|
|
8675
|
+
unhook = () => combined.removeEventListener("abort", onAbort);
|
|
8676
|
+
}
|
|
8677
|
+
});
|
|
8678
|
+
return;
|
|
8679
|
+
}
|
|
8680
|
+
const sleep = Promise.resolve(injectedSleep(ms));
|
|
8681
|
+
if (combined === void 0) {
|
|
8682
|
+
await sleep;
|
|
8683
|
+
return;
|
|
8684
|
+
}
|
|
8685
|
+
let unhook;
|
|
8686
|
+
const wake = new Promise((resolve) => {
|
|
8687
|
+
const onAbort = () => resolve();
|
|
8688
|
+
combined.addEventListener("abort", onAbort, { once: true });
|
|
8689
|
+
unhook = () => combined.removeEventListener("abort", onAbort);
|
|
8690
|
+
});
|
|
8691
|
+
try {
|
|
8692
|
+
await Promise.race([sleep, wake]);
|
|
8693
|
+
} finally {
|
|
8694
|
+
unhook?.();
|
|
8695
|
+
sleep.catch(() => void 0);
|
|
8696
|
+
}
|
|
8697
|
+
};
|
|
8628
8698
|
const dispatchPhase = async (site) => {
|
|
8629
8699
|
for (;;) {
|
|
8630
8700
|
const target = site.chain[site.cursor.index] ?? site.chain[0];
|
|
8631
8701
|
let tries = 0;
|
|
8632
8702
|
inner: for (;;) {
|
|
8633
|
-
const dispatch = () =>
|
|
8703
|
+
const dispatch = () => {
|
|
8704
|
+
const aborted = abortKind();
|
|
8705
|
+
return aborted === void 0 ? streamTurn(target.adapter, site.requestFor(target), site.streamOptionsFor(target)) : Promise.resolve(abortedOutcome(aborted));
|
|
8706
|
+
};
|
|
8634
8707
|
const outcome = await (options.providerSlot === void 0 ? dispatch() : options.providerSlot(target.adapter.id, dispatch));
|
|
8635
8708
|
recordUsage(outcome.usage, outcome.reported, target.adapter.id, target.resolved.ref, site.role, outcome.usageViolation);
|
|
8636
8709
|
tries += 1;
|
|
@@ -8641,6 +8714,11 @@ async function runAgent(options) {
|
|
|
8641
8714
|
};
|
|
8642
8715
|
usageApprox = usageApprox || outcome.usageApprox;
|
|
8643
8716
|
if (retryOn.includes(retryClass) && tries < retryPolicy.attempts) {
|
|
8717
|
+
const abortedBefore = abortKind();
|
|
8718
|
+
if (abortedBefore !== void 0) return {
|
|
8719
|
+
outcome: abortedOutcome(abortedBefore),
|
|
8720
|
+
target
|
|
8721
|
+
};
|
|
8644
8722
|
const retryAfter = (outcome.wireError?.data)?.retryAfterMs;
|
|
8645
8723
|
if (outcome.wireError !== void 0) events?.emit({
|
|
8646
8724
|
type: "agent:error",
|
|
@@ -8649,7 +8727,12 @@ async function runAgent(options) {
|
|
|
8649
8727
|
error: outcome.wireError,
|
|
8650
8728
|
willRetry: true
|
|
8651
8729
|
});
|
|
8652
|
-
await
|
|
8730
|
+
await backoffWait(retryDelayMs(retryPolicy, tries - 1, typeof retryAfter === "number" ? retryAfter : void 0, retryRandom));
|
|
8731
|
+
const abortedAfter = abortKind();
|
|
8732
|
+
if (abortedAfter !== void 0) return {
|
|
8733
|
+
outcome: abortedOutcome(abortedAfter),
|
|
8734
|
+
target
|
|
8735
|
+
};
|
|
8653
8736
|
continue inner;
|
|
8654
8737
|
}
|
|
8655
8738
|
const trigger = failoverTriggerOf(retryClass);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.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",
|