agents 0.28.1 → 0.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/{agent-routing-BMvWTFEp.d.ts → agent-routing-CDbpVjYq.d.ts} +7 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-ohoewW-B.d.ts → agent-tools-C8DH8Yii.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/{ai-ahruGw7e.d.ts → ai-iXw0uOGj.d.ts} +3 -3
- package/dist/{ai-sdk-C2iTAwUd.js → ai-sdk-DRPh2rRa.js} +185 -125
- package/dist/ai-sdk-DRPh2rRa.js.map +1 -0
- package/dist/browser/ai.d.ts +1 -1
- package/dist/browser/ai.js +2 -2
- package/dist/browser/index.d.ts +8 -8
- package/dist/browser/index.js +3 -3
- package/dist/browser/tools/ai-sdk.d.ts +2 -2
- package/dist/browser/tools/ai-sdk.js +1 -1
- package/dist/browser/tools/pi.d.ts +1 -1
- package/dist/browser/tools/pi.js +3 -3
- package/dist/browser/tools/pi.js.map +1 -1
- package/dist/browser/tools/tanstack-ai.d.ts +2 -2
- package/dist/browser/tools/tanstack-ai.js +1 -1
- package/dist/{browser-CEdNlsaD.js → browser-DccPw_wW.js} +130 -79
- package/dist/browser-DccPw_wW.js.map +1 -0
- package/dist/{browser-D30VlpcA.d.ts → browser-DlXhSAdf.d.ts} +41 -37
- package/dist/{browser-tool-4iomavs_.js → browser-tool-B1mhifin.js} +3 -3
- package/dist/{browser-tool-4iomavs_.js.map → browser-tool-B1mhifin.js.map} +1 -1
- package/dist/{browser-tool-vtrPOV8e.d.ts → browser-tool-Cxjk5sgG.d.ts} +2 -2
- package/dist/chat/index.d.ts +143 -71
- package/dist/chat/index.js +269 -110
- package/dist/chat/index.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +33 -33
- package/dist/{client-Bp-JwL3p.d.ts → client-C27CtRZr.d.ts} +2 -2
- package/dist/client.d.ts +1 -1
- package/dist/{connector-DEXzVoaY.d.ts → connector-20DJ6p4k.d.ts} +2 -2
- package/dist/{connector-CtZylXdk.js → connector-DAXBOIIi.js} +2 -2
- package/dist/{connector-CtZylXdk.js.map → connector-DAXBOIIi.js.map} +1 -1
- package/dist/experimental/channels/web/index.js +1 -1
- package/dist/harness/container/index.js +1 -1
- package/dist/harness/container/index.js.map +1 -1
- package/dist/harness/opencode/index.js +1 -1
- package/dist/harness/pi/index.d.ts +13 -5
- package/dist/harness/pi/index.js +8 -214
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/{images-C4hiIexM.js → images-xaDv2Fqe.js} +636 -168
- package/dist/images-xaDv2Fqe.js.map +1 -0
- package/dist/index-DCxk3OSJ.d.ts +378 -0
- package/dist/{index-kbSUIer3.d.ts → index-iv9FTXX9.d.ts} +80 -112
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{input-schema-xBofjBKC.js → input-schema-B0Etuo-o.js} +2 -2
- package/dist/{input-schema-xBofjBKC.js.map → input-schema-B0Etuo-o.js.map} +1 -1
- package/dist/lifecycle/index.js +1 -1
- package/dist/{lifecycle-DGorpAmA.js → lifecycle-ClT4DmF2.js} +11 -3
- package/dist/lifecycle-ClT4DmF2.js.map +1 -0
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +29 -352
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +25 -13
- package/dist/models/opencode/index.js +16 -11
- package/dist/models/opencode/index.js.map +1 -1
- package/dist/models/pi-ai/index.d.ts +13 -14
- package/dist/models/pi-ai/index.js +85 -32
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{session-store-DoPY12xM.d.ts → session-store-_IK6dV-w.d.ts} +14 -2
- package/dist/{session-store-Do4xkDcf.js → session-store-yvwq1f9x.js} +55 -2
- package/dist/session-store-yvwq1f9x.js.map +1 -0
- package/dist/{settings-BjAiPd6Z.js → settings-Dk2il2Hf.js} +4 -1
- package/dist/settings-Dk2il2Hf.js.map +1 -0
- package/dist/skills/index.d.ts +22 -28
- package/dist/skills/index.js +183 -143
- package/dist/skills/index.js.map +1 -1
- package/dist/{src-CQxJFv4l.js → src-6lr7MtM_.js} +3 -3
- package/dist/src-6lr7MtM_.js.map +1 -0
- package/dist/sub-routing.d.ts +1 -1
- package/dist/{tool-VF0qiO7q.js → tool-DkT_DJBm.js} +2 -2
- package/dist/tool-DkT_DJBm.js.map +1 -0
- package/dist/transport-CPh7YGiw.d.ts +623 -0
- package/dist/voice/index.d.ts +1 -1
- package/dist/web/fetch/tools/pi.js +2 -2
- package/dist/web/fetch/tools/pi.js.map +1 -1
- package/dist/web/search/index.js +1 -1
- package/dist/web/search/tools/ai-sdk.js +2 -2
- package/dist/web/search/tools/pi.js +3 -3
- package/dist/web/search/tools/pi.js.map +1 -1
- package/dist/web/search/tools/tanstack-ai.js +2 -2
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-C3zy8YR0.js → websockets-CqxnntmE.js} +2 -2
- package/dist/{websockets-C3zy8YR0.js.map → websockets-CqxnntmE.js.map} +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +1 -1
- package/docs/chat-agents.md +19 -18
- package/docs/harnesses/pi.md +47 -18
- package/docs/models-pi-ai.md +62 -20
- package/docs/models.md +197 -172
- package/package.json +7 -7
- package/dist/ai-sdk-C2iTAwUd.js.map +0 -1
- package/dist/browser-CEdNlsaD.js.map +0 -1
- package/dist/images-C4hiIexM.js.map +0 -1
- package/dist/lifecycle-DGorpAmA.js.map +0 -1
- package/dist/session-store-Do4xkDcf.js.map +0 -1
- package/dist/settings-BjAiPd6Z.js.map +0 -1
- package/dist/settings-DnD__xuE.d.ts +0 -349
- package/dist/src-CQxJFv4l.js.map +0 -1
- package/dist/tool-VF0qiO7q.js.map +0 -1
- package/dist/transport-DCyarnwm.d.ts +0 -200
package/dist/chat/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isPositionlessAgentToolChunk } from "../agent-tool-types.js";
|
|
2
|
+
import { i as _classPrivateFieldInitSpec, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
|
|
3
|
+
import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
|
|
2
4
|
import { isDurableObjectResetError, isPlatformFailure, tryN } from "../retries.js";
|
|
3
5
|
import { a as isReplayChunk, i as isLateToolInputChunk, n as applyLateToolInput, o as lateToolInputForwardChunks, r as getPartialStreamText, s as normalizeToolInput, t as applyChunkToParts } from "../message-builder-DAl9AhHH.js";
|
|
4
6
|
import { a as interceptAgentToolBroadcast, i as createAgentToolEventState, r as applyAgentToolEvent, s as storedChunkBytes, t as AgentToolProgressEmitter } from "../agent-tools-CdJC-8Dc.js";
|
|
@@ -3003,18 +3005,14 @@ const DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS = 10;
|
|
|
3003
3005
|
*/
|
|
3004
3006
|
const DEFAULT_CHAT_RECOVERY_MAX_WORK = 1e4;
|
|
3005
3007
|
/**
|
|
3006
|
-
*
|
|
3007
|
-
*
|
|
3008
|
-
*
|
|
3009
|
-
*
|
|
3010
|
-
*
|
|
3011
|
-
*
|
|
3012
|
-
* turn that one more attempt might have completed. Far tighter than the generic
|
|
3013
|
-
* `maxRecoveryWork` backstop because an OOM is attributable and re-running it is
|
|
3014
|
-
* expensive (it re-runs the model). Counts attempts that ended in an OOM, not
|
|
3015
|
-
* total attempts, so a turn interrupted by deploys (no OOM) is unaffected.
|
|
3008
|
+
* Default number of interrupted attempts a turn may accumulate before recovery
|
|
3009
|
+
* seals it with `reason="interrupted_attempts_exceeded"` (#2613). The original
|
|
3010
|
+
* turn counts, so a turn that dies every time runs the model at most five
|
|
3011
|
+
* times. A deterministic memory-limit reset dies every time; a deploy rarely
|
|
3012
|
+
* lands on the same turn five times in a row, so five tolerates churn while
|
|
3013
|
+
* still bounding a crash loop.
|
|
3016
3014
|
*/
|
|
3017
|
-
const
|
|
3015
|
+
const DEFAULT_CHAT_RECOVERY_MAX_INTERRUPTED_ATTEMPTS = 5;
|
|
3018
3016
|
const DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS = 1e4;
|
|
3019
3017
|
/**
|
|
3020
3018
|
* Delay before retrying a recovery that timed out waiting for stable state.
|
|
@@ -3061,12 +3059,25 @@ function resolveChatRecoveryConfig(raw) {
|
|
|
3061
3059
|
terminalMessage: custom?.terminalMessage ?? "The assistant was interrupted and could not recover. Please try again.",
|
|
3062
3060
|
noProgressTimeoutMs: Math.max(0, Math.floor(custom?.noProgressTimeoutMs ?? 3e5)),
|
|
3063
3061
|
maxRecoveryWork: typeof custom?.maxRecoveryWork === "number" && custom.maxRecoveryWork >= 0 ? custom.maxRecoveryWork : DEFAULT_CHAT_RECOVERY_MAX_WORK,
|
|
3064
|
-
|
|
3062
|
+
maxInterruptedAttempts: resolveMaxInterruptedAttempts(custom),
|
|
3065
3063
|
...custom?.shouldKeepRecovering ? { shouldKeepRecovering: custom.shouldKeepRecovering } : {},
|
|
3066
3064
|
...custom?.onExhausted ? { onExhausted: custom.onExhausted } : {}
|
|
3067
3065
|
};
|
|
3068
3066
|
}
|
|
3069
3067
|
/**
|
|
3068
|
+
* Read the interruption budget, honoring the deprecated `maxOomRetries` alias
|
|
3069
|
+
* as `maxOomRetries + 1` so an explicit retry count keeps its meaning. A
|
|
3070
|
+
* negative or non-numeric value falls back to the default; `Infinity` is kept
|
|
3071
|
+
* and disables the bound.
|
|
3072
|
+
*/
|
|
3073
|
+
function resolveMaxInterruptedAttempts(custom) {
|
|
3074
|
+
const attempts = custom?.maxInterruptedAttempts;
|
|
3075
|
+
if (typeof attempts === "number" && attempts >= 0) return Math.max(1, Math.floor(attempts));
|
|
3076
|
+
const legacyRetries = custom?.maxOomRetries;
|
|
3077
|
+
if (typeof legacyRetries === "number" && legacyRetries >= 0) return Math.floor(legacyRetries) + 1;
|
|
3078
|
+
return 5;
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3070
3081
|
* Stable identifier for a recovery incident.
|
|
3071
3082
|
*
|
|
3072
3083
|
* `recoveryKind` is intentionally NOT part of the identity: a single
|
|
@@ -3293,6 +3304,10 @@ async function setChatRecovering(active, requestId, deps) {
|
|
|
3293
3304
|
* no-progress alarm loop.
|
|
3294
3305
|
* - RUNAWAY — the work budget seals a loop that keeps emitting content but
|
|
3295
3306
|
* never converges. Keyed to WORK done, not wall-clock. Defaults to no cap.
|
|
3307
|
+
* - CRASH-LOOP — the interruption budget counts attempts whose isolate died
|
|
3308
|
+
* before they finished, and never resets on progress. The death is
|
|
3309
|
+
* counted by whoever starts the next attempt, because the isolate that
|
|
3310
|
+
* died cannot record anything (#2613).
|
|
3296
3311
|
* - CALLER — `shouldKeepRecovering` lets the integrator express a
|
|
3297
3312
|
* token/cost/step budget the SDK should not hardcode. Consulted only when no
|
|
3298
3313
|
* hard bound has already sealed the incident, and never on first detection.
|
|
@@ -3301,7 +3316,7 @@ async function setChatRecovering(active, requestId, deps) {
|
|
|
3301
3316
|
* suppressed and the no-progress clock kept fresh.
|
|
3302
3317
|
*/
|
|
3303
3318
|
async function evaluateChatRecoveryIncident(input) {
|
|
3304
|
-
const { identity, config, existing, currentProgress, awaitingClientInteraction, now } = input;
|
|
3319
|
+
const { identity, trigger, config, existing, currentProgress, awaitingClientInteraction, now } = input;
|
|
3305
3320
|
const incidentId = chatRecoveryIncidentId(identity);
|
|
3306
3321
|
const recoveryRootRequestId = identity.recoveryRootRequestId ?? identity.requestId;
|
|
3307
3322
|
const prevProgress = existing?.progress ?? 0;
|
|
@@ -3312,14 +3327,15 @@ async function evaluateChatRecoveryIncident(input) {
|
|
|
3312
3327
|
const progress = Math.max(prevProgress, currentProgress);
|
|
3313
3328
|
const work = progress - workBaseline;
|
|
3314
3329
|
const workBudgetExceeded = existing != null && Number.isFinite(config.maxRecoveryWork) && work > config.maxRecoveryWork;
|
|
3315
|
-
const
|
|
3316
|
-
const
|
|
3330
|
+
const newlyInterrupted = trigger.kind !== "interrupted" ? 0 : existing == null ? 1 : deadIsolateCount(existing.attemptsInFlight, trigger.attempt);
|
|
3331
|
+
const interruptedAttempts = (existing?.interruptedAttempts ?? 0) + newlyInterrupted;
|
|
3332
|
+
const interruptedBudgetExceeded = !awaitingClientInteraction && interruptedAttempts >= config.maxInterruptedAttempts;
|
|
3317
3333
|
const transientRetries = existing?.transientRetries ?? 0;
|
|
3318
3334
|
const transientBudgetExceeded = existing != null && !awaitingClientInteraction && transientRetries >= config.maxAttempts;
|
|
3319
3335
|
const debounced = existing != null && !madeProgress && now - existing.lastAttemptAt < 3e4;
|
|
3320
3336
|
const attempt = madeProgress ? 1 : debounced ? existing?.attempt ?? 1 : (existing?.attempt ?? 0) + 1;
|
|
3321
3337
|
let abortedByCaller = false;
|
|
3322
|
-
if (existing != null && !awaitingClientInteraction && config.shouldKeepRecovering && !noProgressExceeded && !workBudgetExceeded && !
|
|
3338
|
+
if (existing != null && !awaitingClientInteraction && config.shouldKeepRecovering && !noProgressExceeded && !workBudgetExceeded && !interruptedBudgetExceeded && !transientBudgetExceeded && attempt <= config.maxAttempts) try {
|
|
3323
3339
|
const ctx = {
|
|
3324
3340
|
incidentId,
|
|
3325
3341
|
requestId: identity.requestId,
|
|
@@ -3334,7 +3350,7 @@ async function evaluateChatRecoveryIncident(input) {
|
|
|
3334
3350
|
} catch (error) {
|
|
3335
3351
|
input.onShouldKeepRecoveringError?.(error);
|
|
3336
3352
|
}
|
|
3337
|
-
const exhausted = !awaitingClientInteraction && (
|
|
3353
|
+
const exhausted = !awaitingClientInteraction && (interruptedBudgetExceeded || noProgressExceeded || workBudgetExceeded || abortedByCaller || transientBudgetExceeded || attempt > config.maxAttempts);
|
|
3338
3354
|
const incident = {
|
|
3339
3355
|
incidentId,
|
|
3340
3356
|
requestId: identity.requestId,
|
|
@@ -3348,9 +3364,10 @@ async function evaluateChatRecoveryIncident(input) {
|
|
|
3348
3364
|
lastProgressAt,
|
|
3349
3365
|
progress,
|
|
3350
3366
|
workBaseline,
|
|
3351
|
-
...
|
|
3367
|
+
...interruptedAttempts > 0 ? { interruptedAttempts } : {},
|
|
3368
|
+
...attemptsInFlightAfter(trigger, existing, exhausted),
|
|
3352
3369
|
...transientRetries > 0 ? { transientRetries } : {},
|
|
3353
|
-
...exhausted ? { reason:
|
|
3370
|
+
...exhausted ? { reason: interruptedBudgetExceeded ? "interrupted_attempts_exceeded" : workBudgetExceeded ? "work_budget_exceeded" : noProgressExceeded ? "no_progress_timeout" : abortedByCaller ? "recovery_aborted" : "max_attempts_exceeded" } : {}
|
|
3354
3371
|
};
|
|
3355
3372
|
const events = [];
|
|
3356
3373
|
if (!existing) events.push({
|
|
@@ -3375,8 +3392,87 @@ async function evaluateChatRecoveryIncident(input) {
|
|
|
3375
3392
|
events
|
|
3376
3393
|
};
|
|
3377
3394
|
}
|
|
3395
|
+
/**
|
|
3396
|
+
* How many other isolates left attempts in `recorded`. Each such isolate died
|
|
3397
|
+
* mid-attempt once, however many attempts it was running.
|
|
3398
|
+
*/
|
|
3399
|
+
function deadIsolateCount(recorded, current) {
|
|
3400
|
+
const dead = /* @__PURE__ */ new Set();
|
|
3401
|
+
for (const attempt of recorded ?? []) if (attempt.isolate !== current.isolate) dead.add(attempt.isolate);
|
|
3402
|
+
return dead.size;
|
|
3403
|
+
}
|
|
3404
|
+
/** The attempts in `recorded` that are still running in `current`'s isolate. */
|
|
3405
|
+
function liveAttempts(recorded, current) {
|
|
3406
|
+
return (recorded ?? []).filter((attempt) => attempt.isolate === current.isolate);
|
|
3407
|
+
}
|
|
3408
|
+
/** Persist `attempts` only when there is at least one. */
|
|
3409
|
+
function withAttemptsInFlight(attempts) {
|
|
3410
|
+
return attempts.length > 0 ? { attemptsInFlight: attempts } : {};
|
|
3411
|
+
}
|
|
3412
|
+
/**
|
|
3413
|
+
* The `attemptsInFlight` an incident opening leaves behind. A replay drops
|
|
3414
|
+
* the dead isolates' entries it just counted and adds itself, unless the
|
|
3415
|
+
* incident is now sealed; a stall leaves the running attempts untouched.
|
|
3416
|
+
*/
|
|
3417
|
+
function attemptsInFlightAfter(trigger, existing, exhausted) {
|
|
3418
|
+
if (trigger.kind === "interrupted") {
|
|
3419
|
+
const live = liveAttempts(existing?.attemptsInFlight, trigger.attempt);
|
|
3420
|
+
return withAttemptsInFlight(exhausted ? live : [...live, trigger.attempt]);
|
|
3421
|
+
}
|
|
3422
|
+
return withAttemptsInFlight([...existing?.attemptsInFlight ?? []]);
|
|
3423
|
+
}
|
|
3424
|
+
/**
|
|
3425
|
+
* Admit one recovery attempt (a `_chatRecoveryContinue` / `_chatRecoveryRetry`
|
|
3426
|
+
* callback and the turn it starts) before it does any heavy work (#2613).
|
|
3427
|
+
*
|
|
3428
|
+
* Entries in `attemptsInFlight` left by other isolates are attempts that
|
|
3429
|
+
* died, for example to a memory-limit reset before or during their turn.
|
|
3430
|
+
* Each such isolate counts as one interrupted attempt and its entries are
|
|
3431
|
+
* dropped. The returned incident adds `attempt` to the running attempts,
|
|
3432
|
+
* unless the budget is spent, in which case the caller seals the incident
|
|
3433
|
+
* instead of running anything. A parked turn is budget-free: it is counted
|
|
3434
|
+
* but never sealed.
|
|
3435
|
+
*
|
|
3436
|
+
* @param input - The incident, the attempt about to start, and the budget.
|
|
3437
|
+
* @returns The incident to persist, and whether the budget is spent.
|
|
3438
|
+
*/
|
|
3439
|
+
function admitChatRecoveryAttempt(input) {
|
|
3440
|
+
const { existing, attempt, config, awaitingClientInteraction } = input;
|
|
3441
|
+
const interruptedAttempts = (existing.interruptedAttempts ?? 0) + deadIsolateCount(existing.attemptsInFlight, attempt);
|
|
3442
|
+
const exhausted = !awaitingClientInteraction && interruptedAttempts >= config.maxInterruptedAttempts;
|
|
3443
|
+
const live = liveAttempts(existing.attemptsInFlight, attempt);
|
|
3444
|
+
const { attemptsInFlight: _previous, ...rest } = existing;
|
|
3445
|
+
return {
|
|
3446
|
+
incident: {
|
|
3447
|
+
...rest,
|
|
3448
|
+
...interruptedAttempts > 0 ? { interruptedAttempts } : {},
|
|
3449
|
+
...withAttemptsInFlight(exhausted ? live : [...live, attempt])
|
|
3450
|
+
},
|
|
3451
|
+
exhausted
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Remove `attempt` from the running attempts once it finished in this
|
|
3456
|
+
* isolate. Other running attempts stay recorded.
|
|
3457
|
+
*
|
|
3458
|
+
* @param existing - The persisted incident.
|
|
3459
|
+
* @param attempt - The attempt that finished.
|
|
3460
|
+
* @returns The incident to persist, or `null` when `attempt` is not recorded.
|
|
3461
|
+
*/
|
|
3462
|
+
function finishChatRecoveryAttempt(existing, attempt) {
|
|
3463
|
+
const recorded = existing.attemptsInFlight ?? [];
|
|
3464
|
+
const remaining = recorded.filter((entry) => entry.token !== attempt.token);
|
|
3465
|
+
if (remaining.length === recorded.length) return null;
|
|
3466
|
+
const { attemptsInFlight: _finished, ...rest } = existing;
|
|
3467
|
+
return {
|
|
3468
|
+
...rest,
|
|
3469
|
+
...withAttemptsInFlight(remaining)
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3378
3472
|
//#endregion
|
|
3379
3473
|
//#region src/chat/recovery-engine.ts
|
|
3474
|
+
var _isolate = /* @__PURE__ */ new WeakMap();
|
|
3475
|
+
var _ChatRecoveryEngine_brand = /* @__PURE__ */ new WeakSet();
|
|
3380
3476
|
/**
|
|
3381
3477
|
* Drives the shared recovery orchestration over a {@link ChatRecoveryAdapter}.
|
|
3382
3478
|
* The incident *budget math* lives in the pure `evaluateChatRecoveryIncident`;
|
|
@@ -3385,6 +3481,59 @@ async function evaluateChatRecoveryIncident(input) {
|
|
|
3385
3481
|
var ChatRecoveryEngine = class {
|
|
3386
3482
|
constructor(adapter) {
|
|
3387
3483
|
this.adapter = adapter;
|
|
3484
|
+
_classPrivateMethodInitSpec(this, _ChatRecoveryEngine_brand);
|
|
3485
|
+
_classPrivateFieldInitSpec(this, _isolate, crypto.randomUUID());
|
|
3486
|
+
}
|
|
3487
|
+
/**
|
|
3488
|
+
* Run one recovery attempt under the interruption budget (#2613): a
|
|
3489
|
+
* `_chatRecoveryContinue` / `_chatRecoveryRetry` callback and the turn it
|
|
3490
|
+
* starts. Before `run` does anything heavy, the attempt counts any earlier
|
|
3491
|
+
* attempt that died (entries another isolate left in `attemptsInFlight`)
|
|
3492
|
+
* and records itself, confirmed with `syncStorage`. Once
|
|
3493
|
+
* `maxInterruptedAttempts` attempts have died the turn is sealed with
|
|
3494
|
+
* `interrupted_attempts_exceeded` and `run` is never called. The entry is
|
|
3495
|
+
* removed when `run` settles, whatever its outcome.
|
|
3496
|
+
*
|
|
3497
|
+
* This catches deaths the replay of an interrupted turn run cannot see, such
|
|
3498
|
+
* as a reset before the callback starts its turn, which leaves no turn run
|
|
3499
|
+
* to replay. A callback for a sealed incident does nothing: the turn was
|
|
3500
|
+
* already terminalized, and running it would re-run the model. A payload
|
|
3501
|
+
* without an incident, or one whose incident is gone, runs untracked.
|
|
3502
|
+
*
|
|
3503
|
+
* @param input - The callback being run, its payload, and the work.
|
|
3504
|
+
*/
|
|
3505
|
+
async runRecoveryAttempt(input) {
|
|
3506
|
+
const { adapter } = this;
|
|
3507
|
+
const incidentId = typeof input.data?.incidentId === "string" ? input.data.incidentId : void 0;
|
|
3508
|
+
const existing = incidentId ? await adapter.getIncident(chatRecoveryIncidentKey(incidentId)) : null;
|
|
3509
|
+
if (existing?.status === "exhausted") return;
|
|
3510
|
+
if (!incidentId || !existing) {
|
|
3511
|
+
await input.run();
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
adapter.ensureInteractionStateLoaded?.();
|
|
3515
|
+
const attempt = _assertClassBrand(_ChatRecoveryEngine_brand, this, _newAttempt).call(this);
|
|
3516
|
+
const { incident, exhausted } = admitChatRecoveryAttempt({
|
|
3517
|
+
existing,
|
|
3518
|
+
attempt,
|
|
3519
|
+
config: adapter.resolveConfig(),
|
|
3520
|
+
awaitingClientInteraction: adapter.isAwaitingClientInteraction?.() ?? false
|
|
3521
|
+
});
|
|
3522
|
+
await adapter.putIncident(chatRecoveryIncidentKey(incidentId), incident);
|
|
3523
|
+
await adapter.syncStorage();
|
|
3524
|
+
if (exhausted) {
|
|
3525
|
+
await this.exhaustRecoveryGiveUp({
|
|
3526
|
+
callback: input.callback,
|
|
3527
|
+
data: { incidentId },
|
|
3528
|
+
reason: "interrupted_attempts_exceeded"
|
|
3529
|
+
});
|
|
3530
|
+
return;
|
|
3531
|
+
}
|
|
3532
|
+
try {
|
|
3533
|
+
await input.run();
|
|
3534
|
+
} finally {
|
|
3535
|
+
await _assertClassBrand(_ChatRecoveryEngine_brand, this, _finishAttempt).call(this, incidentId, attempt);
|
|
3536
|
+
}
|
|
3388
3537
|
}
|
|
3389
3538
|
/**
|
|
3390
3539
|
* Open or re-evaluate the recovery incident for `input`, persist the result,
|
|
@@ -3447,61 +3596,32 @@ var ChatRecoveryEngine = class {
|
|
|
3447
3596
|
streamStatus
|
|
3448
3597
|
});
|
|
3449
3598
|
const recoveryRootRequestId = snapshot?.recoveryRootRequestId ?? requestId;
|
|
3450
|
-
const { incident, config, exhausted } = await this.beginIncident({
|
|
3599
|
+
const { incident, config, exhausted, attempt } = await this.beginIncident({
|
|
3451
3600
|
requestId,
|
|
3452
3601
|
recoveryRootRequestId,
|
|
3453
3602
|
latestUserMessageId: snapshot?.latestUserMessageId,
|
|
3454
|
-
recoveryKind
|
|
3603
|
+
recoveryKind,
|
|
3604
|
+
trigger: "interrupted"
|
|
3455
3605
|
});
|
|
3456
|
-
if (exhausted) {
|
|
3457
|
-
if (await this._shouldPersistOrphanedPartial(wake, {
|
|
3458
|
-
streamId,
|
|
3459
|
-
streamStillActive,
|
|
3460
|
-
streamStatus,
|
|
3461
|
-
snapshot,
|
|
3462
|
-
options: void 0,
|
|
3463
|
-
partial
|
|
3464
|
-
})) await wake.persistOrphanedStream(streamId);
|
|
3465
|
-
await adapter.exhaustChatRecovery(incident, config, partial, streamId, ctx.createdAt, snapshot?.originMessageIds);
|
|
3466
|
-
return true;
|
|
3467
|
-
}
|
|
3468
3606
|
try {
|
|
3469
|
-
|
|
3607
|
+
return await _assertClassBrand(_ChatRecoveryEngine_brand, this, _replayRecoveredTurn).call(this, wake, {
|
|
3608
|
+
ctx,
|
|
3470
3609
|
incident,
|
|
3610
|
+
config,
|
|
3611
|
+
exhausted,
|
|
3471
3612
|
recoveryKind,
|
|
3472
|
-
|
|
3613
|
+
detail,
|
|
3473
3614
|
requestId,
|
|
3474
|
-
|
|
3475
|
-
partial,
|
|
3615
|
+
recoveryRootRequestId,
|
|
3476
3616
|
snapshot,
|
|
3477
3617
|
recoveryData,
|
|
3478
|
-
createdAt: ctx.createdAt
|
|
3479
|
-
}) ?? {};
|
|
3480
|
-
if (await this._shouldPersistOrphanedPartial(wake, {
|
|
3481
3618
|
streamId,
|
|
3482
3619
|
streamStillActive,
|
|
3483
3620
|
streamStatus,
|
|
3484
|
-
snapshot,
|
|
3485
|
-
options,
|
|
3486
3621
|
partial
|
|
3487
|
-
})) await wake.persistOrphanedStream(streamId);
|
|
3488
|
-
if (streamStillActive) await wake.completeRecoveredStream(streamId);
|
|
3489
|
-
await wake.dispatchRecoveredTurn({
|
|
3490
|
-
incident,
|
|
3491
|
-
config,
|
|
3492
|
-
recoveryKind,
|
|
3493
|
-
options,
|
|
3494
|
-
snapshot,
|
|
3495
|
-
requestId,
|
|
3496
|
-
recoveryRootRequestId,
|
|
3497
|
-
streamId,
|
|
3498
|
-
streamStatus,
|
|
3499
|
-
detail
|
|
3500
3622
|
});
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
await this.updateIncident(incident.incidentId, "failed", error instanceof Error ? error.message : String(error));
|
|
3504
|
-
throw error;
|
|
3623
|
+
} finally {
|
|
3624
|
+
if (attempt) await _assertClassBrand(_ChatRecoveryEngine_brand, this, _finishAttempt).call(this, incident.incidentId, attempt);
|
|
3505
3625
|
}
|
|
3506
3626
|
}
|
|
3507
3627
|
/**
|
|
@@ -3530,21 +3650,29 @@ var ChatRecoveryEngine = class {
|
|
|
3530
3650
|
await adapter.sweepStaleIncidents(now);
|
|
3531
3651
|
const existing = await adapter.getIncident(key);
|
|
3532
3652
|
adapter.ensureInteractionStateLoaded?.();
|
|
3653
|
+
const currentProgress = await adapter.readProgress();
|
|
3654
|
+
const trigger = input.trigger === "interrupted" ? {
|
|
3655
|
+
kind: "interrupted",
|
|
3656
|
+
attempt: _assertClassBrand(_ChatRecoveryEngine_brand, this, _newAttempt).call(this)
|
|
3657
|
+
} : { kind: "stalled" };
|
|
3533
3658
|
const { incident, exhausted, events } = await evaluateChatRecoveryIncident({
|
|
3534
3659
|
identity: input,
|
|
3660
|
+
trigger,
|
|
3535
3661
|
config,
|
|
3536
3662
|
existing,
|
|
3537
|
-
currentProgress
|
|
3663
|
+
currentProgress,
|
|
3538
3664
|
awaitingClientInteraction: adapter.isAwaitingClientInteraction?.() ?? false,
|
|
3539
3665
|
now,
|
|
3540
3666
|
onShouldKeepRecoveringError: (error) => adapter.onShouldKeepRecoveringError?.(error)
|
|
3541
3667
|
});
|
|
3542
3668
|
await adapter.putIncident(key, incident);
|
|
3669
|
+
await adapter.syncStorage();
|
|
3543
3670
|
for (const event of events) adapter.emitRecoveryEvent(event);
|
|
3544
3671
|
return {
|
|
3545
3672
|
incident,
|
|
3546
3673
|
config,
|
|
3547
|
-
exhausted
|
|
3674
|
+
exhausted,
|
|
3675
|
+
attempt: trigger.kind === "interrupted" && !exhausted ? trigger.attempt : null
|
|
3548
3676
|
};
|
|
3549
3677
|
}
|
|
3550
3678
|
/**
|
|
@@ -3656,54 +3784,6 @@ var ChatRecoveryEngine = class {
|
|
|
3656
3784
|
return incident?.status === "skipped" && incident.reason === "user_cancelled";
|
|
3657
3785
|
}
|
|
3658
3786
|
/**
|
|
3659
|
-
* Record that a recovery callback observed a Durable Object memory-limit reset
|
|
3660
|
-
* (the isolate exceeded its 128 MB limit — `isDurableObjectMemoryLimitReset`)
|
|
3661
|
-
* and decide what to do next (#1825).
|
|
3662
|
-
*
|
|
3663
|
-
* Bumps the incident's durable `oomAttempts` counter, then:
|
|
3664
|
-
* - if it is still within `maxOomRetries`, issues a delayed, NON-idempotent
|
|
3665
|
-
* reschedule of the SAME callback (same machinery as
|
|
3666
|
-
* {@link rescheduleAfterStableTimeout}: the executing attempt settles
|
|
3667
|
-
* only after the callback returns, so an idempotent reschedule would
|
|
3668
|
-
* dedup onto that doomed attempt) and returns `"rescheduled"`. The small
|
|
3669
|
-
* delay lets a transient memory spike clear before the re-run;
|
|
3670
|
-
* - otherwise leaves the incremented count persisted (so a begin-path
|
|
3671
|
-
* re-evaluation agrees) and returns `"exhausted"` — the caller then
|
|
3672
|
-
* terminalizes via the give-up path with `reason="out_of_memory"`.
|
|
3673
|
-
*
|
|
3674
|
-
* Returns `"exhausted"` when there is no incident to track against (no id /
|
|
3675
|
-
* record gone): an OOM we cannot bound must seal rather than loop. Unlike a
|
|
3676
|
-
* stable-state retry this is gated by the OOM-specific budget, NOT the generic
|
|
3677
|
-
* attempt cap — re-running an OOM streams a little "progress" that would
|
|
3678
|
-
* otherwise reset the attempt cap forever (the #1825 loop).
|
|
3679
|
-
*/
|
|
3680
|
-
async recordOomAndDecide(input) {
|
|
3681
|
-
const { adapter } = this;
|
|
3682
|
-
if (!input.incidentId) return "exhausted";
|
|
3683
|
-
const key = chatRecoveryIncidentKey(input.incidentId);
|
|
3684
|
-
const incident = await adapter.getIncident(key);
|
|
3685
|
-
if (!incident) return "exhausted";
|
|
3686
|
-
const oomAttempts = (incident.oomAttempts ?? 0) + 1;
|
|
3687
|
-
if (oomAttempts > input.maxOomRetries) {
|
|
3688
|
-
await adapter.putIncident(key, {
|
|
3689
|
-
...incident,
|
|
3690
|
-
oomAttempts,
|
|
3691
|
-
lastAttemptAt: adapter.now(),
|
|
3692
|
-
reason: "out_of_memory"
|
|
3693
|
-
});
|
|
3694
|
-
return "exhausted";
|
|
3695
|
-
}
|
|
3696
|
-
await adapter.putIncident(key, {
|
|
3697
|
-
...incident,
|
|
3698
|
-
oomAttempts,
|
|
3699
|
-
status: "scheduled",
|
|
3700
|
-
lastAttemptAt: adapter.now(),
|
|
3701
|
-
reason: "oom_retry"
|
|
3702
|
-
});
|
|
3703
|
-
await adapter.scheduleRecovery(input.callback, input.data ?? {}, "stable_timeout_retry", 3);
|
|
3704
|
-
return "rescheduled";
|
|
3705
|
-
}
|
|
3706
|
-
/**
|
|
3707
3787
|
* Give up on a recovery turn whose retry budget drained, terminalizing it so
|
|
3708
3788
|
* it can never become an eternal spinner (#1645). The shared spine both
|
|
3709
3789
|
* packages repeated verbatim:
|
|
@@ -3822,6 +3902,85 @@ var ChatRecoveryEngine = class {
|
|
|
3822
3902
|
else if (status === "completed" || status === "skipped" || status === "failed") await adapter.setRecovering(false);
|
|
3823
3903
|
}
|
|
3824
3904
|
};
|
|
3905
|
+
function _newAttempt() {
|
|
3906
|
+
return {
|
|
3907
|
+
isolate: _classPrivateFieldGet2(_isolate, this),
|
|
3908
|
+
token: crypto.randomUUID()
|
|
3909
|
+
};
|
|
3910
|
+
}
|
|
3911
|
+
/**
|
|
3912
|
+
* Remove a finished attempt's entry and confirm the write, so a reset right
|
|
3913
|
+
* after a clean finish cannot make the attempt look interrupted.
|
|
3914
|
+
* Best-effort: in a reset isolate this fails too, and the entry it leaves
|
|
3915
|
+
* behind is exactly what tells the next isolate that this attempt died.
|
|
3916
|
+
*/
|
|
3917
|
+
async function _finishAttempt(incidentId, attempt) {
|
|
3918
|
+
const { adapter } = this;
|
|
3919
|
+
const key = chatRecoveryIncidentKey(incidentId);
|
|
3920
|
+
try {
|
|
3921
|
+
const stored = await adapter.getIncident(key);
|
|
3922
|
+
const next = stored ? finishChatRecoveryAttempt(stored, attempt) : null;
|
|
3923
|
+
if (next) {
|
|
3924
|
+
await adapter.putIncident(key, next);
|
|
3925
|
+
await adapter.syncStorage();
|
|
3926
|
+
}
|
|
3927
|
+
} catch {}
|
|
3928
|
+
}
|
|
3929
|
+
/** The part of {@link handleChatFiberRecovery} that runs after the incident opened. */
|
|
3930
|
+
async function _replayRecoveredTurn(wake, input) {
|
|
3931
|
+
const { adapter } = this;
|
|
3932
|
+
const { ctx, incident, config, exhausted, recoveryKind, detail, requestId, recoveryRootRequestId, snapshot, recoveryData, streamId, streamStillActive, streamStatus, partial } = input;
|
|
3933
|
+
if (exhausted) {
|
|
3934
|
+
if (await this._shouldPersistOrphanedPartial(wake, {
|
|
3935
|
+
streamId,
|
|
3936
|
+
streamStillActive,
|
|
3937
|
+
streamStatus,
|
|
3938
|
+
snapshot,
|
|
3939
|
+
options: void 0,
|
|
3940
|
+
partial
|
|
3941
|
+
})) await wake.persistOrphanedStream(streamId);
|
|
3942
|
+
await adapter.exhaustChatRecovery(incident, config, partial, streamId, ctx.createdAt, snapshot?.originMessageIds);
|
|
3943
|
+
return true;
|
|
3944
|
+
}
|
|
3945
|
+
try {
|
|
3946
|
+
const options = await wake.invokeOnChatRecovery?.({
|
|
3947
|
+
incident,
|
|
3948
|
+
recoveryKind,
|
|
3949
|
+
recoveryRootRequestId,
|
|
3950
|
+
requestId,
|
|
3951
|
+
streamId,
|
|
3952
|
+
partial,
|
|
3953
|
+
snapshot,
|
|
3954
|
+
recoveryData,
|
|
3955
|
+
createdAt: ctx.createdAt
|
|
3956
|
+
}) ?? {};
|
|
3957
|
+
if (await this._shouldPersistOrphanedPartial(wake, {
|
|
3958
|
+
streamId,
|
|
3959
|
+
streamStillActive,
|
|
3960
|
+
streamStatus,
|
|
3961
|
+
snapshot,
|
|
3962
|
+
options,
|
|
3963
|
+
partial
|
|
3964
|
+
})) await wake.persistOrphanedStream(streamId);
|
|
3965
|
+
if (streamStillActive) await wake.completeRecoveredStream(streamId);
|
|
3966
|
+
await wake.dispatchRecoveredTurn({
|
|
3967
|
+
incident,
|
|
3968
|
+
config,
|
|
3969
|
+
recoveryKind,
|
|
3970
|
+
options,
|
|
3971
|
+
snapshot,
|
|
3972
|
+
requestId,
|
|
3973
|
+
recoveryRootRequestId,
|
|
3974
|
+
streamId,
|
|
3975
|
+
streamStatus,
|
|
3976
|
+
detail
|
|
3977
|
+
});
|
|
3978
|
+
return true;
|
|
3979
|
+
} catch (error) {
|
|
3980
|
+
await this.updateIncident(incident.incidentId, "failed", error instanceof Error ? error.message : String(error));
|
|
3981
|
+
throw error;
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3825
3984
|
/** `incident.reason` for a scheduled recovery the user cancelled. */
|
|
3826
3985
|
const CHAT_RECOVERY_CANCELLED_REASON = "user_cancelled";
|
|
3827
3986
|
/**
|
|
@@ -4159,6 +4318,6 @@ function isProviderExecuted(part) {
|
|
|
4159
4318
|
return part.providerExecuted === true;
|
|
4160
4319
|
}
|
|
4161
4320
|
//#endregion
|
|
4162
|
-
export { AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS, AbortRegistry, AgentToolProgressEmitter, AgentToolStreamProgressThrottle, AutoContinuationController, CHAT_LAST_TERMINAL_KEY, CHAT_MESSAGE_TYPES, CHAT_RECOVERING_FLAG_TTL_MS, CHAT_RECOVERING_KEY, CHAT_RECOVERY_ALARM_DEBOUNCE_MS, CHAT_RECOVERY_CANCELLED_REASON, CHAT_RECOVERY_INCIDENT_KEY_PREFIX, CHAT_RECOVERY_INCIDENT_TTL_MS, CHAT_RECOVERY_PROGRESS_KEY, CHAT_RECOVERY_STABLE_RETRY_DELAY_SECONDS, CHAT_RECOVERY_TASK_NAME, CHAT_STREAM_PROGRESS_CREDIT_THROTTLE_MS, ChatRecoveryEngine, ChatStreamStalledError, ContinuationState, DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS,
|
|
4321
|
+
export { AGENT_TOOL_STREAM_PROGRESS_BUMP_THROTTLE_MS, AbortRegistry, AgentToolProgressEmitter, AgentToolStreamProgressThrottle, AutoContinuationController, CHAT_LAST_TERMINAL_KEY, CHAT_MESSAGE_TYPES, CHAT_RECOVERING_FLAG_TTL_MS, CHAT_RECOVERING_KEY, CHAT_RECOVERY_ALARM_DEBOUNCE_MS, CHAT_RECOVERY_CANCELLED_REASON, CHAT_RECOVERY_INCIDENT_KEY_PREFIX, CHAT_RECOVERY_INCIDENT_TTL_MS, CHAT_RECOVERY_PROGRESS_KEY, CHAT_RECOVERY_STABLE_RETRY_DELAY_SECONDS, CHAT_RECOVERY_TASK_NAME, CHAT_STREAM_PROGRESS_CREDIT_THROTTLE_MS, ChatRecoveryEngine, ChatStreamStalledError, ContinuationState, DEFAULT_CHAT_RECOVERY_MAX_ATTEMPTS, DEFAULT_CHAT_RECOVERY_MAX_INTERRUPTED_ATTEMPTS, DEFAULT_CHAT_RECOVERY_MAX_WORK, DEFAULT_CHAT_RECOVERY_NO_PROGRESS_TIMEOUT_MS, DEFAULT_CHAT_RECOVERY_STABLE_TIMEOUT_MS, DEFAULT_CHAT_RECOVERY_TERMINAL_MESSAGE, KV_DELETE_MAX_KEYS, MAX_BOUND_PARAMS, MessageType, PreStreamTurns, ROW_MAX_BYTES, ResumableStream, ResumeHandshake, STREAM_RESUME_NONE_REASONS, StreamAccumulator, StreamProgressCreditThrottle, SubmitConcurrencyController, TIMED_OUT, TextSegmentJoiner, TurnQueue, aiSdkRecoveryCodec, applyAgentToolEvent, applyChunkToParts, applyLateToolInput, applyToolUpdate, awaitWithDeadline, transition as broadcastTransition, buildChatRecoveringFrame, buildInClauseStrings, bumpChatRecoveryProgress, byteLength, chatRecoveryBackoffSeconds, chatRecoveryTaskRunOptions, classifyAgentToolChildRecovery, clearChatTerminal, clientResolvableToolNames, createAgentToolEventState, createChatFiberSnapshot, createChatRecoveryTaskDefinition, createChatStreams, createChatTurnTaskDefinition, createToolsFromClientSchemas, crossMessageToolResultUpdate, dispatchChatRecoveryToHandoff, drainInteractionApplies, enforceRowSizeLimit, hasIncompleteToolBatch, interceptAgentToolBroadcast, isDurableObjectResetError, isLateToolInputChunk, isPlatformFailure, isPositionlessAgentToolChunk, isReplayChunk, iterateWithStallWatchdog, lateToolInputForwardChunks, listActiveChatRecoveryIncidents, normalizeToolInput, originMessageIds, parseProtocolMessage, partAwaitsClientInteraction, partialHasSettledToolResults, pausedExecutionUpdate, pendingChatTerminal, persistReconstructedOrphan, readChatRecoveryProgress, reconcileMessages, reconcileOrphanPartial, recordChatTerminal, repairInterruptedToolParts, resolveChatRecoveryConfig, resolveToolMergeId, retryAfterSeconds, runChatRecoveryExhaustion, sanitizeMessage, sendIfOpen, setChatRecovering, shouldCreditStreamProgress, sweepStaleChatRecoveryIncidents, toolApprovalUpdate, toolPartHasSettledResult, toolResultUpdate, truncateOlderMessages, truncateOlderToolResults, unwrapChatFiberSnapshot, withOriginMessageIds, wrapChatFiberSnapshot };
|
|
4163
4322
|
|
|
4164
4323
|
//# sourceMappingURL=index.js.map
|