@agent-native/core 0.84.17 → 0.84.20
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 +1 -1
- package/corpus/core/CHANGELOG.md +19 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/run-store.ts +180 -13
- package/corpus/core/src/client/AssistantChat.tsx +49 -0
- package/corpus/core/src/client/active-run-state.ts +30 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +41 -3
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +133 -0
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +2 -2
- package/corpus/core/src/client/session-replay.ts +2 -2
- package/corpus/core/src/extensions/html-shell.ts +17 -3
- package/corpus/core/src/extensions/theme.ts +39 -0
- package/corpus/templates/analytics/actions/provider-api-request.ts +8 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +91 -33
- package/corpus/templates/analytics/changelog/2026-07-01-session-replay-recordings-upload-reliably-in-production.md +6 -0
- package/corpus/templates/analytics/server/handlers/session-replay.ts +46 -5
- package/corpus/templates/calendar/app/components/booking/TimeSlotPicker.tsx +10 -0
- package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +15 -6
- package/corpus/templates/calendar/app/components/calendar/GoogleSetupWizard.tsx +22 -0
- package/corpus/templates/calendar/app/hooks/use-bookings.ts +6 -2
- package/corpus/templates/calendar/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/calendar/app/i18n-data.ts +107 -0
- package/corpus/templates/calendar/app/lib/google-oauth-setup.ts +17 -0
- package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +9 -1
- package/corpus/templates/calendar/app/pages/BookingPage.tsx +40 -26
- package/corpus/templates/calendar/app/pages/Settings.tsx +3 -1
- package/corpus/templates/calendar/changelog/2026-07-01-booking-links-now-show-an-error-when-calendar-availability-c.md +6 -0
- package/corpus/templates/calendar/server/handlers/bookings.ts +78 -13
- package/corpus/templates/calendar/server/handlers/google-auth.ts +3 -2
- package/corpus/templates/calendar/server/lib/google-calendar.ts +16 -2
- package/corpus/templates/clips/changelog/2026-07-01-chrome-recording-uploads-now-serialize-chunks-to-avoid-resum.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +30 -23
- package/corpus/templates/design/app/lib/design-system-preview.ts +69 -0
- package/corpus/templates/design/app/pages/DesignSystems.tsx +71 -50
- package/corpus/templates/design/changelog/2026-07-01-design-systems-no-longer-crash-on-responsive-tokens.md +6 -0
- package/dist/agent/run-store.d.ts +19 -6
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +163 -13
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +36 -2
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/active-run-state.d.ts +3 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +24 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +32 -3
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +59 -2
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +2 -2
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/session-replay.js +2 -2
- package/dist/client/session-replay.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +17 -3
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/theme.d.ts +9 -0
- package/dist/extensions/theme.d.ts.map +1 -1
- package/dist/extensions/theme.js +38 -0
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +8 -8
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/package.json +1 -1
package/dist/agent/run-store.js
CHANGED
|
@@ -25,6 +25,8 @@ export const RUN_STALE_MS = 15_000;
|
|
|
25
25
|
* With the normal 15s window the reaper would falsely kill that freshly-
|
|
26
26
|
* inserted-but-not-yet-heartbeaten row. 90s tolerates a slow background
|
|
27
27
|
* cold-start while still reaping a genuinely dead background worker promptly.
|
|
28
|
+
* Claimed background workers heartbeat during long work; the stale watchdog is a
|
|
29
|
+
* liveness timeout, not the Netlify background-function execution budget.
|
|
28
30
|
*
|
|
29
31
|
* Only applied to rows explicitly marked background-dispatched; ordinary
|
|
30
32
|
* foreground runs keep the tight 15s window unchanged.
|
|
@@ -71,13 +73,14 @@ export const CLAIMED_BACKGROUND_WORKER_FAILED_ERROR_EVENT = {
|
|
|
71
73
|
* Grace period before a never-claimed background run (dispatch_mode still
|
|
72
74
|
* 'background', no worker claim) is treated as a dead handoff and reaped.
|
|
73
75
|
*
|
|
74
|
-
* This is intentionally
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* has, by definition, NO worker — nothing
|
|
76
|
+
* This is intentionally tighter than `BACKGROUND_RUN_STALE_MS`. That wider
|
|
77
|
+
* window protects cold-starting or temporarily delayed background dispatches,
|
|
78
|
+
* while claimed workers stay alive by heartbeat/progress updates. A run that is
|
|
79
|
+
* still `dispatch_mode = 'background'` has, by definition, NO worker — nothing
|
|
80
|
+
* to protect — so once a Netlify
|
|
78
81
|
* background function has had a reasonable cold-start window to claim it and
|
|
79
82
|
* hasn't, the handoff is dead and should surface promptly instead of leaving
|
|
80
|
-
* the user staring at a spinner for
|
|
83
|
+
* the user staring at a spinner for the durable-worker window. 25s comfortably exceeds a normal
|
|
81
84
|
* Netlify Lambda cold start while still failing fast on a silent worker death.
|
|
82
85
|
*/
|
|
83
86
|
export const UNCLAIMED_BACKGROUND_RUN_GRACE_MS = 25_000;
|
|
@@ -109,6 +112,7 @@ async function ensureRunTables() {
|
|
|
109
112
|
CREATE TABLE IF NOT EXISTS agent_run_events (
|
|
110
113
|
run_id TEXT NOT NULL,
|
|
111
114
|
seq ${intType()} NOT NULL,
|
|
115
|
+
event_at ${intType()},
|
|
112
116
|
event_data TEXT NOT NULL,
|
|
113
117
|
PRIMARY KEY (run_id, seq)
|
|
114
118
|
)
|
|
@@ -179,6 +183,7 @@ async function ensureRunTables() {
|
|
|
179
183
|
await ensureColumnExists("agent_runs", col, `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS ${col} ${colType}`);
|
|
180
184
|
}
|
|
181
185
|
await ensureTableExists("agent_run_events", agentRunEventsCreateSql);
|
|
186
|
+
await ensureColumnExists("agent_run_events", "event_at", `ALTER TABLE agent_run_events ADD COLUMN IF NOT EXISTS event_at ${intType()}`);
|
|
182
187
|
await ensureTableExists("agent_tool_ledger", agentToolLedgerCreateSql);
|
|
183
188
|
// Widen millisecond-timestamp columns that older deployments created as
|
|
184
189
|
// 32-bit `INTEGER`. `insertRun()` writes `Date.now()` into `started_at`
|
|
@@ -192,6 +197,7 @@ async function ensureRunTables() {
|
|
|
192
197
|
"heartbeat_at",
|
|
193
198
|
"last_progress_at",
|
|
194
199
|
]);
|
|
200
|
+
await widenIntColumnsToBigInt("agent_run_events", ["event_at"]);
|
|
195
201
|
await widenIntColumnsToBigInt("agent_tool_ledger", ["completed_at"]);
|
|
196
202
|
return;
|
|
197
203
|
}
|
|
@@ -254,6 +260,12 @@ async function ensureRunTables() {
|
|
|
254
260
|
}
|
|
255
261
|
}
|
|
256
262
|
await client.execute(agentRunEventsCreateSql);
|
|
263
|
+
try {
|
|
264
|
+
await client.execute(`ALTER TABLE agent_run_events ADD COLUMN event_at ${intType()}`);
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Column already exists — ignore
|
|
268
|
+
}
|
|
257
269
|
await client.execute(agentToolLedgerCreateSql);
|
|
258
270
|
// Widen millisecond-timestamp columns that older deployments created as
|
|
259
271
|
// 32-bit `INTEGER`. `insertRun()` writes `Date.now()` into `started_at`
|
|
@@ -267,6 +279,7 @@ async function ensureRunTables() {
|
|
|
267
279
|
"heartbeat_at",
|
|
268
280
|
"last_progress_at",
|
|
269
281
|
]);
|
|
282
|
+
await widenIntColumnsToBigInt("agent_run_events", ["event_at"]);
|
|
270
283
|
await widenIntColumnsToBigInt("agent_tool_ledger", ["completed_at"]);
|
|
271
284
|
})().catch((err) => {
|
|
272
285
|
// Retry init on the next call after a failed startup.
|
|
@@ -390,6 +403,19 @@ function backgroundAwareStaleCutoffSql() {
|
|
|
390
403
|
// overflows int4. The cast keeps the subtraction 64-bit; a no-op on SQLite.
|
|
391
404
|
return `(CAST(? AS BIGINT) - CASE WHEN dispatch_mode LIKE 'background%' THEN ${BACKGROUND_RUN_STALE_MS} ELSE ${RUN_STALE_MS} END)`;
|
|
392
405
|
}
|
|
406
|
+
function terminalRunEventExclusionSql(runIdColumn = "id") {
|
|
407
|
+
return `NOT EXISTS (
|
|
408
|
+
SELECT 1 FROM agent_run_events terminal_events
|
|
409
|
+
WHERE terminal_events.run_id = agent_runs.${runIdColumn}
|
|
410
|
+
AND (
|
|
411
|
+
terminal_events.event_data LIKE '{"type":"done"%'
|
|
412
|
+
OR terminal_events.event_data LIKE '{"type":"error"%'
|
|
413
|
+
OR terminal_events.event_data LIKE '{"type":"missing_api_key"%'
|
|
414
|
+
OR terminal_events.event_data LIKE '{"type":"loop_limit"%'
|
|
415
|
+
OR terminal_events.event_data LIKE '{"type":"auto_continue"%'
|
|
416
|
+
)
|
|
417
|
+
)`;
|
|
418
|
+
}
|
|
393
419
|
/**
|
|
394
420
|
* Liveness basis for the stale reapers: the MOST RECENT of `heartbeat_at`
|
|
395
421
|
* ("process is up", bumped on a 1.5s timer) and `last_progress_at` ("real work
|
|
@@ -511,6 +537,7 @@ export async function tryClaimRunSlot(threadId, maxStaleMs) {
|
|
|
511
537
|
sql: `SELECT id FROM agent_runs
|
|
512
538
|
WHERE thread_id = ?
|
|
513
539
|
AND status = 'running'
|
|
540
|
+
AND ${terminalRunEventExclusionSql()}
|
|
514
541
|
AND COALESCE(heartbeat_at, started_at) >= ?
|
|
515
542
|
ORDER BY started_at DESC LIMIT 1`,
|
|
516
543
|
args: [threadId, heartbeatCutoff],
|
|
@@ -524,6 +551,7 @@ export async function tryClaimRunSlot(threadId, maxStaleMs) {
|
|
|
524
551
|
sql: `SELECT id FROM agent_runs
|
|
525
552
|
WHERE thread_id = ?
|
|
526
553
|
AND status = 'running'
|
|
554
|
+
AND ${terminalRunEventExclusionSql()}
|
|
527
555
|
AND COALESCE(heartbeat_at, started_at) >= ${backgroundAwareStaleCutoffSql()}
|
|
528
556
|
ORDER BY started_at DESC LIMIT 1`,
|
|
529
557
|
args: [threadId, now],
|
|
@@ -578,6 +606,101 @@ export async function setRunTerminalReason(runId, terminalReason) {
|
|
|
578
606
|
// Diagnostics are best-effort; never let them break completion.
|
|
579
607
|
}
|
|
580
608
|
}
|
|
609
|
+
function terminalStatusForEvent(event) {
|
|
610
|
+
if (event.type === "error")
|
|
611
|
+
return "errored";
|
|
612
|
+
if (event.type === "done" ||
|
|
613
|
+
event.type === "missing_api_key" ||
|
|
614
|
+
event.type === "loop_limit" ||
|
|
615
|
+
event.type === "auto_continue") {
|
|
616
|
+
return "completed";
|
|
617
|
+
}
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
function terminalReasonForEvent(event) {
|
|
621
|
+
if (event.type === "auto_continue")
|
|
622
|
+
return event.reason || "auto_continue";
|
|
623
|
+
if (event.type === "loop_limit")
|
|
624
|
+
return "loop_limit";
|
|
625
|
+
if (event.type === "missing_api_key")
|
|
626
|
+
return "missing_api_key";
|
|
627
|
+
if (event.type === "error")
|
|
628
|
+
return `error:${event.errorCode || "unknown"}`;
|
|
629
|
+
if (event.type === "done")
|
|
630
|
+
return "done";
|
|
631
|
+
return null;
|
|
632
|
+
}
|
|
633
|
+
async function getLatestRunEvent(runId) {
|
|
634
|
+
const client = getDbExec();
|
|
635
|
+
const { rows } = await client.execute({
|
|
636
|
+
sql: `SELECT seq, event_data, event_at FROM agent_run_events WHERE run_id = ? ORDER BY seq DESC LIMIT 1`,
|
|
637
|
+
args: [runId],
|
|
638
|
+
});
|
|
639
|
+
const row = rows[0];
|
|
640
|
+
const raw = row?.event_data;
|
|
641
|
+
if (!raw)
|
|
642
|
+
return null;
|
|
643
|
+
try {
|
|
644
|
+
const eventAt = row.event_at == null ? NaN : Number(row.event_at);
|
|
645
|
+
return {
|
|
646
|
+
event: JSON.parse(raw),
|
|
647
|
+
eventAt: Number.isFinite(eventAt) && eventAt > 0 ? eventAt : null,
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
catch {
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Repair a run whose terminal event was durably appended but whose final
|
|
656
|
+
* `agent_runs.status` write lost a race with reconnect/reaper code.
|
|
657
|
+
*
|
|
658
|
+
* The event ledger is the durable transcript users see. If its latest event is
|
|
659
|
+
* terminal, the run is no longer alive and must not be converted into a stale
|
|
660
|
+
* error later. This keeps `agent_runs` and `agent_run_events` from telling two
|
|
661
|
+
* different stories after delayed DB writes or background function teardown.
|
|
662
|
+
*/
|
|
663
|
+
export async function reconcileTerminalRunFromEvents(runId) {
|
|
664
|
+
await ensureRunTables();
|
|
665
|
+
const latest = await getLatestRunEvent(runId);
|
|
666
|
+
if (!latest)
|
|
667
|
+
return false;
|
|
668
|
+
const status = terminalStatusForEvent(latest.event);
|
|
669
|
+
const terminalReason = terminalReasonForEvent(latest.event);
|
|
670
|
+
if (!status || !terminalReason)
|
|
671
|
+
return false;
|
|
672
|
+
const client = getDbExec();
|
|
673
|
+
const errorCode = latest.event.type === "error" ? (latest.event.errorCode ?? null) : null;
|
|
674
|
+
const errorDetail = latest.event.type === "error"
|
|
675
|
+
? (latest.event.details || latest.event.error || "").slice(0, 2000) ||
|
|
676
|
+
null
|
|
677
|
+
: null;
|
|
678
|
+
const { rowsAffected } = await client.execute({
|
|
679
|
+
sql: `UPDATE agent_runs
|
|
680
|
+
SET status = ?,
|
|
681
|
+
completed_at = COALESCE(completed_at, ?, ${livenessBasisSql()}),
|
|
682
|
+
error_code = CASE WHEN ? IS NOT NULL THEN ? ELSE error_code END,
|
|
683
|
+
error_detail = CASE WHEN ? IS NOT NULL THEN ? ELSE error_detail END,
|
|
684
|
+
terminal_reason = COALESCE(terminal_reason, ?)
|
|
685
|
+
WHERE id = ?
|
|
686
|
+
AND (
|
|
687
|
+
status = 'running'
|
|
688
|
+
OR (status = 'errored' AND error_code = ?)
|
|
689
|
+
)`,
|
|
690
|
+
args: [
|
|
691
|
+
status,
|
|
692
|
+
latest.eventAt,
|
|
693
|
+
errorCode,
|
|
694
|
+
errorCode,
|
|
695
|
+
errorDetail,
|
|
696
|
+
errorDetail,
|
|
697
|
+
terminalReason,
|
|
698
|
+
runId,
|
|
699
|
+
STALE_RUN_ERROR_EVENT.errorCode,
|
|
700
|
+
],
|
|
701
|
+
});
|
|
702
|
+
return (rowsAffected ?? 0) > 0;
|
|
703
|
+
}
|
|
581
704
|
/**
|
|
582
705
|
* Diagnostic stage names recorded onto a background run as it moves through the
|
|
583
706
|
* `_process-run` worker pipeline. Each value is the LAST stage successfully
|
|
@@ -695,6 +818,8 @@ export async function bumpRunProgress(runId) {
|
|
|
695
818
|
*/
|
|
696
819
|
export async function reapIfStale(runId, maxStaleMs) {
|
|
697
820
|
await ensureRunTables();
|
|
821
|
+
if (await reconcileTerminalRunFromEvents(runId))
|
|
822
|
+
return false;
|
|
698
823
|
const client = getDbExec();
|
|
699
824
|
const completedAt = Date.now();
|
|
700
825
|
// Background-dispatched runs get the wider stale window so a slow cold-start
|
|
@@ -713,6 +838,7 @@ export async function reapIfStale(runId, maxStaleMs) {
|
|
|
713
838
|
terminal_reason = ?
|
|
714
839
|
WHERE id = ?
|
|
715
840
|
AND status = 'running'
|
|
841
|
+
AND ${terminalRunEventExclusionSql()}
|
|
716
842
|
AND ${staleClause}`,
|
|
717
843
|
args: [
|
|
718
844
|
completedAt,
|
|
@@ -724,6 +850,8 @@ export async function reapIfStale(runId, maxStaleMs) {
|
|
|
724
850
|
],
|
|
725
851
|
});
|
|
726
852
|
const reaped = (rowsAffected ?? 0) > 0;
|
|
853
|
+
if (!reaped && (await reconcileTerminalRunFromEvents(runId)))
|
|
854
|
+
return false;
|
|
727
855
|
if (reaped) {
|
|
728
856
|
await safeAppendTerminalRunEvent(runId, STALE_RUN_ERROR_EVENT, "reap-if-stale");
|
|
729
857
|
}
|
|
@@ -737,7 +865,7 @@ export async function reapIfStale(runId, maxStaleMs) {
|
|
|
737
865
|
* before it can claim), the row stays `background`, never heartbeats again, and
|
|
738
866
|
* — because dispatch returned 202 — the foreground already returned the SSE
|
|
739
867
|
* stream, so the existing fast-fail inline fallback never engaged. The run would
|
|
740
|
-
* otherwise hang for the full
|
|
868
|
+
* otherwise hang for the full durable background window and then error opaquely.
|
|
741
869
|
*
|
|
742
870
|
* This reaps such a run EARLY and DISTINCTLY: a row that is still unclaimed
|
|
743
871
|
* (`dispatch_mode = 'background'`) past the tight `UNCLAIMED_BACKGROUND_RUN_GRACE_MS`
|
|
@@ -858,8 +986,8 @@ export async function insertRunEvent(runId, seq, eventData) {
|
|
|
858
986
|
// run aborts at the same time the producer emits its final event.
|
|
859
987
|
// Treat the second write as a no-op so the run completes cleanly.
|
|
860
988
|
await client.execute({
|
|
861
|
-
sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
|
|
862
|
-
args: [runId, seq, eventData],
|
|
989
|
+
sql: `INSERT INTO agent_run_events (run_id, seq, event_at, event_data) VALUES (?, ?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
|
|
990
|
+
args: [runId, seq, Date.now(), eventData],
|
|
863
991
|
});
|
|
864
992
|
}
|
|
865
993
|
export async function getRunEventsSince(runId, fromSeq) {
|
|
@@ -895,12 +1023,18 @@ export async function getRunByThread(threadId, options) {
|
|
|
895
1023
|
await ensureRunTables();
|
|
896
1024
|
const client = getDbExec();
|
|
897
1025
|
const sql = options?.includeTerminal
|
|
898
|
-
? `SELECT id, thread_id, turn_id, status, started_at, heartbeat_at, completed_at, last_progress_at, dispatch_mode, terminal_reason, diag_stage FROM agent_runs WHERE thread_id = ? ORDER BY started_at DESC LIMIT 1`
|
|
899
|
-
: `SELECT id, thread_id, turn_id, status, started_at, heartbeat_at, completed_at, last_progress_at, dispatch_mode, terminal_reason, diag_stage FROM agent_runs WHERE thread_id = ? AND status = 'running' ORDER BY started_at DESC LIMIT 1`;
|
|
1026
|
+
? `SELECT id, thread_id, turn_id, status, started_at, heartbeat_at, completed_at, last_progress_at, dispatch_mode, terminal_reason, diag_stage, error_code FROM agent_runs WHERE thread_id = ? ORDER BY started_at DESC LIMIT 1`
|
|
1027
|
+
: `SELECT id, thread_id, turn_id, status, started_at, heartbeat_at, completed_at, last_progress_at, dispatch_mode, terminal_reason, diag_stage, error_code FROM agent_runs WHERE thread_id = ? AND status = 'running' ORDER BY started_at DESC LIMIT 1`;
|
|
900
1028
|
const { rows } = await client.execute({ sql, args: [threadId] });
|
|
901
1029
|
if (rows.length === 0)
|
|
902
1030
|
return null;
|
|
903
1031
|
const r = rows[0];
|
|
1032
|
+
const canReconcileFromEvents = r.status === "running" ||
|
|
1033
|
+
(r.status === "errored" &&
|
|
1034
|
+
r.error_code === STALE_RUN_ERROR_EVENT.errorCode);
|
|
1035
|
+
if (canReconcileFromEvents && (await reconcileTerminalRunFromEvents(r.id))) {
|
|
1036
|
+
return getRunByThread(threadId, options);
|
|
1037
|
+
}
|
|
904
1038
|
return {
|
|
905
1039
|
id: r.id,
|
|
906
1040
|
threadId: r.thread_id,
|
|
@@ -1018,6 +1152,12 @@ export async function reapAllStaleRuns() {
|
|
|
1018
1152
|
AND ${livenessBasisSql()} < ${backgroundAwareStaleCutoffSql()}`,
|
|
1019
1153
|
args: [now],
|
|
1020
1154
|
});
|
|
1155
|
+
for (const row of stale.rows) {
|
|
1156
|
+
const id = row.id;
|
|
1157
|
+
if (typeof id === "string") {
|
|
1158
|
+
await reconcileTerminalRunFromEvents(id);
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1021
1161
|
const completedAt = Date.now();
|
|
1022
1162
|
const { rowsAffected } = await client.execute({
|
|
1023
1163
|
sql: `UPDATE agent_runs
|
|
@@ -1027,6 +1167,7 @@ export async function reapAllStaleRuns() {
|
|
|
1027
1167
|
error_detail = ?,
|
|
1028
1168
|
terminal_reason = ?
|
|
1029
1169
|
WHERE status = 'running'
|
|
1170
|
+
AND ${terminalRunEventExclusionSql()}
|
|
1030
1171
|
AND ${livenessBasisSql()} < ${backgroundAwareStaleCutoffSql()}`,
|
|
1031
1172
|
args: [
|
|
1032
1173
|
completedAt,
|
|
@@ -1069,6 +1210,12 @@ export async function cleanupOldRuns(olderThanMs, erroredOlderThanMs) {
|
|
|
1069
1210
|
)`,
|
|
1070
1211
|
args: [now, cutoff],
|
|
1071
1212
|
});
|
|
1213
|
+
for (const row of stale.rows) {
|
|
1214
|
+
const id = row.id;
|
|
1215
|
+
if (typeof id === "string") {
|
|
1216
|
+
await reconcileTerminalRunFromEvents(id);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1072
1219
|
const completedAt = Date.now();
|
|
1073
1220
|
await client.execute({
|
|
1074
1221
|
sql: `UPDATE agent_runs
|
|
@@ -1077,7 +1224,9 @@ export async function cleanupOldRuns(olderThanMs, erroredOlderThanMs) {
|
|
|
1077
1224
|
error_code = ?,
|
|
1078
1225
|
error_detail = ?,
|
|
1079
1226
|
terminal_reason = ?
|
|
1080
|
-
WHERE status = 'running'
|
|
1227
|
+
WHERE status = 'running'
|
|
1228
|
+
AND ${terminalRunEventExclusionSql()}
|
|
1229
|
+
AND started_at < ?`,
|
|
1081
1230
|
args: [
|
|
1082
1231
|
completedAt,
|
|
1083
1232
|
STALE_RUN_ERROR_EVENT.errorCode,
|
|
@@ -1096,6 +1245,7 @@ export async function cleanupOldRuns(olderThanMs, erroredOlderThanMs) {
|
|
|
1096
1245
|
error_detail = ?,
|
|
1097
1246
|
terminal_reason = ?
|
|
1098
1247
|
WHERE status = 'running'
|
|
1248
|
+
AND ${terminalRunEventExclusionSql()}
|
|
1099
1249
|
AND ${livenessBasisSql()} < ${backgroundAwareStaleCutoffSql()}`,
|
|
1100
1250
|
args: [
|
|
1101
1251
|
completedAt,
|
|
@@ -1242,8 +1392,8 @@ async function appendTerminalRunEvent(runId, event) {
|
|
|
1242
1392
|
}
|
|
1243
1393
|
const nextSeq = last ? Number(last.seq ?? -1) + 1 : 0;
|
|
1244
1394
|
await client.execute({
|
|
1245
|
-
sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
|
|
1246
|
-
args: [runId, nextSeq, JSON.stringify(event)],
|
|
1395
|
+
sql: `INSERT INTO agent_run_events (run_id, seq, event_at, event_data) VALUES (?, ?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
|
|
1396
|
+
args: [runId, nextSeq, Date.now(), JSON.stringify(event)],
|
|
1247
1397
|
});
|
|
1248
1398
|
}
|
|
1249
1399
|
//# sourceMappingURL=run-store.js.map
|