@agent-native/core 0.13.1 → 0.14.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.
Files changed (78) hide show
  1. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  2. package/dist/agent/engine/builder-engine.js +5 -1
  3. package/dist/agent/engine/builder-engine.js.map +1 -1
  4. package/dist/agent/production-agent.d.ts +23 -1
  5. package/dist/agent/production-agent.d.ts.map +1 -1
  6. package/dist/agent/production-agent.js +82 -1
  7. package/dist/agent/production-agent.js.map +1 -1
  8. package/dist/agent/run-loop-with-resume.d.ts +45 -0
  9. package/dist/agent/run-loop-with-resume.d.ts.map +1 -0
  10. package/dist/agent/run-loop-with-resume.js +121 -0
  11. package/dist/agent/run-loop-with-resume.js.map +1 -0
  12. package/dist/agent/run-store.d.ts.map +1 -1
  13. package/dist/agent/run-store.js +8 -2
  14. package/dist/agent/run-store.js.map +1 -1
  15. package/dist/agent/types.d.ts +1 -1
  16. package/dist/agent/types.d.ts.map +1 -1
  17. package/dist/agent/types.js.map +1 -1
  18. package/dist/client/AssistantChat.d.ts.map +1 -1
  19. package/dist/client/AssistantChat.js +8 -45
  20. package/dist/client/AssistantChat.js.map +1 -1
  21. package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
  22. package/dist/client/ConnectBuilderCard.js +24 -0
  23. package/dist/client/ConnectBuilderCard.js.map +1 -1
  24. package/dist/client/analytics.d.ts.map +1 -1
  25. package/dist/client/analytics.js +10 -1
  26. package/dist/client/analytics.js.map +1 -1
  27. package/dist/client/extensions/ExtensionsSidebarSection.js +1 -1
  28. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  29. package/dist/client/use-chat-threads.d.ts +0 -6
  30. package/dist/client/use-chat-threads.d.ts.map +1 -1
  31. package/dist/client/use-chat-threads.js +40 -52
  32. package/dist/client/use-chat-threads.js.map +1 -1
  33. package/dist/client/use-db-sync.d.ts.map +1 -1
  34. package/dist/client/use-db-sync.js +3 -1
  35. package/dist/client/use-db-sync.js.map +1 -1
  36. package/dist/db/client.d.ts.map +1 -1
  37. package/dist/db/client.js +9 -0
  38. package/dist/db/client.js.map +1 -1
  39. package/dist/db/create-get-db.d.ts.map +1 -1
  40. package/dist/db/create-get-db.js +7 -0
  41. package/dist/db/create-get-db.js.map +1 -1
  42. package/dist/extensions/actions.js +1 -1
  43. package/dist/extensions/actions.js.map +1 -1
  44. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  45. package/dist/extensions/fetch-tool.js +46 -5
  46. package/dist/extensions/fetch-tool.js.map +1 -1
  47. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  48. package/dist/server/agent-chat-plugin.js +82 -75
  49. package/dist/server/agent-chat-plugin.js.map +1 -1
  50. package/dist/server/agent-discovery.d.ts +21 -0
  51. package/dist/server/agent-discovery.d.ts.map +1 -1
  52. package/dist/server/agent-discovery.js +18 -3
  53. package/dist/server/agent-discovery.js.map +1 -1
  54. package/dist/server/auth.d.ts +27 -0
  55. package/dist/server/auth.d.ts.map +1 -1
  56. package/dist/server/auth.js +71 -12
  57. package/dist/server/auth.js.map +1 -1
  58. package/dist/server/better-auth-instance.js +13 -0
  59. package/dist/server/better-auth-instance.js.map +1 -1
  60. package/dist/server/google-auth-mode.d.ts +20 -0
  61. package/dist/server/google-auth-mode.d.ts.map +1 -0
  62. package/dist/server/google-auth-mode.js +20 -0
  63. package/dist/server/google-auth-mode.js.map +1 -0
  64. package/dist/server/google-auth-plugin.d.ts +7 -0
  65. package/dist/server/google-auth-plugin.d.ts.map +1 -1
  66. package/dist/server/google-auth-plugin.js +21 -5
  67. package/dist/server/google-auth-plugin.js.map +1 -1
  68. package/dist/server/index.d.ts +1 -0
  69. package/dist/server/index.d.ts.map +1 -1
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/server/onboarding-html.d.ts +7 -0
  72. package/dist/server/onboarding-html.d.ts.map +1 -1
  73. package/dist/server/onboarding-html.js +22 -3
  74. package/dist/server/onboarding-html.js.map +1 -1
  75. package/dist/server/sentry.d.ts.map +1 -1
  76. package/dist/server/sentry.js +41 -0
  77. package/dist/server/sentry.js.map +1 -1
  78. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Wraps `runAgentLoop` with two layered recovery mechanisms so a single hosted
3
+ * invocation can survive interruptions without showing the user a dead chat:
4
+ *
5
+ * 1. **Soft timeout** — an inner timer that aborts the LLM call before the
6
+ * hosting function's hard limit (Lambda 75s, Vercel 60s, etc.) so we have a
7
+ * chance to gracefully wind down and append a continuation nudge. Without
8
+ * this the function gets killed mid-stream and the user sees a frozen
9
+ * spinner.
10
+ *
11
+ * 2. **Resumable-error continuation** — when the LLM call errors with a
12
+ * transport- or gateway-level interruption (Builder gateway 45s timeout,
13
+ * socket hang up, ECONNRESET, upstream 5xx that survived engine retries),
14
+ * we save the conversation prefix, append a "continue from where you left
15
+ * off" message, and run another LLM call. Anthropic's prompt cache makes
16
+ * the resume call dramatically faster than the cold first attempt, and the
17
+ * agent gets explicit context that it was cut off so it doesn't re-do
18
+ * completed work.
19
+ *
20
+ * Both paths route through `appendAgentLoopContinuation` so the agent sees a
21
+ * uniform "continue" instruction regardless of which recovery fired.
22
+ */
23
+ import { runAgentLoop } from "./production-agent.js";
24
+ /**
25
+ * Cap on continuation iterations inside a single
26
+ * `runAgentLoopDirectWithSoftTimeout` invocation. The host's hard function
27
+ * timeout usually bounds this naturally — but a defensive cap prevents an
28
+ * instant-error spiral from looping forever inside hosting environments with a
29
+ * generous budget.
30
+ *
31
+ * 6 leaves room for: 1 normal completion + a few resume rounds for design
32
+ * generation (prompt + 3 variants ≈ 4 LLM calls), with a small safety margin.
33
+ */
34
+ export declare const MAX_RUN_LOOP_CONTINUATIONS = 6;
35
+ /**
36
+ * Internal entry point used by the agent-chat plugin's run handler. Wraps
37
+ * `runAgentLoop` with soft-timeout + resumable-error continuation recovery.
38
+ *
39
+ * The `softTimeoutMs` argument falls back to `resolveRunSoftTimeoutMs(...)` so
40
+ * different hosting environments (Lambda, Vercel, Cloudflare, local dev) get
41
+ * an appropriate inner budget. Setting it to <= 0 disables both layers — the
42
+ * call goes straight to `runAgentLoop` with no wrapping.
43
+ */
44
+ export declare function runAgentLoopDirectWithSoftTimeout(opts: Parameters<typeof runAgentLoop>[0], softTimeoutMs?: number): Promise<Awaited<ReturnType<typeof runAgentLoop>>>;
45
+ //# sourceMappingURL=run-loop-with-resume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-loop-with-resume.d.ts","sourceRoot":"","sources":["../../src/agent/run-loop-with-resume.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EACL,YAAY,EAIb,MAAM,uBAAuB,CAAC;AAG/B;;;;;;;;;GASG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAE5C;;;;;;;;GAQG;AACH,wBAAsB,iCAAiC,CACrD,IAAI,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,EACxC,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CA+EnD"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Wraps `runAgentLoop` with two layered recovery mechanisms so a single hosted
3
+ * invocation can survive interruptions without showing the user a dead chat:
4
+ *
5
+ * 1. **Soft timeout** — an inner timer that aborts the LLM call before the
6
+ * hosting function's hard limit (Lambda 75s, Vercel 60s, etc.) so we have a
7
+ * chance to gracefully wind down and append a continuation nudge. Without
8
+ * this the function gets killed mid-stream and the user sees a frozen
9
+ * spinner.
10
+ *
11
+ * 2. **Resumable-error continuation** — when the LLM call errors with a
12
+ * transport- or gateway-level interruption (Builder gateway 45s timeout,
13
+ * socket hang up, ECONNRESET, upstream 5xx that survived engine retries),
14
+ * we save the conversation prefix, append a "continue from where you left
15
+ * off" message, and run another LLM call. Anthropic's prompt cache makes
16
+ * the resume call dramatically faster than the cold first attempt, and the
17
+ * agent gets explicit context that it was cut off so it doesn't re-do
18
+ * completed work.
19
+ *
20
+ * Both paths route through `appendAgentLoopContinuation` so the agent sees a
21
+ * uniform "continue" instruction regardless of which recovery fired.
22
+ */
23
+ import { runAgentLoop, appendAgentLoopContinuation, isResumableEngineError, continuationReasonForResumableError, } from "./production-agent.js";
24
+ import { resolveRunSoftTimeoutMs } from "./run-manager.js";
25
+ /**
26
+ * Cap on continuation iterations inside a single
27
+ * `runAgentLoopDirectWithSoftTimeout` invocation. The host's hard function
28
+ * timeout usually bounds this naturally — but a defensive cap prevents an
29
+ * instant-error spiral from looping forever inside hosting environments with a
30
+ * generous budget.
31
+ *
32
+ * 6 leaves room for: 1 normal completion + a few resume rounds for design
33
+ * generation (prompt + 3 variants ≈ 4 LLM calls), with a small safety margin.
34
+ */
35
+ export const MAX_RUN_LOOP_CONTINUATIONS = 6;
36
+ /**
37
+ * Internal entry point used by the agent-chat plugin's run handler. Wraps
38
+ * `runAgentLoop` with soft-timeout + resumable-error continuation recovery.
39
+ *
40
+ * The `softTimeoutMs` argument falls back to `resolveRunSoftTimeoutMs(...)` so
41
+ * different hosting environments (Lambda, Vercel, Cloudflare, local dev) get
42
+ * an appropriate inner budget. Setting it to <= 0 disables both layers — the
43
+ * call goes straight to `runAgentLoop` with no wrapping.
44
+ */
45
+ export async function runAgentLoopDirectWithSoftTimeout(opts, softTimeoutMs) {
46
+ const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs);
47
+ if (timeoutMs <= 0)
48
+ return runAgentLoop(opts);
49
+ const upstreamSignal = opts.signal;
50
+ const usage = {
51
+ inputTokens: 0,
52
+ outputTokens: 0,
53
+ cacheReadTokens: 0,
54
+ cacheWriteTokens: 0,
55
+ model: opts.model,
56
+ };
57
+ const addUsage = (next) => {
58
+ usage.inputTokens += next.inputTokens;
59
+ usage.outputTokens += next.outputTokens;
60
+ usage.cacheReadTokens += next.cacheReadTokens;
61
+ usage.cacheWriteTokens += next.cacheWriteTokens;
62
+ usage.model = next.model;
63
+ };
64
+ let attempts = 0;
65
+ while (!upstreamSignal.aborted && attempts < MAX_RUN_LOOP_CONTINUATIONS) {
66
+ attempts++;
67
+ const controller = new AbortController();
68
+ const abortFromUpstream = () => controller.abort();
69
+ if (upstreamSignal.aborted) {
70
+ controller.abort();
71
+ }
72
+ else {
73
+ upstreamSignal.addEventListener("abort", abortFromUpstream, {
74
+ once: true,
75
+ });
76
+ }
77
+ let softTimedOut = false;
78
+ const timer = setTimeout(() => {
79
+ if (controller.signal.aborted)
80
+ return;
81
+ softTimedOut = true;
82
+ controller.abort();
83
+ }, timeoutMs);
84
+ try {
85
+ const nextUsage = await runAgentLoop({
86
+ ...opts,
87
+ signal: controller.signal,
88
+ });
89
+ addUsage(nextUsage);
90
+ if (softTimedOut && !upstreamSignal.aborted) {
91
+ appendAgentLoopContinuation(opts.messages, "run_timeout");
92
+ continue;
93
+ }
94
+ return usage;
95
+ }
96
+ catch (err) {
97
+ if (softTimedOut && !upstreamSignal.aborted) {
98
+ appendAgentLoopContinuation(opts.messages, "run_timeout");
99
+ continue;
100
+ }
101
+ // Resumable transport / gateway interruptions: the LLM call was cut off
102
+ // mid-stream (gateway 45s timeout, socket hang up, function-level
103
+ // timeout that didn't trip our soft timer first). Treat it the same way
104
+ // as a soft timeout — append a "continue from where you left off" nudge
105
+ // and let the loop run another LLM call. The conversation prefix up to
106
+ // the cut-off is preserved in opts.messages, and Anthropic's prompt
107
+ // cache makes the resume call much faster.
108
+ if (!upstreamSignal.aborted && isResumableEngineError(err)) {
109
+ appendAgentLoopContinuation(opts.messages, continuationReasonForResumableError(err));
110
+ continue;
111
+ }
112
+ throw err;
113
+ }
114
+ finally {
115
+ clearTimeout(timer);
116
+ upstreamSignal.removeEventListener("abort", abortFromUpstream);
117
+ }
118
+ }
119
+ return usage;
120
+ }
121
+ //# sourceMappingURL=run-loop-with-resume.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-loop-with-resume.js","sourceRoot":"","sources":["../../src/agent/run-loop-with-resume.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Wraps `runAgentLoop` with two layered recovery mechanisms so a single hosted\n * invocation can survive interruptions without showing the user a dead chat:\n *\n * 1. **Soft timeout** — an inner timer that aborts the LLM call before the\n * hosting function's hard limit (Lambda 75s, Vercel 60s, etc.) so we have a\n * chance to gracefully wind down and append a continuation nudge. Without\n * this the function gets killed mid-stream and the user sees a frozen\n * spinner.\n *\n * 2. **Resumable-error continuation** — when the LLM call errors with a\n * transport- or gateway-level interruption (Builder gateway 45s timeout,\n * socket hang up, ECONNRESET, upstream 5xx that survived engine retries),\n * we save the conversation prefix, append a \"continue from where you left\n * off\" message, and run another LLM call. Anthropic's prompt cache makes\n * the resume call dramatically faster than the cold first attempt, and the\n * agent gets explicit context that it was cut off so it doesn't re-do\n * completed work.\n *\n * Both paths route through `appendAgentLoopContinuation` so the agent sees a\n * uniform \"continue\" instruction regardless of which recovery fired.\n */\n\nimport {\n runAgentLoop,\n appendAgentLoopContinuation,\n isResumableEngineError,\n continuationReasonForResumableError,\n} from \"./production-agent.js\";\nimport { resolveRunSoftTimeoutMs } from \"./run-manager.js\";\n\n/**\n * Cap on continuation iterations inside a single\n * `runAgentLoopDirectWithSoftTimeout` invocation. The host's hard function\n * timeout usually bounds this naturally — but a defensive cap prevents an\n * instant-error spiral from looping forever inside hosting environments with a\n * generous budget.\n *\n * 6 leaves room for: 1 normal completion + a few resume rounds for design\n * generation (prompt + 3 variants ≈ 4 LLM calls), with a small safety margin.\n */\nexport const MAX_RUN_LOOP_CONTINUATIONS = 6;\n\n/**\n * Internal entry point used by the agent-chat plugin's run handler. Wraps\n * `runAgentLoop` with soft-timeout + resumable-error continuation recovery.\n *\n * The `softTimeoutMs` argument falls back to `resolveRunSoftTimeoutMs(...)` so\n * different hosting environments (Lambda, Vercel, Cloudflare, local dev) get\n * an appropriate inner budget. Setting it to <= 0 disables both layers — the\n * call goes straight to `runAgentLoop` with no wrapping.\n */\nexport async function runAgentLoopDirectWithSoftTimeout(\n opts: Parameters<typeof runAgentLoop>[0],\n softTimeoutMs?: number,\n): Promise<Awaited<ReturnType<typeof runAgentLoop>>> {\n const timeoutMs = resolveRunSoftTimeoutMs(softTimeoutMs);\n if (timeoutMs <= 0) return runAgentLoop(opts);\n\n const upstreamSignal = opts.signal;\n const usage: Awaited<ReturnType<typeof runAgentLoop>> = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheWriteTokens: 0,\n model: opts.model,\n };\n\n const addUsage = (next: Awaited<ReturnType<typeof runAgentLoop>>) => {\n usage.inputTokens += next.inputTokens;\n usage.outputTokens += next.outputTokens;\n usage.cacheReadTokens += next.cacheReadTokens;\n usage.cacheWriteTokens += next.cacheWriteTokens;\n usage.model = next.model;\n };\n\n let attempts = 0;\n while (!upstreamSignal.aborted && attempts < MAX_RUN_LOOP_CONTINUATIONS) {\n attempts++;\n const controller = new AbortController();\n const abortFromUpstream = () => controller.abort();\n if (upstreamSignal.aborted) {\n controller.abort();\n } else {\n upstreamSignal.addEventListener(\"abort\", abortFromUpstream, {\n once: true,\n });\n }\n\n let softTimedOut = false;\n const timer = setTimeout(() => {\n if (controller.signal.aborted) return;\n softTimedOut = true;\n controller.abort();\n }, timeoutMs);\n\n try {\n const nextUsage = await runAgentLoop({\n ...opts,\n signal: controller.signal,\n });\n addUsage(nextUsage);\n if (softTimedOut && !upstreamSignal.aborted) {\n appendAgentLoopContinuation(opts.messages, \"run_timeout\");\n continue;\n }\n return usage;\n } catch (err) {\n if (softTimedOut && !upstreamSignal.aborted) {\n appendAgentLoopContinuation(opts.messages, \"run_timeout\");\n continue;\n }\n // Resumable transport / gateway interruptions: the LLM call was cut off\n // mid-stream (gateway 45s timeout, socket hang up, function-level\n // timeout that didn't trip our soft timer first). Treat it the same way\n // as a soft timeout — append a \"continue from where you left off\" nudge\n // and let the loop run another LLM call. The conversation prefix up to\n // the cut-off is preserved in opts.messages, and Anthropic's prompt\n // cache makes the resume call much faster.\n if (!upstreamSignal.aborted && isResumableEngineError(err)) {\n appendAgentLoopContinuation(\n opts.messages,\n continuationReasonForResumableError(err),\n );\n continue;\n }\n throw err;\n } finally {\n clearTimeout(timer);\n upstreamSignal.removeEventListener(\"abort\", abortFromUpstream);\n }\n }\n\n return usage;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,OAAQ,CAAC;AAoFlC,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3E;AAED,+EAA+E;AAC/E,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrE;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAqB,GAChC,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,GAC1C,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElE;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAchD;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAWpD;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,CAoBR;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,IAAI,CAAC,CA2BR;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAwBxD;AAED;;oDAEoD;AACpD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CvE"}
1
+ {"version":3,"file":"run-store.d.ts","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,OAAQ,CAAC;AAoFlC,wBAAsB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3E;AAED,+EAA+E;AAC/E,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrE;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,EACb,UAAU,GAAE,MAAqB,GAChC,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,SAAS,GAC1C,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElE;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAchD;AAED,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAWpD;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACvD,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,IAAI,CAAC,CAoBR;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC;IACT,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,GAAG,IAAI,CAAC,CA2BR;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAwBxD;AAED;;oDAEoD;AACpD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CvE"}
@@ -178,8 +178,14 @@ export async function getRunAbortState(runId) {
178
178
  export async function insertRunEvent(runId, seq, eventData) {
179
179
  await ensureRunTables();
180
180
  const client = getDbExec();
181
+ // ON CONFLICT DO NOTHING: a (runId, seq) collision can happen on the
182
+ // soft-timeout / terminal-event path where `pendingTerminalEvent` was
183
+ // assigned a seq that later gets reused by an event pushed after it.
184
+ // It can also race with `appendTerminalRunEvent` (max-seq + 1) when a
185
+ // run aborts at the same time the producer emits its final event.
186
+ // Treat the second write as a no-op so the run completes cleanly.
181
187
  await client.execute({
182
- sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?)`,
188
+ sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
183
189
  args: [runId, seq, eventData],
184
190
  });
185
191
  }
@@ -334,7 +340,7 @@ async function appendTerminalRunEvent(runId, event) {
334
340
  }
335
341
  const nextSeq = last ? Number(last.seq ?? -1) + 1 : 0;
336
342
  await client.execute({
337
- sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?)`,
343
+ sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,
338
344
  args: [runId, nextSeq, JSON.stringify(event)],
339
345
  });
340
346
  }
@@ -1 +1 @@
1
- {"version":3,"file":"run-store.js","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEjE,IAAI,YAAuC,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAElC,MAAM,qBAAqB,GAAG;IAC5B,IAAI,EAAE,OAAO;IACb,KAAK,EACH,qHAAqH;IACvH,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,IAAI;IACjB,OAAO,EACL,gIAAgI;CAC1H,CAAC;AAEX,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;;;;;;uBAMJ,OAAO,EAAE;yBACP,OAAO,EAAE;yBACT,OAAO,EAAE;6BACL,OAAO,EAAE;;OAE/B,CAAC,CAAC;YACH,8CAA8C;YAC9C,IAAI,CAAC;gBACH,IAAI,UAAU,EAAE,EAAE,CAAC;oBACjB,MAAM,MAAM,CAAC,OAAO,CAClB,gEAAgE,OAAO,EAAE,EAAE,CAC5E,CAAC;oBACF,MAAM,MAAM,CAAC,OAAO,CAClB,mEAAmE,CACpE,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,MAAM,MAAM,CAAC,OAAO,CAClB,kDAAkD,OAAO,EAAE,EAAE,CAC9D,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;oBAClB,MAAM,MAAM,CAAC,OAAO,CAClB,qDAAqD,CACtD,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;YACD,kEAAkE;YAClE,sEAAsE;YACtE,wEAAwE;YACxE,iEAAiE;YACjE,IAAI,CAAC;gBACH,IAAI,UAAU,EAAE,EAAE,CAAC;oBACjB,MAAM,MAAM,CAAC,OAAO,CAClB,oEAAoE,OAAO,EAAE,EAAE,CAChF,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,MAAM,MAAM,CAAC,OAAO,CAClB,sDAAsD,OAAO,EAAE,EAAE,CAClE,CAAC;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iCAAiC;YACnC,CAAC;YACD,MAAM,MAAM,CAAC,OAAO,CAAC;;;gBAGX,OAAO,EAAE;;;;OAIlB,CAAC,CAAC;QACL,CAAC,CAAC,EAAE,CAAC;IACP,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU,EAAE,QAAgB;IAC1D,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,8HAA8H;QACnI,IAAI,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;KACpC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAa;IACpD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,qDAAqD;QAC1D,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;KAC1B,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAa;IACjD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,yDAAyD;QAC9D,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;KAC1B,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAa,EACb,aAAqB,YAAY;IAEjC,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,UAAU,CAAC;IACvC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAC5C,GAAG,EAAE;;;;uDAI8C;QACnD,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC;KAClC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,KAAa,EACb,MAA2C;IAE3C,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,iEAAiE;QACtE,IAAI,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAa,EACb,MAAe;IAEf,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,2FAA2F;QAChG,IAAI,EAAE,CAAC,MAAM,IAAI,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC;KAC5C,CAAC,CAAC;IACH,MAAM,sBAAsB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa;IAC9C,OAAO,CAAC,MAAM,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa;IAEb,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,0DAA0D;QAC/D,IAAI,EAAE,CAAC,KAAK,CAAC;KACd,CAAC,CAAC;IACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAqD,CAAC;IACxE,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACxD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAa,EACb,GAAW,EACX,SAAiB;IAEjB,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,yEAAyE;QAC9E,IAAI,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,CAAC;KAC9B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAa,EACb,OAAe;IAEf,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,6FAA6F;QAClG,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;KACvB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpB,MAAM,GAAG,GAAG,CAAiD,CAAC;QAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAa;IAM5C,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,uEAAuE;QAC5E,IAAI,EAAE,CAAC,KAAK,CAAC;KACd,CAAC,CAAC;IACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAKf,CAAC;IACF,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;KAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,OAAuC;IAUvC,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,GAAG,GAAG,OAAO,EAAE,eAAe;QAClC,CAAC,CAAC,6JAA6J;QAC/J,CAAC,CAAC,oLAAoL,CAAC;IACzL,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAQf,CAAC;IACF,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,QAAQ,EAAE,CAAC,CAAC,SAAS;QACrB,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;QAC/B,WAAW,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;QACnE,WAAW,EAAE,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;QACnE,cAAc,EACZ,CAAC,CAAC,gBAAgB,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC;KACjE,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACjC,GAAG,EAAE;;uDAE8C;QACnD,IAAI,EAAE,CAAC,eAAe,CAAC;KACxB,CAAC,CAAC;IACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QAC5C,GAAG,EAAE;;;uDAG8C;QACnD,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC;KACpC,CAAC,CAAC;IACH,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAI,GAAwB,CAAC,EAAE,CAAC;QACxC,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,sBAAsB,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,OAAO,YAAY,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED;;oDAEoD;AACpD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,WAAmB;IACtD,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,CAAC;IACxC,uEAAuE;IACvE,mEAAmE;IACnE,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;IAClD,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACjC,GAAG,EAAE;;uDAE8C;QACnD,IAAI,EAAE,CAAC,eAAe,CAAC;KACxB,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,wGAAwG;QAC7G,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC;KAC3B,CAAC,CAAC;IACH,iEAAiE;IACjE,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE;;;uDAG8C;QACnD,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC;KACpC,CAAC,CAAC;IACH,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAI,GAAwB,CAAC,EAAE,CAAC;QACxC,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,sBAAsB,CAAC,EAAE,EAAE,qBAAqB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IACD,yCAAyC;IACzC,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE;;MAEH;QACF,IAAI,EAAE,CAAC,MAAM,CAAC;KACf,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,uEAAuE;QAC5E,IAAI,EAAE,CAAC,MAAM,CAAC;KACf,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,sBAAsB,CACnC,KAAa,EACb,KAA8B;IAE9B,MAAM,eAAe,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACpC,GAAG,EAAE,yFAAyF;QAC9F,IAAI,EAAE,CAAC,KAAK,CAAC;KACd,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAEN,CAAC;IACd,IAAI,IAAI,EAAE,UAAU,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3C,IACE,MAAM,EAAE,IAAI,KAAK,MAAM;gBACvB,MAAM,EAAE,IAAI,KAAK,OAAO;gBACxB,MAAM,EAAE,IAAI,KAAK,iBAAiB;gBAClC,MAAM,EAAE,IAAI,KAAK,YAAY;gBAC7B,MAAM,EAAE,IAAI,KAAK,eAAe,EAChC,CAAC;gBACD,OAAO;YACT,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,MAAM,CAAC,OAAO,CAAC;QACnB,GAAG,EAAE,yEAAyE;QAC9E,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;KAC9C,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * SQL persistence for agent runs and events.\n * Enables cross-isolate access on Cloudflare Workers and\n * reliable reconnection after page refreshes.\n */\nimport { getDbExec, intType, isPostgres } from \"../db/client.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\n/**\n * Max time without a heartbeat before a \"running\" run is considered dead.\n * The run-manager heartbeats every 1.5s, so 6s tolerates 3 missed writes.\n * Short window is what makes reload recovery feel instant instead of\n * stranding the user on \"Thinking...\" for up to 90s after a process death.\n */\nexport const RUN_STALE_MS = 6_000;\n\nconst STALE_RUN_ERROR_EVENT = {\n type: \"error\",\n error:\n \"The agent stopped before it could finish. It may have hit a server timeout or the worker may have been interrupted.\",\n errorCode: \"stale_run\",\n recoverable: true,\n details:\n \"The run heartbeat stopped while the run was still marked running. Partial output and tool calls were preserved when available.\",\n} as const;\n\nasync function ensureRunTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n await client.execute(`\n CREATE TABLE IF NOT EXISTS agent_runs (\n id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'running',\n abort_reason TEXT,\n started_at ${intType()} NOT NULL,\n completed_at ${intType()},\n heartbeat_at ${intType()},\n last_progress_at ${intType()}\n )\n `);\n // Backfill heartbeat_at on older deployments.\n try {\n if (isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS heartbeat_at ${intType()}`,\n );\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS abort_reason TEXT`,\n );\n } else {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN heartbeat_at ${intType()}`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n try {\n if (!isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN abort_reason TEXT`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n // Backfill last_progress_at — this is distinct from heartbeat_at.\n // heartbeat_at = \"the producer process is alive\" (bumped on a timer).\n // last_progress_at = \"the agent is actually emitting events\" (bumped on\n // each emit). The gap between them is the stuck-detector signal.\n try {\n if (isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS last_progress_at ${intType()}`,\n );\n } else {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN last_progress_at ${intType()}`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n await client.execute(`\n CREATE TABLE IF NOT EXISTS agent_run_events (\n run_id TEXT NOT NULL,\n seq ${intType()} NOT NULL,\n event_data TEXT NOT NULL,\n PRIMARY KEY (run_id, seq)\n )\n `);\n })();\n }\n return _initPromise;\n}\n\nexport async function insertRun(id: string, threadId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at) VALUES (?, ?, 'running', ?, ?, ?)`,\n args: [id, threadId, now, now, now],\n });\n}\n\n/** Update the run's liveness heartbeat. Called periodically by run-manager. */\nexport async function updateRunHeartbeat(runId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET heartbeat_at = ? WHERE id = ?`,\n args: [Date.now(), runId],\n });\n}\n\n/**\n * Bump `last_progress_at` — call this whenever the agent actually emits an\n * event (token, tool call, message). Distinct from `heartbeat_at` so the\n * stuck-detector can tell \"process alive but nothing happening\" from\n * \"process dead.\" Callers should throttle (run-manager debounces to ~1/s).\n */\nexport async function bumpRunProgress(runId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET last_progress_at = ? WHERE id = ?`,\n args: [Date.now(), runId],\n });\n}\n\n/**\n * If the given run is marked \"running\" in SQL but its heartbeat is stale\n * (producer likely crashed), flip it to \"errored\" so watchers stop waiting.\n * Returns true if the row was reaped.\n */\nexport async function reapIfStale(\n runId: string,\n maxStaleMs: number = RUN_STALE_MS,\n): Promise<boolean> {\n await ensureRunTables();\n const client = getDbExec();\n const cutoff = Date.now() - maxStaleMs;\n const { rowsAffected } = await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE id = ?\n AND status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), runId, cutoff],\n });\n const reaped = (rowsAffected ?? 0) > 0;\n if (reaped) {\n await appendTerminalRunEvent(runId, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n return reaped;\n}\n\nexport async function updateRunStatus(\n runId: string,\n status: \"completed\" | \"errored\" | \"aborted\",\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET status = ?, completed_at = ? WHERE id = ?`,\n args: [status, Date.now(), runId],\n });\n}\n\nexport async function markRunAborted(\n runId: string,\n reason?: string,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET status = 'aborted', abort_reason = ?, completed_at = ? WHERE id = ?`,\n args: [reason ?? \"user\", Date.now(), runId],\n });\n await appendTerminalRunEvent(runId, { type: \"done\" }).catch(() => {});\n}\n\nexport async function isRunAborted(runId: string): Promise<boolean> {\n return (await getRunAbortState(runId)).aborted;\n}\n\nexport async function getRunAbortState(\n runId: string,\n): Promise<{ aborted: boolean; reason?: string }> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT status, abort_reason FROM agent_runs WHERE id = ?`,\n args: [runId],\n });\n if (rows.length === 0) return { aborted: false };\n const row = rows[0] as { status: string; abort_reason?: string | null };\n if (row.status !== \"aborted\") return { aborted: false };\n return {\n aborted: true,\n ...(row.abort_reason ? { reason: row.abort_reason } : {}),\n };\n}\n\nexport async function insertRunEvent(\n runId: string,\n seq: number,\n eventData: string,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?)`,\n args: [runId, seq, eventData],\n });\n}\n\nexport async function getRunEventsSince(\n runId: string,\n fromSeq: number,\n): Promise<Array<{ seq: number; eventData: string }>> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT seq, event_data FROM agent_run_events WHERE run_id = ? AND seq >= ? ORDER BY seq ASC`,\n args: [runId, fromSeq],\n });\n return rows.map((r) => {\n const row = r as { seq: number | string; event_data: string };\n return { seq: Number(row.seq), eventData: row.event_data };\n });\n}\n\nexport async function getRunById(runId: string): Promise<{\n id: string;\n threadId: string;\n status: string;\n startedAt: number;\n} | null> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, thread_id, status, started_at FROM agent_runs WHERE id = ?`,\n args: [runId],\n });\n if (rows.length === 0) return null;\n const r = rows[0] as {\n id: string;\n thread_id: string;\n status: string;\n started_at: number | string;\n };\n return {\n id: r.id,\n threadId: r.thread_id,\n status: r.status,\n startedAt: Number(r.started_at),\n };\n}\n\nexport async function getRunByThread(\n threadId: string,\n options?: { includeTerminal?: boolean },\n): Promise<{\n id: string;\n threadId: string;\n status: string;\n startedAt: number;\n heartbeatAt: number | null;\n completedAt: number | null;\n lastProgressAt: number | null;\n} | null> {\n await ensureRunTables();\n const client = getDbExec();\n const sql = options?.includeTerminal\n ? `SELECT id, thread_id, status, started_at, heartbeat_at, completed_at, last_progress_at FROM agent_runs WHERE thread_id = ? ORDER BY started_at DESC LIMIT 1`\n : `SELECT id, thread_id, status, started_at, heartbeat_at, completed_at, last_progress_at FROM agent_runs WHERE thread_id = ? AND status = 'running' ORDER BY started_at DESC LIMIT 1`;\n const { rows } = await client.execute({ sql, args: [threadId] });\n if (rows.length === 0) return null;\n const r = rows[0] as {\n id: string;\n thread_id: string;\n status: string;\n started_at: number | string;\n heartbeat_at: number | string | null;\n completed_at: number | string | null;\n last_progress_at: number | string | null;\n };\n return {\n id: r.id,\n threadId: r.thread_id,\n status: r.status,\n startedAt: Number(r.started_at),\n heartbeatAt: r.heartbeat_at == null ? null : Number(r.heartbeat_at),\n completedAt: r.completed_at == null ? null : Number(r.completed_at),\n lastProgressAt:\n r.last_progress_at == null ? null : Number(r.last_progress_at),\n };\n}\n\n/**\n * Expire any \"running\" rows whose heartbeat is stale — producer died.\n * Safe to call at server startup on multi-isolate deployments: only rows\n * without a fresh heartbeat get reaped, so runs owned by OTHER live\n * isolates (which keep heartbeating) are left alone.\n */\nexport async function reapAllStaleRuns(): Promise<number> {\n await ensureRunTables();\n const client = getDbExec();\n const heartbeatCutoff = Date.now() - RUN_STALE_MS;\n const stale = await client.execute({\n sql: `SELECT id FROM agent_runs\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [heartbeatCutoff],\n });\n const { rowsAffected } = await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), heartbeatCutoff],\n });\n for (const row of stale.rows) {\n const id = (row as { id?: unknown }).id;\n if (typeof id === \"string\") {\n await appendTerminalRunEvent(id, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n }\n return rowsAffected ?? 0;\n}\n\n/** Delete completed/errored runs older than the given threshold,\n * and expire stale \"running\" rows that haven't had activity\n * (e.g. worker crashed before updating status). */\nexport async function cleanupOldRuns(olderThanMs: number): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const cutoff = Date.now() - olderThanMs;\n // Expire stale running rows on the absolute-age threshold — safety net\n // for runs that never received a heartbeat (very old deployments).\n const heartbeatCutoff = Date.now() - RUN_STALE_MS;\n const stale = await client.execute({\n sql: `SELECT id FROM agent_runs\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [heartbeatCutoff],\n });\n await client.execute({\n sql: `UPDATE agent_runs SET status = 'errored', completed_at = ? WHERE status = 'running' AND started_at < ?`,\n args: [Date.now(), cutoff],\n });\n // Also expire runs whose heartbeat is stale — producer has died.\n await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), heartbeatCutoff],\n });\n for (const row of stale.rows) {\n const id = (row as { id?: unknown }).id;\n if (typeof id === \"string\") {\n await appendTerminalRunEvent(id, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n }\n // Delete events for old non-running runs\n await client.execute({\n sql: `DELETE FROM agent_run_events WHERE run_id IN (\n SELECT id FROM agent_runs WHERE status != 'running' AND completed_at < ?\n )`,\n args: [cutoff],\n });\n await client.execute({\n sql: `DELETE FROM agent_runs WHERE status != 'running' AND completed_at < ?`,\n args: [cutoff],\n });\n}\n\nasync function appendTerminalRunEvent(\n runId: string,\n event: Record<string, unknown>,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT seq, event_data FROM agent_run_events WHERE run_id = ? ORDER BY seq DESC LIMIT 1`,\n args: [runId],\n });\n const last = rows[0] as\n | { seq?: number | string; event_data?: string }\n | undefined;\n if (last?.event_data) {\n try {\n const parsed = JSON.parse(last.event_data);\n if (\n parsed?.type === \"done\" ||\n parsed?.type === \"error\" ||\n parsed?.type === \"missing_api_key\" ||\n parsed?.type === \"loop_limit\" ||\n parsed?.type === \"auto_continue\"\n ) {\n return;\n }\n } catch {\n // Ignore malformed rows and append the terminal event.\n }\n }\n const nextSeq = last ? Number(last.seq ?? -1) + 1 : 0;\n await client.execute({\n sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?)`,\n args: [runId, nextSeq, JSON.stringify(event)],\n });\n}\n"]}
1
+ {"version":3,"file":"run-store.js","sourceRoot":"","sources":["../../src/agent/run-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SQL persistence for agent runs and events.\n * Enables cross-isolate access on Cloudflare Workers and\n * reliable reconnection after page refreshes.\n */\nimport { getDbExec, intType, isPostgres } from \"../db/client.js\";\n\nlet _initPromise: Promise<void> | undefined;\n\n/**\n * Max time without a heartbeat before a \"running\" run is considered dead.\n * The run-manager heartbeats every 1.5s, so 6s tolerates 3 missed writes.\n * Short window is what makes reload recovery feel instant instead of\n * stranding the user on \"Thinking...\" for up to 90s after a process death.\n */\nexport const RUN_STALE_MS = 6_000;\n\nconst STALE_RUN_ERROR_EVENT = {\n type: \"error\",\n error:\n \"The agent stopped before it could finish. It may have hit a server timeout or the worker may have been interrupted.\",\n errorCode: \"stale_run\",\n recoverable: true,\n details:\n \"The run heartbeat stopped while the run was still marked running. Partial output and tool calls were preserved when available.\",\n} as const;\n\nasync function ensureRunTables(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n await client.execute(`\n CREATE TABLE IF NOT EXISTS agent_runs (\n id TEXT PRIMARY KEY,\n thread_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'running',\n abort_reason TEXT,\n started_at ${intType()} NOT NULL,\n completed_at ${intType()},\n heartbeat_at ${intType()},\n last_progress_at ${intType()}\n )\n `);\n // Backfill heartbeat_at on older deployments.\n try {\n if (isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS heartbeat_at ${intType()}`,\n );\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS abort_reason TEXT`,\n );\n } else {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN heartbeat_at ${intType()}`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n try {\n if (!isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN abort_reason TEXT`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n // Backfill last_progress_at — this is distinct from heartbeat_at.\n // heartbeat_at = \"the producer process is alive\" (bumped on a timer).\n // last_progress_at = \"the agent is actually emitting events\" (bumped on\n // each emit). The gap between them is the stuck-detector signal.\n try {\n if (isPostgres()) {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN IF NOT EXISTS last_progress_at ${intType()}`,\n );\n } else {\n await client.execute(\n `ALTER TABLE agent_runs ADD COLUMN last_progress_at ${intType()}`,\n );\n }\n } catch {\n // Column already exists — ignore\n }\n await client.execute(`\n CREATE TABLE IF NOT EXISTS agent_run_events (\n run_id TEXT NOT NULL,\n seq ${intType()} NOT NULL,\n event_data TEXT NOT NULL,\n PRIMARY KEY (run_id, seq)\n )\n `);\n })();\n }\n return _initPromise;\n}\n\nexport async function insertRun(id: string, threadId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const now = Date.now();\n await client.execute({\n sql: `INSERT INTO agent_runs (id, thread_id, status, started_at, heartbeat_at, last_progress_at) VALUES (?, ?, 'running', ?, ?, ?)`,\n args: [id, threadId, now, now, now],\n });\n}\n\n/** Update the run's liveness heartbeat. Called periodically by run-manager. */\nexport async function updateRunHeartbeat(runId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET heartbeat_at = ? WHERE id = ?`,\n args: [Date.now(), runId],\n });\n}\n\n/**\n * Bump `last_progress_at` — call this whenever the agent actually emits an\n * event (token, tool call, message). Distinct from `heartbeat_at` so the\n * stuck-detector can tell \"process alive but nothing happening\" from\n * \"process dead.\" Callers should throttle (run-manager debounces to ~1/s).\n */\nexport async function bumpRunProgress(runId: string): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET last_progress_at = ? WHERE id = ?`,\n args: [Date.now(), runId],\n });\n}\n\n/**\n * If the given run is marked \"running\" in SQL but its heartbeat is stale\n * (producer likely crashed), flip it to \"errored\" so watchers stop waiting.\n * Returns true if the row was reaped.\n */\nexport async function reapIfStale(\n runId: string,\n maxStaleMs: number = RUN_STALE_MS,\n): Promise<boolean> {\n await ensureRunTables();\n const client = getDbExec();\n const cutoff = Date.now() - maxStaleMs;\n const { rowsAffected } = await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE id = ?\n AND status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), runId, cutoff],\n });\n const reaped = (rowsAffected ?? 0) > 0;\n if (reaped) {\n await appendTerminalRunEvent(runId, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n return reaped;\n}\n\nexport async function updateRunStatus(\n runId: string,\n status: \"completed\" | \"errored\" | \"aborted\",\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET status = ?, completed_at = ? WHERE id = ?`,\n args: [status, Date.now(), runId],\n });\n}\n\nexport async function markRunAborted(\n runId: string,\n reason?: string,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n await client.execute({\n sql: `UPDATE agent_runs SET status = 'aborted', abort_reason = ?, completed_at = ? WHERE id = ?`,\n args: [reason ?? \"user\", Date.now(), runId],\n });\n await appendTerminalRunEvent(runId, { type: \"done\" }).catch(() => {});\n}\n\nexport async function isRunAborted(runId: string): Promise<boolean> {\n return (await getRunAbortState(runId)).aborted;\n}\n\nexport async function getRunAbortState(\n runId: string,\n): Promise<{ aborted: boolean; reason?: string }> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT status, abort_reason FROM agent_runs WHERE id = ?`,\n args: [runId],\n });\n if (rows.length === 0) return { aborted: false };\n const row = rows[0] as { status: string; abort_reason?: string | null };\n if (row.status !== \"aborted\") return { aborted: false };\n return {\n aborted: true,\n ...(row.abort_reason ? { reason: row.abort_reason } : {}),\n };\n}\n\nexport async function insertRunEvent(\n runId: string,\n seq: number,\n eventData: string,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n // ON CONFLICT DO NOTHING: a (runId, seq) collision can happen on the\n // soft-timeout / terminal-event path where `pendingTerminalEvent` was\n // assigned a seq that later gets reused by an event pushed after it.\n // It can also race with `appendTerminalRunEvent` (max-seq + 1) when a\n // run aborts at the same time the producer emits its final event.\n // Treat the second write as a no-op so the run completes cleanly.\n await client.execute({\n sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,\n args: [runId, seq, eventData],\n });\n}\n\nexport async function getRunEventsSince(\n runId: string,\n fromSeq: number,\n): Promise<Array<{ seq: number; eventData: string }>> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT seq, event_data FROM agent_run_events WHERE run_id = ? AND seq >= ? ORDER BY seq ASC`,\n args: [runId, fromSeq],\n });\n return rows.map((r) => {\n const row = r as { seq: number | string; event_data: string };\n return { seq: Number(row.seq), eventData: row.event_data };\n });\n}\n\nexport async function getRunById(runId: string): Promise<{\n id: string;\n threadId: string;\n status: string;\n startedAt: number;\n} | null> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT id, thread_id, status, started_at FROM agent_runs WHERE id = ?`,\n args: [runId],\n });\n if (rows.length === 0) return null;\n const r = rows[0] as {\n id: string;\n thread_id: string;\n status: string;\n started_at: number | string;\n };\n return {\n id: r.id,\n threadId: r.thread_id,\n status: r.status,\n startedAt: Number(r.started_at),\n };\n}\n\nexport async function getRunByThread(\n threadId: string,\n options?: { includeTerminal?: boolean },\n): Promise<{\n id: string;\n threadId: string;\n status: string;\n startedAt: number;\n heartbeatAt: number | null;\n completedAt: number | null;\n lastProgressAt: number | null;\n} | null> {\n await ensureRunTables();\n const client = getDbExec();\n const sql = options?.includeTerminal\n ? `SELECT id, thread_id, status, started_at, heartbeat_at, completed_at, last_progress_at FROM agent_runs WHERE thread_id = ? ORDER BY started_at DESC LIMIT 1`\n : `SELECT id, thread_id, status, started_at, heartbeat_at, completed_at, last_progress_at FROM agent_runs WHERE thread_id = ? AND status = 'running' ORDER BY started_at DESC LIMIT 1`;\n const { rows } = await client.execute({ sql, args: [threadId] });\n if (rows.length === 0) return null;\n const r = rows[0] as {\n id: string;\n thread_id: string;\n status: string;\n started_at: number | string;\n heartbeat_at: number | string | null;\n completed_at: number | string | null;\n last_progress_at: number | string | null;\n };\n return {\n id: r.id,\n threadId: r.thread_id,\n status: r.status,\n startedAt: Number(r.started_at),\n heartbeatAt: r.heartbeat_at == null ? null : Number(r.heartbeat_at),\n completedAt: r.completed_at == null ? null : Number(r.completed_at),\n lastProgressAt:\n r.last_progress_at == null ? null : Number(r.last_progress_at),\n };\n}\n\n/**\n * Expire any \"running\" rows whose heartbeat is stale — producer died.\n * Safe to call at server startup on multi-isolate deployments: only rows\n * without a fresh heartbeat get reaped, so runs owned by OTHER live\n * isolates (which keep heartbeating) are left alone.\n */\nexport async function reapAllStaleRuns(): Promise<number> {\n await ensureRunTables();\n const client = getDbExec();\n const heartbeatCutoff = Date.now() - RUN_STALE_MS;\n const stale = await client.execute({\n sql: `SELECT id FROM agent_runs\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [heartbeatCutoff],\n });\n const { rowsAffected } = await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), heartbeatCutoff],\n });\n for (const row of stale.rows) {\n const id = (row as { id?: unknown }).id;\n if (typeof id === \"string\") {\n await appendTerminalRunEvent(id, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n }\n return rowsAffected ?? 0;\n}\n\n/** Delete completed/errored runs older than the given threshold,\n * and expire stale \"running\" rows that haven't had activity\n * (e.g. worker crashed before updating status). */\nexport async function cleanupOldRuns(olderThanMs: number): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const cutoff = Date.now() - olderThanMs;\n // Expire stale running rows on the absolute-age threshold — safety net\n // for runs that never received a heartbeat (very old deployments).\n const heartbeatCutoff = Date.now() - RUN_STALE_MS;\n const stale = await client.execute({\n sql: `SELECT id FROM agent_runs\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [heartbeatCutoff],\n });\n await client.execute({\n sql: `UPDATE agent_runs SET status = 'errored', completed_at = ? WHERE status = 'running' AND started_at < ?`,\n args: [Date.now(), cutoff],\n });\n // Also expire runs whose heartbeat is stale — producer has died.\n await client.execute({\n sql: `UPDATE agent_runs\n SET status = 'errored', completed_at = ?\n WHERE status = 'running'\n AND COALESCE(heartbeat_at, started_at) < ?`,\n args: [Date.now(), heartbeatCutoff],\n });\n for (const row of stale.rows) {\n const id = (row as { id?: unknown }).id;\n if (typeof id === \"string\") {\n await appendTerminalRunEvent(id, STALE_RUN_ERROR_EVENT).catch(() => {});\n }\n }\n // Delete events for old non-running runs\n await client.execute({\n sql: `DELETE FROM agent_run_events WHERE run_id IN (\n SELECT id FROM agent_runs WHERE status != 'running' AND completed_at < ?\n )`,\n args: [cutoff],\n });\n await client.execute({\n sql: `DELETE FROM agent_runs WHERE status != 'running' AND completed_at < ?`,\n args: [cutoff],\n });\n}\n\nasync function appendTerminalRunEvent(\n runId: string,\n event: Record<string, unknown>,\n): Promise<void> {\n await ensureRunTables();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT seq, event_data FROM agent_run_events WHERE run_id = ? ORDER BY seq DESC LIMIT 1`,\n args: [runId],\n });\n const last = rows[0] as\n | { seq?: number | string; event_data?: string }\n | undefined;\n if (last?.event_data) {\n try {\n const parsed = JSON.parse(last.event_data);\n if (\n parsed?.type === \"done\" ||\n parsed?.type === \"error\" ||\n parsed?.type === \"missing_api_key\" ||\n parsed?.type === \"loop_limit\" ||\n parsed?.type === \"auto_continue\"\n ) {\n return;\n }\n } catch {\n // Ignore malformed rows and append the terminal event.\n }\n }\n const nextSeq = last ? Number(last.seq ?? -1) + 1 : 0;\n await client.execute({\n sql: `INSERT INTO agent_run_events (run_id, seq, event_data) VALUES (?, ?, ?) ON CONFLICT (run_id, seq) DO NOTHING`,\n args: [runId, nextSeq, JSON.stringify(event)],\n });\n}\n"]}
@@ -162,7 +162,7 @@ export type AgentChatEvent = {
162
162
  maxIterations?: number;
163
163
  } | {
164
164
  type: "auto_continue";
165
- reason: "run_timeout" | "loop_limit" | "no_progress" | "stream_ended";
165
+ reason: "run_timeout" | "loop_limit" | "no_progress" | "stream_ended" | "gateway_timeout" | "network_interrupted";
166
166
  maxIterations?: number;
167
167
  } | {
168
168
  type: "clear";
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ReasoningEffort } from \"../shared/reasoning-effort.js\";\n\nexport interface ActionTool {\n description: string;\n parameters?: {\n type: \"object\";\n properties: Record<\n string,\n {\n type: string;\n description?: string;\n enum?: string[];\n }\n >;\n required?: string[];\n };\n}\n\n/** @deprecated Use `ActionTool` instead */\nexport type ScriptTool = ActionTool;\n\nexport interface AgentMessage {\n role: \"user\" | \"assistant\";\n content: string;\n}\n\nexport type AgentChatStructuredContentPart =\n | { type: \"text\"; text: string }\n | {\n type: \"tool-call\";\n id?: string;\n toolCallId?: string;\n name?: string;\n toolName?: string;\n input?: unknown;\n args?: unknown;\n }\n | {\n type: \"tool-result\";\n toolCallId: string;\n toolName?: string;\n content: string;\n isError?: boolean;\n };\n\nexport interface AgentChatStructuredMessage {\n role: \"user\" | \"assistant\";\n content: AgentChatStructuredContentPart[];\n}\n\nexport interface AgentChatReference {\n type: \"file\" | \"skill\" | \"mention\" | \"agent\" | \"custom-agent\";\n path: string;\n name: string;\n source: string;\n refType?: string;\n refId?: string;\n}\n\nexport interface MentionProviderItem {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n refType: string;\n refId?: string;\n refPath?: string;\n}\n\nexport interface MentionProvider {\n label: string;\n icon?: string;\n search: (\n query: string,\n /** The H3 event for the current request — use to make internal API calls */\n event?: any,\n ) => MentionProviderItem[] | Promise<MentionProviderItem[]>;\n}\n\nexport interface AgentChatAttachment {\n type: string;\n name: string;\n data?: string;\n contentType?: string;\n text?: string;\n}\n\nexport interface AgentChatRequest {\n message: string;\n /**\n * User-visible text to persist in chat history. `message` may be normalized\n * for the model (for example mention markup or internal continuation text).\n */\n displayMessage?: string;\n history?: AgentMessage[];\n /**\n * Provider-neutral transcript used for run recovery. Unlike `history`,\n * this preserves assistant tool calls and matching tool results so\n * continuation turns do not re-run completed read-only tools.\n */\n structuredHistory?: AgentChatStructuredMessage[];\n references?: AgentChatReference[];\n threadId?: string;\n attachments?: AgentChatAttachment[];\n /** Internal retry/continuation requests should not create visible user turns. */\n internalContinuation?: boolean;\n /** Execution mode for this turn. Plan mode is read-only and proposes before acting. */\n mode?: \"act\" | \"plan\";\n /** Per-request model override (ephemeral, from the composer model picker). */\n model?: string;\n /** Per-request engine override (sent alongside model for cross-provider switches). */\n engine?: string;\n /** Per-request reasoning effort override (ephemeral, from the composer picker). */\n effort?: ReasoningEffort;\n /** Usage-tracking label for this call (e.g. \"chat\", \"summarize\"). Default: \"chat\". */\n usageLabel?: string;\n}\n\nexport type AgentChatEvent =\n | { type: \"text\"; text: string }\n | { type: \"activity\"; label: string; tool?: string }\n | { type: \"tool_start\"; tool: string; input: Record<string, string> }\n | { type: \"tool_done\"; tool: string; result: string }\n | {\n type: \"agent_call\";\n agent: string;\n status: \"start\" | \"done\" | \"error\";\n }\n | { type: \"agent_call_text\"; agent: string; text: string }\n | {\n type: \"agent_task\";\n taskId: string;\n threadId: string;\n description: string;\n status: \"running\" | \"completed\" | \"errored\";\n }\n | {\n type: \"agent_task_update\";\n taskId: string;\n preview: string;\n currentStep?: string;\n }\n | {\n type: \"agent_task_complete\";\n taskId: string;\n summary: string;\n }\n | { type: \"done\" }\n | {\n type: \"error\";\n error: string;\n /**\n * Optional machine-readable error code. Builder gateway uses codes\n * like \"credits-limit-monthly\" / \"unauthorized\" / \"gateway_not_enabled\"\n * so the chat UI can render a structured CTA (e.g. upgrade button).\n */\n errorCode?: string;\n /** Optional link paired with errorCode — e.g. Builder billing page. */\n upgradeUrl?: string;\n /** Optional details for expandable UI/debugging. */\n details?: string;\n /** True when the user can reasonably continue/retry from partial work. */\n recoverable?: boolean;\n }\n | { type: \"missing_api_key\" }\n | { type: \"loop_limit\"; maxIterations?: number }\n | {\n type: \"auto_continue\";\n reason: \"run_timeout\" | \"loop_limit\" | \"no_progress\" | \"stream_ended\";\n maxIterations?: number;\n }\n | { type: \"clear\" };\n\nexport interface RunEvent {\n seq: number;\n event: AgentChatEvent;\n}\n\nexport type RunStatus = \"running\" | \"completed\" | \"errored\" | \"aborted\";\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agent/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ReasoningEffort } from \"../shared/reasoning-effort.js\";\n\nexport interface ActionTool {\n description: string;\n parameters?: {\n type: \"object\";\n properties: Record<\n string,\n {\n type: string;\n description?: string;\n enum?: string[];\n }\n >;\n required?: string[];\n };\n}\n\n/** @deprecated Use `ActionTool` instead */\nexport type ScriptTool = ActionTool;\n\nexport interface AgentMessage {\n role: \"user\" | \"assistant\";\n content: string;\n}\n\nexport type AgentChatStructuredContentPart =\n | { type: \"text\"; text: string }\n | {\n type: \"tool-call\";\n id?: string;\n toolCallId?: string;\n name?: string;\n toolName?: string;\n input?: unknown;\n args?: unknown;\n }\n | {\n type: \"tool-result\";\n toolCallId: string;\n toolName?: string;\n content: string;\n isError?: boolean;\n };\n\nexport interface AgentChatStructuredMessage {\n role: \"user\" | \"assistant\";\n content: AgentChatStructuredContentPart[];\n}\n\nexport interface AgentChatReference {\n type: \"file\" | \"skill\" | \"mention\" | \"agent\" | \"custom-agent\";\n path: string;\n name: string;\n source: string;\n refType?: string;\n refId?: string;\n}\n\nexport interface MentionProviderItem {\n id: string;\n label: string;\n description?: string;\n icon?: string;\n refType: string;\n refId?: string;\n refPath?: string;\n}\n\nexport interface MentionProvider {\n label: string;\n icon?: string;\n search: (\n query: string,\n /** The H3 event for the current request — use to make internal API calls */\n event?: any,\n ) => MentionProviderItem[] | Promise<MentionProviderItem[]>;\n}\n\nexport interface AgentChatAttachment {\n type: string;\n name: string;\n data?: string;\n contentType?: string;\n text?: string;\n}\n\nexport interface AgentChatRequest {\n message: string;\n /**\n * User-visible text to persist in chat history. `message` may be normalized\n * for the model (for example mention markup or internal continuation text).\n */\n displayMessage?: string;\n history?: AgentMessage[];\n /**\n * Provider-neutral transcript used for run recovery. Unlike `history`,\n * this preserves assistant tool calls and matching tool results so\n * continuation turns do not re-run completed read-only tools.\n */\n structuredHistory?: AgentChatStructuredMessage[];\n references?: AgentChatReference[];\n threadId?: string;\n attachments?: AgentChatAttachment[];\n /** Internal retry/continuation requests should not create visible user turns. */\n internalContinuation?: boolean;\n /** Execution mode for this turn. Plan mode is read-only and proposes before acting. */\n mode?: \"act\" | \"plan\";\n /** Per-request model override (ephemeral, from the composer model picker). */\n model?: string;\n /** Per-request engine override (sent alongside model for cross-provider switches). */\n engine?: string;\n /** Per-request reasoning effort override (ephemeral, from the composer picker). */\n effort?: ReasoningEffort;\n /** Usage-tracking label for this call (e.g. \"chat\", \"summarize\"). Default: \"chat\". */\n usageLabel?: string;\n}\n\nexport type AgentChatEvent =\n | { type: \"text\"; text: string }\n | { type: \"activity\"; label: string; tool?: string }\n | { type: \"tool_start\"; tool: string; input: Record<string, string> }\n | { type: \"tool_done\"; tool: string; result: string }\n | {\n type: \"agent_call\";\n agent: string;\n status: \"start\" | \"done\" | \"error\";\n }\n | { type: \"agent_call_text\"; agent: string; text: string }\n | {\n type: \"agent_task\";\n taskId: string;\n threadId: string;\n description: string;\n status: \"running\" | \"completed\" | \"errored\";\n }\n | {\n type: \"agent_task_update\";\n taskId: string;\n preview: string;\n currentStep?: string;\n }\n | {\n type: \"agent_task_complete\";\n taskId: string;\n summary: string;\n }\n | { type: \"done\" }\n | {\n type: \"error\";\n error: string;\n /**\n * Optional machine-readable error code. Builder gateway uses codes\n * like \"credits-limit-monthly\" / \"unauthorized\" / \"gateway_not_enabled\"\n * so the chat UI can render a structured CTA (e.g. upgrade button).\n */\n errorCode?: string;\n /** Optional link paired with errorCode — e.g. Builder billing page. */\n upgradeUrl?: string;\n /** Optional details for expandable UI/debugging. */\n details?: string;\n /** True when the user can reasonably continue/retry from partial work. */\n recoverable?: boolean;\n }\n | { type: \"missing_api_key\" }\n | { type: \"loop_limit\"; maxIterations?: number }\n | {\n type: \"auto_continue\";\n reason:\n | \"run_timeout\"\n | \"loop_limit\"\n | \"no_progress\"\n | \"stream_ended\"\n | \"gateway_timeout\"\n | \"network_interrupted\";\n maxIterations?: number;\n }\n | { type: \"clear\" };\n\nexport interface RunEvent {\n seq: number;\n event: AgentChatEvent;\n}\n\nexport type RunStatus = \"running\" | \"completed\" | \"errored\" | \"aborted\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/AssistantChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/AssistantChat.tsx"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React, { useState, useRef, useEffect, useLayoutEffect, useCallback, useMemo, forwardRef, useImperativeHandle, } from "react";
2
+ import React, { useState, useRef, useEffect, useCallback, useMemo, forwardRef, useImperativeHandle, } from "react";
3
3
  import { AssistantRuntimeProvider, useLocalRuntime, useThreadRuntime, useThread, useAui, useComposer, useMessageRuntime, ThreadPrimitive, ComposerPrimitive, MessagePrimitive, } from "@assistant-ui/react";
4
4
  import { SimpleImageAttachmentAdapter, CompositeAttachmentAdapter, } from "@assistant-ui/react";
5
5
  import { MarkdownTextPrimitive } from "@assistant-ui/react-markdown";
@@ -18,7 +18,6 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel,
18
18
  import { IframeEmbed, parseEmbedBody } from "./IframeEmbed.js";
19
19
  import { useDevMode } from "./use-dev-mode.js";
20
20
  import { agentNativePath } from "./api-path.js";
21
- import { getThreadCacheKey } from "./use-chat-threads.js";
22
21
  import { BUILDER_SPACE_SETTINGS_URL } from "./error-format.js";
23
22
  import { ThumbsFeedback } from "./observability/ThumbsFeedback.js";
24
23
  import { TiptapComposer, } from "./composer/TiptapComposer.js";
@@ -1193,7 +1192,7 @@ function BuilderSetupCard({ onConnected, bouncePulse, }) {
1193
1192
  void el.offsetWidth;
1194
1193
  el.classList.add("animate-bounce-once");
1195
1194
  }, [bouncePulse]);
1196
- return (_jsxs("div", { ref: cardRef, className: "mx-4 my-6 rounded-lg border border-border bg-card p-5", children: [_jsxs("div", { className: "flex items-center gap-3 mb-3", children: [_jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted", children: _jsx(IconMessage, { className: "h-4.5 w-4.5 text-muted-foreground" }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium text-foreground", children: "Connect an LLM" }), _jsx("p", { className: "mt-0.5 text-[11px] text-muted-foreground", children: "Use the hosted agent without adding a separate model provider key." })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx(BuilderConnectCta, { onConnected: onConnected }), _jsx("div", { className: "text-center", children: _jsx("button", { type: "button", onClick: openSettings, className: "text-[11px] text-muted-foreground underline-offset-2 hover:text-foreground hover:underline", children: "Or add your own API key" }) })] })] }));
1195
+ return (_jsxs("div", { ref: cardRef, className: "mx-4 my-6 rounded-lg border border-border bg-card p-5", children: [_jsxs("div", { className: "flex items-center gap-3 mb-3", children: [_jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-muted", children: _jsx(IconMessage, { className: "h-4.5 w-4.5 text-muted-foreground" }) }), _jsxs("div", { children: [_jsx("h3", { className: "text-sm font-medium text-foreground", children: "Turn on the AI assistant" }), _jsx("p", { className: "mt-0.5 text-[11px] text-muted-foreground", children: "One click to connect Builder for free hosted access \u2014 no API keys needed." })] })] }), _jsxs("div", { className: "space-y-3", children: [_jsx(BuilderConnectCta, { onConnected: onConnected }), _jsx("div", { className: "text-center", children: _jsx("button", { type: "button", onClick: openSettings, className: "text-[11px] text-muted-foreground underline-offset-2 hover:text-foreground hover:underline", children: "Or add your own API key" }) })] })] }));
1197
1196
  }
1198
1197
  function getLoopLimitMetadata(message) {
1199
1198
  const meta = message?.metadata;
@@ -1492,22 +1491,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1492
1491
  }, [isRunning, tabId, threadId]);
1493
1492
  // ─── Chat persistence ──────────────────────────────────────────────
1494
1493
  const hasRestoredRef = useRef(false);
1495
- // Cached thread data from a prior session, read synchronously so existing
1496
- // chats can paint their messages on first commit instead of after the server
1497
- // round-trip. The server fetch still runs to refresh with the latest.
1498
- const [cachedThreadData] = useState(() => {
1499
- if (typeof window === "undefined")
1500
- return null;
1501
- if (!threadId || isNewThread)
1502
- return null;
1503
- try {
1504
- return localStorage.getItem(getThreadCacheKey(threadId));
1505
- }
1506
- catch {
1507
- return null;
1508
- }
1509
- });
1510
- const [isRestoring, setIsRestoring] = useState(!!threadId && !isNewThread && !cachedThreadData);
1494
+ const [isRestoring, setIsRestoring] = useState(!!threadId && !isNewThread);
1511
1495
  const onSaveThreadRef = useRef(onSaveThread);
1512
1496
  onSaveThreadRef.current = onSaveThread;
1513
1497
  const onGenerateTitleRef = useRef(onGenerateTitle);
@@ -1708,30 +1692,15 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1708
1692
  return false;
1709
1693
  }
1710
1694
  }, [apiUrl, refreshThreadFromServer, startReconnectToRun, threadId]);
1711
- // Hydrate from the localStorage cache synchronously so the message bubbles
1712
- // paint on the first commit instead of after the server round-trip. The
1713
- // server fetch below still runs to refresh with the latest content.
1714
- const hydratedFromCacheRef = useRef(false);
1715
- useLayoutEffect(() => {
1716
- if (hydratedFromCacheRef.current)
1717
- return;
1718
- if (!cachedThreadData)
1719
- return;
1720
- hydratedFromCacheRef.current = true;
1721
- try {
1722
- importThreadData(cachedThreadData, { markTitleGenerated: true });
1723
- }
1724
- catch {
1725
- // Corrupt cache entry — ignore and let the server fetch repopulate.
1726
- }
1727
- }, [cachedThreadData, importThreadData]);
1728
- // Restore messages from server on mount (when threadId is set)
1695
+ // Restore messages from server on mount (when threadId is set). The
1696
+ // server is the single source of truth we don't hydrate from localStorage
1697
+ // first, so what the user sees in the chat panel always matches what the
1698
+ // history list (and the agent) sees on disk.
1729
1699
  useEffect(() => {
1730
1700
  if (hasRestoredRef.current)
1731
1701
  return;
1732
1702
  hasRestoredRef.current = true;
1733
1703
  if (threadId) {
1734
- // Load from server
1735
1704
  (async () => {
1736
1705
  try {
1737
1706
  const res = await fetch(`${apiUrl}/threads/${encodeURIComponent(threadId)}`);
@@ -1739,12 +1708,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1739
1708
  return;
1740
1709
  const data = await res.json();
1741
1710
  if (data.threadData) {
1742
- // Skip the re-import if the server data matches what we already
1743
- // hydrated from cache — avoids a second runtime.import that would
1744
- // briefly flicker the message list.
1745
- if (data.threadData !== cachedThreadData) {
1746
- importThreadData(data.threadData, { markTitleGenerated: true });
1747
- }
1711
+ importThreadData(data.threadData, { markTitleGenerated: true });
1748
1712
  }
1749
1713
  // Also skip title generation if thread already has a title
1750
1714
  if (data.title) {
@@ -1784,7 +1748,6 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1784
1748
  threadRuntime,
1785
1749
  importThreadData,
1786
1750
  reconnectActiveRunForThread,
1787
- cachedThreadData,
1788
1751
  ]);
1789
1752
  // If assistant-ui stops the local runtime while the background server run is
1790
1753
  // still alive, immediately switch into the same reconnect path used after a