@agent-native/core 0.84.67 → 0.85.1
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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +20 -0
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +55 -0
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +55 -0
- package/corpus/core/docs/content/tracking.mdx +2 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/action-continuation-guidance.ts +1 -1
- package/corpus/core/src/agent/production-agent.ts +222 -38
- package/corpus/core/src/agent/run-manager.ts +79 -0
- package/corpus/core/src/agent/run-store.ts +122 -8
- package/corpus/core/src/agent/types.ts +13 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +14 -0
- package/corpus/core/src/client/agent-chat-adapter.ts +475 -0
- package/corpus/core/src/client/analytics.ts +2 -0
- package/corpus/core/src/client/error-format.ts +4 -0
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +1 -1
- package/corpus/core/src/client/session-replay.ts +774 -2
- package/corpus/core/src/client/sse-event-processor.ts +65 -9
- package/corpus/core/src/client/use-run-stuck-detection.ts +31 -7
- package/corpus/core/src/db/runtime-diagnostics.ts +331 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +115 -2
- package/corpus/core/src/server/core-routes-plugin.ts +91 -4
- package/corpus/core/src/server/http-response-telemetry.ts +189 -0
- package/corpus/core/src/server/self-dispatch.ts +29 -0
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +53 -1
- package/corpus/templates/analytics/AGENTS.md +13 -0
- package/corpus/templates/analytics/actions/view-screen.ts +25 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +20 -0
- package/corpus/templates/analytics/app/global.css +55 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +100 -1
- package/corpus/templates/analytics/app/i18n-data.ts +1226 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +3 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +182 -144
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +11 -18
- package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +11 -18
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +49 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +557 -0
- package/corpus/templates/analytics/app/pages/sessions/session-replay-devtools.ts +274 -0
- package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +974 -0
- package/corpus/templates/analytics/changelog/2026-07-02-alert-rules-can-now-be-viewed-and-managed-from-settings.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-02-recent-ask-chats-show-a-loading-placeholder-while-your-chat-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-02-session-replays-now-capture-console-logs-and-network-request.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-02-sharing-status-labels-use-neutral-icons-instead-of-colored-d.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-02-the-session-replay-viewer-has-a-dev-tools-panel-with-console.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +3 -0
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +4 -0
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +142 -1
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +369 -8
- package/corpus/templates/analytics/server/lib/session-replay.ts +76 -2
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +101 -0
- package/corpus/templates/analytics/shared/session-replay-diagnostics.ts +78 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +24 -12
- package/corpus/templates/design/changelog/2026-07-02-the-temporary-code-tab-is-hidden-from-the-design-editor-side.md +6 -0
- package/corpus/templates/plan/actions/create-visual-recap.ts +1 -1
- package/corpus/templates/plan/actions/update-local-plan-folder.ts +3 -1
- package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
- package/corpus/templates/plan/changelog/2026-07-02-trying-to-edit-a-recap-or-plan-you-can-only-view-now-explain.md +6 -0
- package/corpus/templates/plan/server/plans.ts +26 -9
- package/dist/agent/action-continuation-guidance.js +1 -1
- package/dist/agent/action-continuation-guidance.js.map +1 -1
- package/dist/agent/production-agent.d.ts +9 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +168 -34
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +29 -0
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +73 -0
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +41 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +105 -7
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +13 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +13 -0
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +410 -0
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/analytics.d.ts +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +2 -0
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/session-replay.d.ts +36 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +579 -1
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +20 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +42 -11
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts +14 -4
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +18 -4
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/db/runtime-diagnostics.d.ts +52 -0
- package/dist/db/runtime-diagnostics.d.ts.map +1 -0
- package/dist/db/runtime-diagnostics.js +250 -0
- package/dist/db/runtime-diagnostics.js.map +1 -0
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +101 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +17 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +65 -5
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/http-response-telemetry.d.ts +4 -0
- package/dist/server/http-response-telemetry.d.ts.map +1 -0
- package/dist/server/http-response-telemetry.js +174 -0
- package/dist/server/http-response-telemetry.js.map +1 -0
- package/dist/server/self-dispatch.d.ts +17 -0
- package/dist/server/self-dispatch.d.ts.map +1 -1
- package/dist/server/self-dispatch.js +11 -0
- package/dist/server/self-dispatch.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/locales/ar-SA/tracking.mdx +55 -0
- package/docs/content/locales/de-DE/tracking.mdx +55 -0
- package/docs/content/locales/es-ES/tracking.mdx +55 -0
- package/docs/content/locales/fr-FR/tracking.mdx +55 -0
- package/docs/content/locales/hi-IN/tracking.mdx +55 -0
- package/docs/content/locales/ja-JP/tracking.mdx +55 -0
- package/docs/content/locales/ko-KR/tracking.mdx +55 -0
- package/docs/content/locales/pt-BR/tracking.mdx +55 -0
- package/docs/content/locales/zh-CN/tracking.mdx +55 -0
- package/docs/content/locales/zh-TW/tracking.mdx +55 -0
- package/docs/content/tracking.mdx +2 -0
- package/package.json +1 -1
|
@@ -32,7 +32,7 @@ import { getDefaultMaxIterations, MAX_AGENT_MAX_ITERATIONS, MIN_AGENT_MAX_ITERAT
|
|
|
32
32
|
import { maybeCompactThread, buildObservationalContext, hasObservationalMemory, serializeObservationalMemoryBlock, } from "./observational-memory/index.js";
|
|
33
33
|
import { ProcessorChain, TripWire, toolCallsFromContent, } from "./processors.js";
|
|
34
34
|
import { startRun, subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, tryClaimRunSlot, } from "./run-manager.js";
|
|
35
|
-
import { writeLedgerEntry, readLedgerEntry, clearLedgerForThread, getCurrentTurnEventsForThread, insertRun, updateRunHeartbeat, updateRunStatusIfRunning, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, RUN_DIAG_STAGE, UNCLAIMED_BACKGROUND_RUN_GRACE_MS, } from "./run-store.js";
|
|
35
|
+
import { writeLedgerEntry, readLedgerEntry, clearLedgerForThread, getCurrentTurnEventsForThread, insertRun, updateRunHeartbeat, updateRunStatusIfRunning, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, countRunsForTurn, RUN_DIAG_STAGE, UNCLAIMED_BACKGROUND_RUN_GRACE_MS, } from "./run-store.js";
|
|
36
36
|
import { classifyToolCallJournal, findCompletedJournalEntry, } from "./tool-call-journal.js";
|
|
37
37
|
import { redactSensitiveFields, sanitizeToolErrorText, sanitizeToolErrorValue, } from "./tool-error-redaction.js";
|
|
38
38
|
import { createToolSearchEntry, TOOL_SEARCH_ACTION_NAME, } from "./tool-search.js";
|
|
@@ -3460,6 +3460,15 @@ export function shouldChainBackgroundContinuation(opts) {
|
|
|
3460
3460
|
endsAtContinuationBoundary(opts.run) &&
|
|
3461
3461
|
opts.continuationCount < MAX_BACKGROUND_RUN_CONTINUATIONS);
|
|
3462
3462
|
}
|
|
3463
|
+
export async function markBackgroundContinuationChunkTerminal(opts) {
|
|
3464
|
+
const updateStatus = opts.deps?.updateRunStatusIfRunning ?? updateRunStatusIfRunning;
|
|
3465
|
+
const setTerminalReason = opts.deps?.setRunTerminalReason ?? setRunTerminalReason;
|
|
3466
|
+
const updated = await updateStatus(opts.runId, "completed");
|
|
3467
|
+
if (updated) {
|
|
3468
|
+
await setTerminalReason(opts.runId, opts.continuationReason);
|
|
3469
|
+
}
|
|
3470
|
+
return updated;
|
|
3471
|
+
}
|
|
3463
3472
|
export async function claimBackgroundWorkerRunEarly(opts) {
|
|
3464
3473
|
const record = opts.deps?.recordRunDiagnostic ?? recordRunDiagnostic;
|
|
3465
3474
|
const insert = opts.deps?.insertRun ?? insertRun;
|
|
@@ -4246,8 +4255,13 @@ export function createProductionAgentHandler(options) {
|
|
|
4246
4255
|
// Insert the run row up front so /runs/active sees it immediately and
|
|
4247
4256
|
// the slot stays held while the background function cold-starts. Mark
|
|
4248
4257
|
// it background-dispatched so the stale reaper uses the wider window.
|
|
4258
|
+
// The full request body is persisted ON the row (dispatch_payload) so
|
|
4259
|
+
// the self-POST below can carry only the tiny marker — Netlify caps
|
|
4260
|
+
// background-function request bodies at 256KB, and a large chat
|
|
4261
|
+
// history (inline attachments especially) silently exceeded that.
|
|
4249
4262
|
await insertRun(runId, effectiveThreadId, effectiveTurnId, {
|
|
4250
4263
|
dispatchMode: "background",
|
|
4264
|
+
dispatchPayload: JSON.stringify(body),
|
|
4251
4265
|
});
|
|
4252
4266
|
backgroundRowInserted = true;
|
|
4253
4267
|
}
|
|
@@ -4275,15 +4289,29 @@ export function createProductionAgentHandler(options) {
|
|
|
4275
4289
|
// the Authorization Bearer HMAC is preserved either way.
|
|
4276
4290
|
path: backgroundDispatchPath,
|
|
4277
4291
|
taskId: runId,
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4292
|
+
// When the row (and its persisted payload) landed, send only the
|
|
4293
|
+
// marker — the worker rehydrates the body from dispatch_payload
|
|
4294
|
+
// (`payloadRef`), keeping the self-POST far under Netlify's 256KB
|
|
4295
|
+
// background-function body cap. If the insert failed we fall back to
|
|
4296
|
+
// carrying the full body inline, exactly as before.
|
|
4297
|
+
body: backgroundRowInserted
|
|
4298
|
+
? {
|
|
4299
|
+
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
|
|
4300
|
+
runId,
|
|
4301
|
+
turnId: effectiveTurnId,
|
|
4302
|
+
backgroundFunctionRuntimeExpected: expectsNetlifyBackgroundFunction,
|
|
4303
|
+
payloadRef: true,
|
|
4304
|
+
},
|
|
4305
|
+
}
|
|
4306
|
+
: {
|
|
4307
|
+
...body,
|
|
4308
|
+
// Carry the pre-claimed identity so the worker reuses this run.
|
|
4309
|
+
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
|
|
4310
|
+
runId,
|
|
4311
|
+
turnId: effectiveTurnId,
|
|
4312
|
+
backgroundFunctionRuntimeExpected: expectsNetlifyBackgroundFunction,
|
|
4313
|
+
},
|
|
4285
4314
|
},
|
|
4286
|
-
},
|
|
4287
4315
|
});
|
|
4288
4316
|
dispatched = true;
|
|
4289
4317
|
}
|
|
@@ -4503,6 +4531,23 @@ export function createProductionAgentHandler(options) {
|
|
|
4503
4531
|
// foreground fallback, which is not a worker and rides the
|
|
4504
4532
|
// connected client's auto_continue instead.)
|
|
4505
4533
|
if (willChainBackgroundContinuation(run)) {
|
|
4534
|
+
// DURABLE PER-TURN LEDGER: bound the total number of runs one
|
|
4535
|
+
// logical turn may consume, counted in SQL. The in-marker
|
|
4536
|
+
// `continuationCount` resets whenever a fresh POST starts a new
|
|
4537
|
+
// chain for the same turn (client recovery, duplicate delivery),
|
|
4538
|
+
// so it cannot bound cross-chain loops — the SQL count survives
|
|
4539
|
+
// every recovery path and is what actually kills a pathological
|
|
4540
|
+
// turn (the "dozens of runs on one prompt" incident class).
|
|
4541
|
+
const turnRunCount = await countRunsForTurn(effectiveThreadId, effectiveTurnId).catch(() => null);
|
|
4542
|
+
if (turnRunCount !== null &&
|
|
4543
|
+
turnRunCount > MAX_BACKGROUND_RUN_CONTINUATIONS + 5) {
|
|
4544
|
+
console.error(`[agent-chat] turn ${effectiveTurnId} consumed ${turnRunCount} runs — refusing to chain further`, runId);
|
|
4545
|
+
const statusUpdated = await updateRunStatusIfRunning(runId, "errored").catch(() => false);
|
|
4546
|
+
if (statusUpdated) {
|
|
4547
|
+
await setRunTerminalReason(runId, "turn_continuation_budget_exhausted").catch(() => { });
|
|
4548
|
+
}
|
|
4549
|
+
return;
|
|
4550
|
+
}
|
|
4506
4551
|
// Mint the next chunk's runId here and sign the dispatch token
|
|
4507
4552
|
// over it, so the `_process-run` route's HMAC check and the
|
|
4508
4553
|
// worker's run identity agree. Fresh runId (not this chunk's) so
|
|
@@ -4513,37 +4558,126 @@ export function createProductionAgentHandler(options) {
|
|
|
4513
4558
|
const continuationReason = backgroundContinuationReasonForRun(run);
|
|
4514
4559
|
const continuationDispatchPath = resolveAgentChatProcessRunDispatchPath();
|
|
4515
4560
|
const continuationExpectsNetlifyBackgroundFunction = dispatchPathTargetsNetlifyBackgroundFunction(continuationDispatchPath);
|
|
4561
|
+
const continuationMarker = {
|
|
4562
|
+
runId: nextRunId,
|
|
4563
|
+
turnId: effectiveTurnId,
|
|
4564
|
+
continuationCount: backgroundContinuationCount + 1,
|
|
4565
|
+
continuationReason,
|
|
4566
|
+
...(actionPreparationTool ? { actionPreparationTool } : {}),
|
|
4567
|
+
backgroundFunctionRuntimeExpected: continuationExpectsNetlifyBackgroundFunction,
|
|
4568
|
+
};
|
|
4569
|
+
// Strip this chunk's own marker before persisting/forwarding —
|
|
4570
|
+
// the next chunk gets the fresh marker above.
|
|
4571
|
+
const continuationBody = {
|
|
4572
|
+
...body,
|
|
4573
|
+
internalContinuation: true,
|
|
4574
|
+
};
|
|
4575
|
+
delete continuationBody[AGENT_CHAT_BACKGROUND_RUN_FIELD];
|
|
4516
4576
|
try {
|
|
4517
4577
|
await recordRunDiagnostic(run.runId, RUN_DIAG_STAGE.workerSetupStep, `chain_dispatch_start nextRunId=${nextRunId} reason=${continuationReason} path=${continuationDispatchPath}`).catch(() => { });
|
|
4518
|
-
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4578
|
+
// ── TRANSACTIONAL HANDOFF ──────────────────────────────────
|
|
4579
|
+
// 1. Insert the successor row (with its rehydration payload)
|
|
4580
|
+
// BEFORE firing the dispatch, so:
|
|
4581
|
+
// - /runs/active shows an active run continuously across
|
|
4582
|
+
// the chunk boundary (no idle gap for the client to
|
|
4583
|
+
// misread as "the turn ended"), and
|
|
4584
|
+
// - a lost dispatch leaves a row the unclaimed-run sweep
|
|
4585
|
+
// reaps into a LOUD error instead of a silent hang.
|
|
4586
|
+
// 2. Await the dispatch response fully (`awaitResponse`) —
|
|
4587
|
+
// this worker's Lambda is about to finish, and the old
|
|
4588
|
+
// 250ms settle race let a still-in-flight handoff fetch be
|
|
4589
|
+
// killed by the post-return freeze WITHOUT rejecting: the
|
|
4590
|
+
// turn just stopped, silently. A Netlify background
|
|
4591
|
+
// function 202s on enqueue (normally well under a second),
|
|
4592
|
+
// and this chunk has minutes of budget headroom left, so
|
|
4593
|
+
// awaiting is cheap. Retried with backoff for transient
|
|
4594
|
+
// network blips.
|
|
4595
|
+
let nextRowInserted = false;
|
|
4596
|
+
try {
|
|
4597
|
+
await insertRun(nextRunId, effectiveThreadId, effectiveTurnId, {
|
|
4598
|
+
dispatchMode: "background",
|
|
4599
|
+
dispatchPayload: JSON.stringify(continuationBody),
|
|
4600
|
+
});
|
|
4601
|
+
nextRowInserted = true;
|
|
4602
|
+
}
|
|
4603
|
+
catch (insertErr) {
|
|
4604
|
+
await recordRunDiagnostic(run.runId, RUN_DIAG_STAGE.workerSetupStep, `chain_successor_insert_failed nextRunId=${nextRunId} ${insertErr instanceof Error
|
|
4605
|
+
? insertErr.message
|
|
4606
|
+
: String(insertErr)}`).catch(() => { });
|
|
4607
|
+
console.error("[agent-chat] continuation insertRun failed; dispatching with inline body:", insertErr instanceof Error
|
|
4608
|
+
? insertErr.message
|
|
4609
|
+
: insertErr);
|
|
4610
|
+
}
|
|
4611
|
+
const dispatchBody = nextRowInserted
|
|
4612
|
+
? {
|
|
4530
4613
|
internalContinuation: true,
|
|
4531
4614
|
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: {
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
continuationCount: backgroundContinuationCount + 1,
|
|
4535
|
-
continuationReason,
|
|
4536
|
-
...(actionPreparationTool
|
|
4537
|
-
? { actionPreparationTool }
|
|
4538
|
-
: {}),
|
|
4539
|
-
backgroundFunctionRuntimeExpected: continuationExpectsNetlifyBackgroundFunction,
|
|
4615
|
+
...continuationMarker,
|
|
4616
|
+
payloadRef: true,
|
|
4540
4617
|
},
|
|
4541
|
-
}
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
:
|
|
4545
|
-
|
|
4618
|
+
}
|
|
4619
|
+
: {
|
|
4620
|
+
...continuationBody,
|
|
4621
|
+
[AGENT_CHAT_BACKGROUND_RUN_FIELD]: continuationMarker,
|
|
4622
|
+
};
|
|
4623
|
+
let dispatched = false;
|
|
4624
|
+
let lastDispatchErr;
|
|
4625
|
+
for (let attempt = 0; attempt < 3 && !dispatched; attempt++) {
|
|
4626
|
+
try {
|
|
4627
|
+
if (attempt > 0) {
|
|
4628
|
+
await new Promise((resolve) => setTimeout(resolve, 500 * 2 ** attempt));
|
|
4629
|
+
// Keep the pre-inserted successor row visibly alive
|
|
4630
|
+
// while we retry: the awaited attempts + backoff can
|
|
4631
|
+
// outlast UNCLAIMED_BACKGROUND_RUN_GRACE_MS (25s), and
|
|
4632
|
+
// without a fresh heartbeat the unclaimed-run reaper /
|
|
4633
|
+
// sweep could error a handoff we are still delivering.
|
|
4634
|
+
if (nextRowInserted) {
|
|
4635
|
+
await updateRunHeartbeat(nextRunId).catch(() => { });
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
await fireInternalDispatch({
|
|
4639
|
+
event,
|
|
4640
|
+
// Continuation chunks use the same path resolution as
|
|
4641
|
+
// the initial dispatch: on hosted Netlify the background
|
|
4642
|
+
// function's DEFAULT url (no custom config.path; async
|
|
4643
|
+
// via background:true; never shadowed because
|
|
4644
|
+
// /.netlify/* is excluded from the /* catch-all) so each
|
|
4645
|
+
// chunk keeps the 15-min budget; off-Netlify the
|
|
4646
|
+
// in-process framework route.
|
|
4647
|
+
path: continuationDispatchPath,
|
|
4648
|
+
taskId: nextRunId,
|
|
4649
|
+
body: dispatchBody,
|
|
4650
|
+
awaitResponse: true,
|
|
4651
|
+
responseTimeoutMs: 15_000,
|
|
4652
|
+
});
|
|
4653
|
+
dispatched = true;
|
|
4654
|
+
}
|
|
4655
|
+
catch (dispatchErr) {
|
|
4656
|
+
lastDispatchErr = dispatchErr;
|
|
4657
|
+
console.error(`[agent-chat] background continuation dispatch attempt ${attempt + 1} failed:`, dispatchErr instanceof Error
|
|
4658
|
+
? dispatchErr.message
|
|
4659
|
+
: dispatchErr);
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4662
|
+
if (!dispatched) {
|
|
4663
|
+
// The pre-inserted successor row would otherwise sit
|
|
4664
|
+
// unclaimed until the sweep reaps it — error it now so the
|
|
4665
|
+
// failure is immediate and truthful.
|
|
4666
|
+
if (nextRowInserted) {
|
|
4667
|
+
const nextStatusUpdated = await updateRunStatusIfRunning(nextRunId, "errored").catch(() => false);
|
|
4668
|
+
if (nextStatusUpdated) {
|
|
4669
|
+
await setRunTerminalReason(nextRunId, "background_continuation_dispatch_failed").catch(() => { });
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
throw lastDispatchErr instanceof Error
|
|
4673
|
+
? lastDispatchErr
|
|
4674
|
+
: new Error(String(lastDispatchErr));
|
|
4675
|
+
}
|
|
4546
4676
|
await recordRunDiagnostic(run.runId, RUN_DIAG_STAGE.workerSetupStep, `chain_dispatch_sent nextRunId=${nextRunId} reason=${continuationReason}`).catch(() => { });
|
|
4677
|
+
await markBackgroundContinuationChunkTerminal({
|
|
4678
|
+
runId: run.runId,
|
|
4679
|
+
continuationReason,
|
|
4680
|
+
}).catch(() => { });
|
|
4547
4681
|
}
|
|
4548
4682
|
catch (chainErr) {
|
|
4549
4683
|
// Chain dispatch failed — fail loud so the held row goes
|