@agent-native/core 0.84.66 → 0.85.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/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/production-agent.ts +199 -38
- package/corpus/core/src/agent/run-manager.ts +79 -0
- package/corpus/core/src/agent/run-store.ts +117 -5
- 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/analytics.ts +1 -34
- 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/core/src/server/ssr-handler.ts +18 -377
- 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/clips/server/routes/api/video/[recordingId].get.ts +0 -2
- 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/forms/server/lib/public-form-ssr.ts +0 -1
- 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/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +155 -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 +100 -4
- 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 +1 -1
- 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/observability/routes.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- 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/analytics.d.ts +1 -19
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +1 -31
- package/dist/server/analytics.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/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +18 -271
- package/dist/server/ssr-handler.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
|
@@ -121,7 +121,8 @@ async function ensureRunTables(): Promise<void> {
|
|
|
121
121
|
error_detail TEXT,
|
|
122
122
|
terminal_reason TEXT,
|
|
123
123
|
dispatch_mode TEXT,
|
|
124
|
-
diag_stage TEXT
|
|
124
|
+
diag_stage TEXT,
|
|
125
|
+
dispatch_payload TEXT
|
|
125
126
|
)
|
|
126
127
|
`;
|
|
127
128
|
const agentRunEventsCreateSql = `
|
|
@@ -196,6 +197,13 @@ async function ensureRunTables(): Promise<void> {
|
|
|
196
197
|
["dispatch_mode", "TEXT"],
|
|
197
198
|
["diag_stage", "TEXT"],
|
|
198
199
|
["worker_stage", "TEXT"],
|
|
200
|
+
// dispatch_payload holds the JSON request body for a background
|
|
201
|
+
// dispatch so the self-POST to the Netlify background function can
|
|
202
|
+
// stay tiny (Netlify caps background-function request bodies at
|
|
203
|
+
// 256KB — a large chat history silently exceeded it). The worker
|
|
204
|
+
// rehydrates the body from this column via the marker's payloadRef.
|
|
205
|
+
// Cleared on terminal status writes.
|
|
206
|
+
["dispatch_payload", "TEXT"],
|
|
199
207
|
] as const) {
|
|
200
208
|
await ensureColumnExists(
|
|
201
209
|
"agent_runs",
|
|
@@ -280,6 +288,7 @@ async function ensureRunTables(): Promise<void> {
|
|
|
280
288
|
"dispatch_mode",
|
|
281
289
|
"diag_stage",
|
|
282
290
|
"worker_stage",
|
|
291
|
+
"dispatch_payload",
|
|
283
292
|
] as const) {
|
|
284
293
|
try {
|
|
285
294
|
await client.execute(`ALTER TABLE agent_runs ADD COLUMN ${col} TEXT`);
|
|
@@ -410,13 +419,22 @@ export async function insertRun(
|
|
|
410
419
|
id: string,
|
|
411
420
|
threadId: string,
|
|
412
421
|
turnId?: string,
|
|
413
|
-
options?: {
|
|
422
|
+
options?: {
|
|
423
|
+
dispatchMode?: "foreground" | "background";
|
|
424
|
+
/**
|
|
425
|
+
* JSON-serialized request body for a background dispatch. Persisted on the
|
|
426
|
+
* run row so the self-POST to the background function carries only the
|
|
427
|
+
* tiny `__backgroundRun` marker (Netlify caps background-function request
|
|
428
|
+
* bodies at 256KB); the worker rehydrates the body from this column.
|
|
429
|
+
*/
|
|
430
|
+
dispatchPayload?: string;
|
|
431
|
+
},
|
|
414
432
|
): Promise<void> {
|
|
415
433
|
await ensureRunTables();
|
|
416
434
|
const client = getDbExec();
|
|
417
435
|
const now = Date.now();
|
|
418
436
|
await client.execute({
|
|
419
|
-
sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at, turn_id, dispatch_mode) VALUES (?, ?, 'running', ?, ?, ?, ?, ?)`,
|
|
437
|
+
sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at, turn_id, dispatch_mode, dispatch_payload) VALUES (?, ?, 'running', ?, ?, ?, ?, ?, ?)`,
|
|
420
438
|
args: [
|
|
421
439
|
id,
|
|
422
440
|
threadId,
|
|
@@ -425,6 +443,7 @@ export async function insertRun(
|
|
|
425
443
|
now,
|
|
426
444
|
turnId ?? id,
|
|
427
445
|
options?.dispatchMode ?? null,
|
|
446
|
+
options?.dispatchPayload ?? null,
|
|
428
447
|
],
|
|
429
448
|
});
|
|
430
449
|
}
|
|
@@ -557,6 +576,95 @@ export async function readBackgroundRunClaim(runId: string): Promise<{
|
|
|
557
576
|
};
|
|
558
577
|
}
|
|
559
578
|
|
|
579
|
+
/**
|
|
580
|
+
* Read the persisted dispatch payload for a background-dispatched run. The
|
|
581
|
+
* worker rehydrates its request body from this column when the dispatch marker
|
|
582
|
+
* carries `payloadRef: true` (the self-POST itself stays under Netlify's 256KB
|
|
583
|
+
* background-function body cap). Returns null when the row is missing or the
|
|
584
|
+
* payload was already cleared (terminal run).
|
|
585
|
+
*/
|
|
586
|
+
export async function readRunDispatchPayload(
|
|
587
|
+
runId: string,
|
|
588
|
+
): Promise<string | null> {
|
|
589
|
+
await ensureRunTables();
|
|
590
|
+
const client = getDbExec();
|
|
591
|
+
const { rows } = await client.execute({
|
|
592
|
+
sql: `SELECT dispatch_payload FROM agent_runs WHERE id = ? LIMIT 1`,
|
|
593
|
+
args: [runId],
|
|
594
|
+
});
|
|
595
|
+
const row = rows?.[0] as { dispatch_payload?: string | null } | undefined;
|
|
596
|
+
if (!row) return null;
|
|
597
|
+
const payload = row.dispatch_payload;
|
|
598
|
+
return typeof payload === "string" && payload.length > 0 ? payload : null;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Clear a run's persisted dispatch payload once the worker has claimed and
|
|
603
|
+
* rehydrated it — the payload can be large (full chat history) and has no use
|
|
604
|
+
* after the handoff. Best-effort; terminal status writes also clear it.
|
|
605
|
+
*/
|
|
606
|
+
export async function clearRunDispatchPayload(runId: string): Promise<void> {
|
|
607
|
+
await ensureRunTables();
|
|
608
|
+
const client = getDbExec();
|
|
609
|
+
await client.execute({
|
|
610
|
+
sql: `UPDATE agent_runs SET dispatch_payload = NULL WHERE id = ?`,
|
|
611
|
+
args: [runId],
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* List background-dispatched runs that were never claimed by a worker within
|
|
617
|
+
* the unclaimed grace window. These are handoffs that were lost in flight —
|
|
618
|
+
* the async 202 (or the dispatching worker) died before any worker reached
|
|
619
|
+
* `claimBackgroundRun`. The periodic sweeper reaps them via
|
|
620
|
+
* `reapUnclaimedBackgroundRun` so a lost handoff becomes a loud, attributable
|
|
621
|
+
* error instead of a silent forever-hang. The foreground circuit-breaker
|
|
622
|
+
* already covers initial dispatches while the client is connected; this sweep
|
|
623
|
+
* exists for server-chained continuation handoffs, which have no foreground
|
|
624
|
+
* watching them.
|
|
625
|
+
*/
|
|
626
|
+
export async function listUnclaimedBackgroundRunIds(): Promise<string[]> {
|
|
627
|
+
await ensureRunTables();
|
|
628
|
+
const client = getDbExec();
|
|
629
|
+
const { rows } = await client.execute({
|
|
630
|
+
// CAST keeps the ms-epoch param 64-bit on Postgres (see
|
|
631
|
+
// backgroundAwareStaleCutoffSql for the int4-inference failure mode).
|
|
632
|
+
sql: `SELECT id FROM agent_runs
|
|
633
|
+
WHERE status = 'running'
|
|
634
|
+
AND dispatch_mode = 'background'
|
|
635
|
+
AND COALESCE(heartbeat_at, started_at) < (CAST(? AS BIGINT) - ${UNCLAIMED_BACKGROUND_RUN_GRACE_MS})`,
|
|
636
|
+
args: [Date.now()],
|
|
637
|
+
});
|
|
638
|
+
const ids: string[] = [];
|
|
639
|
+
for (const row of rows ?? []) {
|
|
640
|
+
const id = (row as { id?: unknown }).id;
|
|
641
|
+
if (typeof id === "string" && id) ids.push(id);
|
|
642
|
+
}
|
|
643
|
+
return ids;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Count how many runs (chunks) a logical turn has consumed so far. This is the
|
|
648
|
+
* durable per-turn recovery ledger: unlike the in-marker `continuationCount`
|
|
649
|
+
* (which resets whenever a fresh client POST starts a new chain for the same
|
|
650
|
+
* turn), the SQL count survives every recovery path, so it bounds pathological
|
|
651
|
+
* turn loops regardless of which layer initiated each chunk.
|
|
652
|
+
*/
|
|
653
|
+
export async function countRunsForTurn(
|
|
654
|
+
threadId: string,
|
|
655
|
+
turnId: string,
|
|
656
|
+
): Promise<number> {
|
|
657
|
+
await ensureRunTables();
|
|
658
|
+
const client = getDbExec();
|
|
659
|
+
const { rows } = await client.execute({
|
|
660
|
+
sql: `SELECT COUNT(*) AS run_count FROM agent_runs WHERE thread_id = ? AND turn_id = ?`,
|
|
661
|
+
args: [threadId, turnId],
|
|
662
|
+
});
|
|
663
|
+
const raw = (rows?.[0] as { run_count?: unknown } | undefined)?.run_count;
|
|
664
|
+
const count = Number(raw);
|
|
665
|
+
return Number.isFinite(count) ? count : 0;
|
|
666
|
+
}
|
|
667
|
+
|
|
560
668
|
/**
|
|
561
669
|
* Resolve the authenticated owner email for a run by joining it to its chat
|
|
562
670
|
* thread. The durable background worker's self-dispatch is cookieless
|
|
@@ -1027,7 +1135,9 @@ export async function updateRunStatus(
|
|
|
1027
1135
|
await ensureRunTables();
|
|
1028
1136
|
const client = getDbExec();
|
|
1029
1137
|
await client.execute({
|
|
1030
|
-
|
|
1138
|
+
// Terminal writes also drop the (potentially large) dispatch payload —
|
|
1139
|
+
// it only exists to rehydrate a not-yet-claimed background worker.
|
|
1140
|
+
sql: `UPDATE agent_runs SET status = ?, completed_at = ?, dispatch_payload = NULL WHERE id = ?`,
|
|
1031
1141
|
args: [status, Date.now(), runId],
|
|
1032
1142
|
});
|
|
1033
1143
|
}
|
|
@@ -1047,7 +1157,9 @@ export async function updateRunStatusIfRunning(
|
|
|
1047
1157
|
await ensureRunTables();
|
|
1048
1158
|
const client = getDbExec();
|
|
1049
1159
|
const { rowsAffected } = await client.execute({
|
|
1050
|
-
|
|
1160
|
+
// Terminal writes also drop the (potentially large) dispatch payload —
|
|
1161
|
+
// it only exists to rehydrate a not-yet-claimed background worker.
|
|
1162
|
+
sql: `UPDATE agent_runs SET status = ?, completed_at = ?, dispatch_payload = NULL WHERE id = ? AND status = 'running'`,
|
|
1051
1163
|
args: [status, Date.now(), runId],
|
|
1052
1164
|
});
|
|
1053
1165
|
return (rowsAffected ?? 0) > 0;
|
|
@@ -178,6 +178,19 @@ export interface AgentChatRequest {
|
|
|
178
178
|
* boundary and refuses to chain past `MAX_BACKGROUND_RUN_CONTINUATIONS`.
|
|
179
179
|
*/
|
|
180
180
|
continuationCount?: number;
|
|
181
|
+
/**
|
|
182
|
+
* True when the dispatcher expects the self-POST to land in a real
|
|
183
|
+
* Netlify `-background` function (15-min budget) rather than the ~60s
|
|
184
|
+
* synchronous function. See `shouldUseBackgroundFunctionTimeoutForWorker`.
|
|
185
|
+
*/
|
|
186
|
+
backgroundFunctionRuntimeExpected?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* True when the dispatch body carries ONLY this marker and the worker
|
|
189
|
+
* must rehydrate the full request body from the run row's
|
|
190
|
+
* `dispatch_payload` column (`readRunDispatchPayload`). Keeps the
|
|
191
|
+
* self-POST under Netlify's 256KB background-function body cap.
|
|
192
|
+
*/
|
|
193
|
+
payloadRef?: boolean;
|
|
181
194
|
};
|
|
182
195
|
/**
|
|
183
196
|
* Stable identity for the logical assistant turn this request belongs to.
|
|
@@ -163,6 +163,16 @@ export function RunStuckBanner({
|
|
|
163
163
|
}
|
|
164
164
|
const ownerId = autoRetryOwnerId ?? generatedOwnerIdRef.current;
|
|
165
165
|
const backgroundWorkerStillAlive = isFreshBackgroundWorker(state);
|
|
166
|
+
// Background-dispatched runs are recovered by the SERVER (chained
|
|
167
|
+
// continuation chunks + lost-handoff sweep); an automatic client abort
|
|
168
|
+
// would kill a live server-chained run. Auto-retry is therefore disabled
|
|
169
|
+
// unconditionally for ANY background dispatch mode — not just a
|
|
170
|
+
// fresh-heartbeat worker — and the localStorage/Web-Locks auto-retry claim
|
|
171
|
+
// below is never taken for these runs (the adapter's follow loop is
|
|
172
|
+
// read-only, so multiple tabs need no retry dedup). Only the manual banner
|
|
173
|
+
// remains, on the wider background threshold from useRunStuckDetection.
|
|
174
|
+
const isBackgroundDispatch =
|
|
175
|
+
state.dispatchMode?.startsWith("background") === true;
|
|
166
176
|
|
|
167
177
|
const lastReportedRef = useRef<{
|
|
168
178
|
isStuck: boolean;
|
|
@@ -202,6 +212,9 @@ export function RunStuckBanner({
|
|
|
202
212
|
useEffect(() => {
|
|
203
213
|
if (
|
|
204
214
|
!autoRetry ||
|
|
215
|
+
// Server owns recovery for background dispatch modes — never auto-abort
|
|
216
|
+
// (see comment on isBackgroundDispatch above).
|
|
217
|
+
isBackgroundDispatch ||
|
|
205
218
|
backgroundWorkerStillAlive ||
|
|
206
219
|
!state.isStuck ||
|
|
207
220
|
!state.runId ||
|
|
@@ -238,6 +251,7 @@ export function RunStuckBanner({
|
|
|
238
251
|
autoRetry,
|
|
239
252
|
backgroundWorkerStillAlive,
|
|
240
253
|
busy,
|
|
254
|
+
isBackgroundDispatch,
|
|
241
255
|
onRetry,
|
|
242
256
|
ownerId,
|
|
243
257
|
state.isStuck,
|