@agent-native/core 0.70.0 → 0.70.2

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 (172) hide show
  1. package/README.md +15 -15
  2. package/corpus/README.md +2 -2
  3. package/corpus/core/CHANGELOG.md +67 -0
  4. package/corpus/core/docs/design/durable-agent-runs.md +217 -0
  5. package/corpus/core/package.json +1 -1
  6. package/corpus/core/src/action.ts +89 -0
  7. package/corpus/core/src/agent/model-config.ts +0 -2
  8. package/corpus/core/src/agent/run-loop-with-resume.ts +48 -0
  9. package/corpus/core/src/cli/skills.ts +2 -2
  10. package/corpus/core/src/cli/sync-builder-starter-manifest.ts +275 -0
  11. package/corpus/core/src/client/AgentPanel.tsx +5 -3
  12. package/corpus/core/src/client/AssistantChat.tsx +8 -0
  13. package/corpus/core/src/client/client-surface.ts +41 -0
  14. package/corpus/core/src/client/composer/TiptapComposer.tsx +123 -12
  15. package/corpus/core/src/client/feedback-context.ts +4 -0
  16. package/corpus/core/src/client/index.ts +1 -0
  17. package/corpus/core/src/client/sse-event-processor.ts +7 -1
  18. package/corpus/core/src/mcp/build-server.ts +57 -1
  19. package/corpus/core/src/mcp/embed-app.ts +86 -2
  20. package/corpus/core/src/mcp/oauth-route.ts +109 -13
  21. package/corpus/core/src/server/core-routes-plugin.ts +78 -0
  22. package/corpus/core/src/server/onboarding-html.ts +35 -0
  23. package/corpus/core/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  24. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +22 -0
  25. package/corpus/templates/analytics/AGENTS.md +8 -1
  26. package/corpus/templates/analytics/actions/install-dashboard-template.ts +97 -2
  27. package/corpus/templates/analytics/actions/update-dashboard.ts +36 -7
  28. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +30 -3
  29. package/corpus/templates/analytics/app/components/layout/Header.tsx +0 -1
  30. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +2 -4
  31. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +0 -3
  32. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +32 -2
  33. package/corpus/templates/analytics/changelog/2026-06-23-long-dashboard-and-analysis-names-in-the-sidebar-now-truncat.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-06-23-open-any-dashboard-chart-full-screen-in-a-modal-from-the-pan.md +6 -0
  35. package/corpus/templates/assets/actions/generate-image.ts +24 -0
  36. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
  37. package/corpus/templates/assets/app/global.css +17 -1
  38. package/corpus/templates/assets/app/routes/_index.tsx +94 -14
  39. package/corpus/templates/assets/changelog/2026-06-23-chat-dates-in-the-sidebar-no-longer-wrap-onto-two-lines.md +6 -0
  40. package/corpus/templates/assets/changelog/2026-06-23-clicking-image-video-or-refine-on-the-start-screen-now-drops.md +6 -0
  41. package/corpus/templates/assets/changelog/2026-06-23-pick-your-image-generation-model-right-from-the-chat-model-m.md +6 -0
  42. package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -20
  43. package/corpus/templates/clips/app/components/recorder/countdown-overlay.tsx +72 -48
  44. package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +35 -17
  45. package/corpus/templates/clips/changelog/2026-06-23-removed-select-button-from-library-hover-a-clip-to-select-it.md +6 -0
  46. package/corpus/templates/clips/changelog/2026-06-23-shared-video-links-now-play-for-anyone-without-signing-in.md +6 -0
  47. package/corpus/templates/clips/changelog/2026-06-23-skip-or-cancel-the-recording-countdown-with-buttons-beside-t.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-camera-bubble-now-looks-sharp-the-instant-it-ope.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-06-23-the-desktop-recording-widget-now-grows-downward-only-when-yo.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-06-23-the-recording-start-sound-is-now-a-softer-more-modern-chime.md +6 -0
  51. package/corpus/templates/clips/chrome-extension/public/manifest.json +17 -8
  52. package/corpus/templates/clips/chrome-extension/src/background.ts +769 -180
  53. package/corpus/templates/clips/chrome-extension/src/content-script.ts +177 -0
  54. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +466 -329
  55. package/corpus/templates/clips/chrome-extension/src/overlay.css +377 -0
  56. package/corpus/templates/clips/chrome-extension/src/overlay.html +12 -0
  57. package/corpus/templates/clips/chrome-extension/src/overlay.ts +330 -0
  58. package/corpus/templates/clips/chrome-extension/src/permission.html +227 -0
  59. package/corpus/templates/clips/chrome-extension/src/permission.ts +105 -0
  60. package/corpus/templates/clips/chrome-extension/src/popup.html +3 -0
  61. package/corpus/templates/clips/chrome-extension/src/popup.ts +50 -2
  62. package/corpus/templates/clips/chrome-extension/src/styles.css +50 -0
  63. package/corpus/templates/clips/chrome-extension/vite.config.ts +3 -0
  64. package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +41 -24
  65. package/corpus/templates/clips/desktop/src/lib/bubble-webrtc.ts +119 -2
  66. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +21 -2
  67. package/corpus/templates/clips/desktop/src/styles.css +70 -2
  68. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +73 -0
  69. package/corpus/templates/clips/server/routes/api/video/[recordingId].get.ts +34 -5
  70. package/corpus/templates/content/AGENTS.md +20 -3
  71. package/corpus/templates/content/actions/_database-utils.ts +15 -0
  72. package/corpus/templates/content/actions/_property-utils.ts +371 -4
  73. package/corpus/templates/content/actions/configure-document-property.ts +35 -1
  74. package/corpus/templates/content/actions/create-content-database.ts +5 -1
  75. package/corpus/templates/content/actions/delete-document-property.ts +52 -2
  76. package/corpus/templates/content/actions/duplicate-document-property.ts +34 -17
  77. package/corpus/templates/content/actions/reorder-document-property.ts +79 -0
  78. package/corpus/templates/content/actions/set-document-property.ts +39 -0
  79. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +806 -0
  80. package/corpus/templates/content/app/components/editor/DocumentDatabase.tsx +226 -68
  81. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +59 -30
  82. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +25 -1
  83. package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +180 -0
  84. package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +179 -0
  85. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +244 -0
  86. package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +132 -0
  87. package/corpus/templates/content/app/global.css +9 -0
  88. package/corpus/templates/content/app/hooks/use-document-properties.ts +21 -0
  89. package/corpus/templates/content/server/db/schema.ts +30 -0
  90. package/corpus/templates/content/server/plugins/db.ts +87 -0
  91. package/corpus/templates/content/shared/api.ts +7 -0
  92. package/corpus/templates/content/shared/properties.ts +109 -0
  93. package/corpus/templates/forms/.agents/skills/form-responses/SKILL.md +10 -0
  94. package/corpus/templates/forms/actions/export-responses.ts +6 -0
  95. package/corpus/templates/forms/actions/list-responses.ts +2 -0
  96. package/corpus/templates/forms/actions/response-insights.ts +2 -0
  97. package/corpus/templates/forms/app/pages/ResponsesPage.tsx +138 -1
  98. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-the-page-each-submission-came-from-.md +6 -0
  99. package/corpus/templates/forms/changelog/2026-06-23-response-tables-now-show-whether-feedback-came-from-the-web-.md +6 -0
  100. package/corpus/templates/forms/server/db/schema.ts +7 -0
  101. package/corpus/templates/forms/server/handlers/submissions.ts +19 -2
  102. package/corpus/templates/forms/server/lib/integrations.ts +76 -2
  103. package/corpus/templates/forms/server/plugins/db.ts +20 -0
  104. package/corpus/templates/forms/shared/types.ts +12 -0
  105. package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +3 -1
  106. package/corpus/templates/plan/changelog/2026-06-23-large-diagrams-in-a-plan-now-scroll-within-their-block-inste.md +6 -0
  107. package/dist/action.js +87 -0
  108. package/dist/action.js.map +1 -1
  109. package/dist/agent/engine/builder-engine.d.ts +1 -1
  110. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  111. package/dist/agent/model-config.d.ts +2 -2
  112. package/dist/agent/model-config.d.ts.map +1 -1
  113. package/dist/agent/model-config.js +0 -2
  114. package/dist/agent/model-config.js.map +1 -1
  115. package/dist/agent/run-loop-with-resume.d.ts +13 -0
  116. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  117. package/dist/agent/run-loop-with-resume.js +44 -0
  118. package/dist/agent/run-loop-with-resume.js.map +1 -1
  119. package/dist/cli/skills.js +2 -2
  120. package/dist/cli/skills.js.map +1 -1
  121. package/dist/cli/sync-builder-starter-manifest.d.ts +32 -0
  122. package/dist/cli/sync-builder-starter-manifest.d.ts.map +1 -0
  123. package/dist/cli/sync-builder-starter-manifest.js +179 -0
  124. package/dist/cli/sync-builder-starter-manifest.js.map +1 -0
  125. package/dist/client/AgentPanel.d.ts.map +1 -1
  126. package/dist/client/AgentPanel.js +5 -3
  127. package/dist/client/AgentPanel.js.map +1 -1
  128. package/dist/client/AssistantChat.d.ts +6 -1
  129. package/dist/client/AssistantChat.d.ts.map +1 -1
  130. package/dist/client/AssistantChat.js +2 -2
  131. package/dist/client/AssistantChat.js.map +1 -1
  132. package/dist/client/client-surface.d.ts +17 -0
  133. package/dist/client/client-surface.d.ts.map +1 -0
  134. package/dist/client/client-surface.js +24 -0
  135. package/dist/client/client-surface.js.map +1 -0
  136. package/dist/client/composer/TiptapComposer.d.ts +26 -1
  137. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  138. package/dist/client/composer/TiptapComposer.js +27 -5
  139. package/dist/client/composer/TiptapComposer.js.map +1 -1
  140. package/dist/client/feedback-context.d.ts +3 -0
  141. package/dist/client/feedback-context.d.ts.map +1 -1
  142. package/dist/client/feedback-context.js +2 -0
  143. package/dist/client/feedback-context.js.map +1 -1
  144. package/dist/client/index.d.ts +1 -0
  145. package/dist/client/index.d.ts.map +1 -1
  146. package/dist/client/index.js +1 -0
  147. package/dist/client/index.js.map +1 -1
  148. package/dist/client/sse-event-processor.d.ts.map +1 -1
  149. package/dist/client/sse-event-processor.js +7 -1
  150. package/dist/client/sse-event-processor.js.map +1 -1
  151. package/dist/mcp/build-server.d.ts +21 -0
  152. package/dist/mcp/build-server.d.ts.map +1 -1
  153. package/dist/mcp/build-server.js +43 -1
  154. package/dist/mcp/build-server.js.map +1 -1
  155. package/dist/mcp/embed-app.d.ts.map +1 -1
  156. package/dist/mcp/embed-app.js +86 -2
  157. package/dist/mcp/embed-app.js.map +1 -1
  158. package/dist/mcp/oauth-route.d.ts.map +1 -1
  159. package/dist/mcp/oauth-route.js +95 -12
  160. package/dist/mcp/oauth-route.js.map +1 -1
  161. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  162. package/dist/server/core-routes-plugin.js +63 -0
  163. package/dist/server/core-routes-plugin.js.map +1 -1
  164. package/dist/server/onboarding-html.d.ts.map +1 -1
  165. package/dist/server/onboarding-html.js +35 -0
  166. package/dist/server/onboarding-html.js.map +1 -1
  167. package/dist/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  168. package/docs/design/durable-agent-runs.md +217 -0
  169. package/package.json +1 -1
  170. package/src/templates/workspace-core/.agents/skills/reliable-mutations/SKILL.md +72 -0
  171. package/corpus/templates/analytics/app/pages/About.tsx +0 -108
  172. package/corpus/templates/analytics/app/routes/about.tsx +0 -9
@@ -0,0 +1,217 @@
1
+ # Design: Durable / Checkpointed Agent Runs
2
+
3
+ Status: proposed
4
+ Owner: core / run-manager
5
+ Related code: `packages/core/src/agent/run-manager.ts`,
6
+ `packages/core/src/agent/engine/builder-engine.ts`
7
+
8
+ ## Problem
9
+
10
+ Hosted agent runs are bounded by a ~40s soft timeout enforced in
11
+ `run-manager.ts` (`DEFAULT_HOSTED_RUN_SOFT_TIMEOUT_MS = 40_000`, also the
12
+ `HOSTED_SOFT_TIMEOUT_CEILING_MS`). That budget is deliberate and correct: it
13
+ sits just under a stack of upstream walls that the framework does not control.
14
+
15
+ When the soft timeout fires, the run-manager aborts the current chunk, persists
16
+ the partial turn, writes a terminal event, and emits an `auto_continue` event
17
+ (`reason: "run_timeout"`) so the client transparently resumes the turn in a
18
+ fresh chunk. This works well for a single long model call that just needs more
19
+ wall-clock time.
20
+
21
+ It does **not** work well for long _multi-step_ operations. A turn that performs
22
+ many sequential side effects — for example an agent appending many dashboard
23
+ panels through many separate write calls, or any "do N independent mutations in
24
+ a loop" workflow — fails in a characteristic way:
25
+
26
+ - **Continuation thrash / re-hydration.** Each `auto_continue` chunk starts the
27
+ model over from the rebuilt context. If the work isn't expressed as resumable
28
+ progress, the model frequently re-reasons about and re-issues steps it already
29
+ attempted in the previous chunk instead of advancing. Successive chunks burn
30
+ their entire 40s budget re-deciding rather than completing new steps.
31
+ - **Partial or zero net progress.** Because each chunk can be cut mid-step and
32
+ the next chunk may redo earlier steps, the run can churn for many chunks while
33
+ the _persisted_ end state barely moves — or, when nothing reaches a committed
34
+ state before each cutoff, moves not at all.
35
+ - **Silent "looked-done" failure.** A tool call that returned a success marker
36
+ (✓) in an aborted chunk does not guarantee its effect was committed and
37
+ survived the cutoff. The model can reasonably believe a step succeeded, report
38
+ the whole task complete, and leave nothing (or only some rows) actually
39
+ persisted. The user is told it worked; the data says otherwise.
40
+
41
+ Net effect: long multi-step runs can spin indefinitely, never finish, and
42
+ terminate with an untruthful "done" state.
43
+
44
+ ## Goals
45
+
46
+ 1. Long multi-step runs **complete reliably** — they make monotonic forward
47
+ progress across continuation chunks rather than re-doing work.
48
+ 2. The user always gets a **truthful terminal state**: either "completed, here
49
+ is concrete proof (N of N persisted, ids …)", or an honest "did not finish,
50
+ here is what was committed (M of N) and what remains" — never a false
51
+ success.
52
+ 3. No change to the upstream walls and no raising of the 40s soft timeout (see
53
+ Guardrail).
54
+
55
+ ## Non-goals
56
+
57
+ - Raising or removing the soft timeout. It is correct; see Guardrail.
58
+ - Changing the gateway, serverless function limits, or model call timeout.
59
+ - Replacing `auto_continue`. Both approaches below build on it.
60
+
61
+ ## Guardrail: the 40s soft timeout is correct and must not be raised
62
+
63
+ `DEFAULT_HOSTED_RUN_SOFT_TIMEOUT_MS` / `HOSTED_SOFT_TIMEOUT_CEILING_MS` =
64
+ `40_000` is intentional headroom under the upstream hard walls. Raising it does
65
+ not buy more time — it just converts a graceful hand-off into a hard kill. The
66
+ walls, in order:
67
+
68
+ 1. **Builder model gateway hard cap — ~45s.**
69
+ `MAX_BUILDER_GATEWAY_TIMEOUT_MS = 45_000` in
70
+ `packages/core/src/agent/engine/builder-engine.ts`. A single model call is
71
+ killed at the gateway after 45s. **Not raisable** by the framework.
72
+ 2. **Serverless function kill — ~60–65s.** The hosting function is terminated
73
+ shortly after; the heartbeat then reaps the run row as `stale_run`.
74
+
75
+ 40s leaves ~5s under the gateway wall to abort, persist the partial turn, write
76
+ the terminal event, and emit a clean `auto_continue` so the client resumes. A
77
+ larger value (production saw per-template overrides like `240_000`) pushes the
78
+ cutoff past both walls, so `auto_continue` never fires and the run dies as
79
+ `builder_gateway_timeout` / `stale_run` instead. The ceiling clamp in
80
+ `resolveRunSoftTimeoutMs` exists precisely to defeat that footgun. **Do not
81
+ raise it. Fix durability above the timeout, not by moving the timeout.**
82
+
83
+ ## Approach options
84
+
85
+ Both options keep the 40s budget and build on the existing `auto_continue`
86
+ mechanism. They differ in _where the long work lives_.
87
+
88
+ ### Option A — Checkpointed / idempotent continuation
89
+
90
+ Keep the work inside the normal run/`auto_continue` loop, but make each
91
+ continuation chunk **resume from committed progress instead of restarting**.
92
+
93
+ Mechanism:
94
+
95
+ - **Persist a progress record** for the operation (a checkpoint): the planned
96
+ unit of work (the N items / steps), and which units are already committed.
97
+ This lives in SQL so it survives chunk boundaries and function recycling, the
98
+ same way run rows do.
99
+ - **Idempotent steps.** Each step keys off a stable identity so re-issuing a
100
+ completed step is a no-op (upsert by natural key, or "skip if checkpoint says
101
+ done"). Re-hydration after `auto_continue` then can't double-apply or
102
+ thrash — a redone step costs a cheap check, not a duplicate write.
103
+ - **Resume, don't replan.** On `auto_continue`, the next chunk reads the
104
+ checkpoint, skips committed units, and continues with the remainder. Progress
105
+ is monotonic: every chunk that does anything moves the committed count up.
106
+ - **Truthful terminal state from the checkpoint.** "Done" means the checkpoint
107
+ shows N of N committed. If the run is cut for good (e.g. it exhausts a
108
+ continuation budget), the checkpoint still reports M of N committed and the
109
+ exact remainder — so the terminal message is honest by construction.
110
+
111
+ Interaction with the walls and the 40s budget:
112
+
113
+ - Fully respects the 40s soft timeout and the gateway/function walls — it never
114
+ needs a single chunk to outlast them. It just makes the _sequence_ of chunks
115
+ productive.
116
+ - Works hand-in-glove with `auto_continue`: today a continuation can redo work;
117
+ with a checkpoint, a continuation can only advance.
118
+
119
+ Tradeoffs:
120
+
121
+ - Pro: smallest change to the runtime model; no new infrastructure; the user
122
+ keeps watching one live turn; degrades gracefully (even a half-finished run is
123
+ truthful and re-runnable).
124
+ - Pro: directly kills re-hydration thrash, the actual failure mode.
125
+ - Con: still bounded by however many continuation chunks the client/turn budget
126
+ allows. A truly enormous job (thousands of steps) can still run out of chunks
127
+ — but it now ends _truthfully partial and resumable_, not silently empty.
128
+ - Con: requires per-operation work to define the unit of progress and make
129
+ steps idempotent. Best paid down once at the primitive/action layer (see
130
+ Tie-in) so individual agents don't have to.
131
+
132
+ ### Option B — Out-of-band durable background execution
133
+
134
+ Hand a long run to a **queued background job** that executes beyond the
135
+ function/gateway lifetime and reports progress back into the run/event stream.
136
+
137
+ Mechanism:
138
+
139
+ - The foreground turn **enqueues** a durable job (the full operation + its
140
+ inputs) and returns immediately with "started, tracking as job X". The
141
+ user-facing run does not try to do the work itself within 40s.
142
+ - A durable worker (outside the per-request serverless function lifetime — e.g.
143
+ the core run-manager / agent-teams background infrastructure the framework
144
+ already mandates for background agents) runs the job to completion, free of
145
+ the 45s gateway cap and the ~60s function kill on the _original_ request.
146
+ - The worker **streams progress** (committed counts, ids, errors) back so the
147
+ UI and the agent can observe and the final state is truthful.
148
+
149
+ Interaction with the walls and the 40s budget:
150
+
151
+ - Sidesteps the gateway/function walls for the _long_ work by moving it off the
152
+ request path. The walls still apply to each individual model call the worker
153
+ makes, so the worker itself should checkpoint internally (i.e. Option B is
154
+ strongest when it contains Option A).
155
+ - `auto_continue` becomes a lightweight "is the job still running / what's its
156
+ progress" poll on the foreground turn rather than the vehicle for the work.
157
+
158
+ Tradeoffs:
159
+
160
+ - Pro: removes the hard ceiling on total operation length — genuinely large
161
+ jobs can finish.
162
+ - Pro: the foreground turn stays responsive and cheap; the user can leave and
163
+ come back.
164
+ - Con: more infrastructure and lifecycle complexity (job queue, durable worker,
165
+ progress fan-in, failure/retry semantics, surfacing job state in the UI and
166
+ to the agent).
167
+ - Con: changes the UX from "one live turn" to "fire-and-track"; needs clear
168
+ status surfacing so it doesn't become its own kind of silent failure.
169
+
170
+ ## Recommendation
171
+
172
+ Build **Option A first**, then layer **Option B** for the genuinely unbounded
173
+ cases. Option A delivers the most reliability per unit of effort: it directly
174
+ removes re-hydration thrash and silent looked-done failure for the common case
175
+ (tens of steps), needs no new infrastructure, and makes terminal state truthful
176
+ by construction. Option B is the right ceiling-remover but is a larger build and
177
+ is most valuable _on top of_ a checkpointed core (the durable worker should
178
+ itself checkpoint).
179
+
180
+ ### Phased plan
181
+
182
+ 1. **Phase 0 — Stop hitting the ceiling so often (near-term, cheapest).** Land
183
+ the mitigations in the Tie-in below (one-call atomic primitives,
184
+ self-documenting actions, loud termination, proof-of-done verification).
185
+ These don't fix the ceiling but sharply cut how often multi-step loops are
186
+ even attempted, and make the failures that remain _loud and truthful_ instead
187
+ of silent. Capture the agent-facing half as the `reliable-mutations` skill.
188
+ 2. **Phase 1 — Checkpointed continuation (Option A).** Add a SQL-backed progress
189
+ checkpoint for long operations and make their steps idempotent/resumable so
190
+ each `auto_continue` chunk advances committed progress instead of replanning.
191
+ Drive terminal state ("N of N", or "M of N + remainder") from the checkpoint.
192
+ This is the primary reliability win.
193
+ 3. **Phase 2 — Durable background execution (Option B).** For operations that
194
+ can exceed any reasonable number of continuation chunks, enqueue them onto the
195
+ core background infrastructure, have the durable worker run them to completion
196
+ (checkpointing internally per Phase 1), and stream truthful progress back to
197
+ the foreground run and UI.
198
+
199
+ ## Tie-in: cheaper near-term mitigations reduce, but do not replace, the fix
200
+
201
+ The following reduce _how often_ the 40s ceiling is hit and make the remaining
202
+ failures honest. They are valuable and should ship first (Phase 0), but the
203
+ **actual fix is durable/checkpointed runs** (Phases 1–2):
204
+
205
+ - **One-call atomic primitives.** Where an action can accept the whole batch
206
+ (e.g. "set all panels" / "append many in one call"), a single call commits
207
+ atomically inside one chunk instead of looping N writes that race the budget.
208
+ - **Self-documenting actions.** Action descriptions that steer agents toward the
209
+ atomic/batch call and away from per-item loops.
210
+ - **Loud termination.** On a time-budget cutoff, fail loud with what was and
211
+ wasn't committed — never report success on an aborted chunk.
212
+ - **Proof-of-done verification.** After a write, re-read the end state and report
213
+ concrete proof (counts/ids) rather than trusting a tool ✓.
214
+
215
+ The agent-facing rules for these live in the `reliable-mutations` skill
216
+ (`.agents/skills/reliable-mutations/SKILL.md`). They lower the blast radius;
217
+ checkpointed and durable runs remove the ceiling itself.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.70.0",
3
+ "version": "0.70.2",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: reliable-mutations
3
+ description: >-
4
+ How the agent must perform writes so they actually persist under the hosted
5
+ ~40s run budget. Use whenever you create, update, delete, or batch-write app
6
+ data — especially "do this for many items" loops, or any task where the user
7
+ expects N things to end up saved.
8
+ ---
9
+
10
+ # Reliable Mutations
11
+
12
+ ## Rule
13
+
14
+ Make a change in **one atomic call** when the action supports it, then **verify
15
+ the persisted end state and report concrete proof** (counts/ids). Never drive a
16
+ multi-step change by looping many small writes, and never report success from a
17
+ tool ✓ alone.
18
+
19
+ ## Why
20
+
21
+ Hosted agent runs have a ~40s soft budget (it exists to hand off cleanly under
22
+ the upstream gateway/function walls — it is correct and is not raisable; see the
23
+ durable-agent-runs design doc). When you loop many sequential writes inside one
24
+ turn, the budget can cut you off mid-loop. The run resumes in a new chunk, but
25
+ the resume often re-does earlier steps instead of advancing, so the loop churns
26
+ and the *saved* result ends up partial — or empty — even though each individual
27
+ tool call appeared to succeed. The user gets told "done" while the data says
28
+ otherwise. One atomic call commits or fails as a unit; verification turns a
29
+ hopeful ✓ into a fact.
30
+
31
+ ## How
32
+
33
+ 1. **Prefer a single atomic call.** If an action accepts the whole set (add
34
+ many, set all, bulk update), pass the full batch in one call so it commits
35
+ atomically. Check the action surface for a batch/plural form before reaching
36
+ for a loop.
37
+ 2. **Do not loop many small writes under the run budget.** A sequence of N
38
+ per-item writes in one turn will race the ~40s cutoff and can leave partial
39
+ or no state. If no batch action exists, that is a gap in the action layer —
40
+ add or extend an action that accepts the batch (see the `actions` skill)
41
+ rather than papering over it with a loop.
42
+ 3. **Verify the end state after writing.** Re-read the data (a list/read action,
43
+ a count query) and confirm the result matches intent — the right number of
44
+ rows, the expected ids/fields. Do this before you tell the user it worked.
45
+ 4. **Report proof-of-done, not vibes.** State concrete evidence: "saved 12 of 12
46
+ panels (ids …)" or "updated 5 rows". Do not infer success from the presence
47
+ of a tool ✓ on an individual call.
48
+ 5. **On a time-budget cutoff, fail loud.** If the turn is cut before the change
49
+ is fully committed and verified, say so explicitly and report what *did*
50
+ persist (M of N) and what remains. Never round a partial or unverified write
51
+ up to "done".
52
+
53
+ ## Don't
54
+
55
+ - Don't loop `for each item: write(item)` for a large set in a single hosted
56
+ turn.
57
+ - Don't claim completion because every tool call returned ✓ — a ✓ on an aborted
58
+ chunk does not mean the row was committed.
59
+ - Don't silently shrink the scope ("I added a few of them") and present it as the
60
+ finished task.
61
+ - Don't try to "fix" this by asking for a longer run timeout — the budget is
62
+ correct; restructure the write instead.
63
+
64
+ ## Related
65
+
66
+ - `actions` — define or extend a batch/atomic action when only per-item writes
67
+ exist.
68
+ - `storing-data` — where app data lives and how reads/writes are scoped.
69
+ - `performance` — avoid query waterfalls when verifying end state.
70
+ - Design doc: `packages/core/docs/design/durable-agent-runs.md` — the real
71
+ ceiling fix (checkpointed and durable runs); this skill is the agent-facing
72
+ mitigation that reduces how often the ceiling is hit.
@@ -1,108 +0,0 @@
1
- import {
2
- IconChartBar,
3
- IconMessage,
4
- IconLayoutDashboard,
5
- IconDatabase,
6
- } from "@tabler/icons-react";
7
- import { dataSources, categoryLabels, categoryOrder } from "@/lib/data-sources";
8
-
9
- const capabilities = [
10
- {
11
- icon: IconDatabase,
12
- title: "Connect Data Sources",
13
- description:
14
- "Connect any of 20+ data sources — from Google Analytics and BigQuery to Stripe, HubSpot, and PostgreSQL. Each source includes a step-by-step setup guide.",
15
- },
16
- {
17
- icon: IconLayoutDashboard,
18
- title: "Create Custom Dashboards",
19
- description:
20
- "Describe the dashboard you want and the agent builds it — charts, tables, metrics, and all. A Google Analytics example is included to show what's possible.",
21
- },
22
- {
23
- icon: IconChartBar,
24
- title: "Query Explorer",
25
- description:
26
- "Use the Explorer tool to write arbitrary SQL against BigQuery and visualize results as charts or tables instantly.",
27
- },
28
- {
29
- icon: IconMessage,
30
- title: "Ask Questions in Chat",
31
- description:
32
- "Ask natural-language questions about any connected data source. Get answers, charts, and insights without writing SQL.",
33
- },
34
- ];
35
-
36
- export default function About() {
37
- return (
38
- <div className="mx-auto max-w-4xl space-y-10 p-6 md:p-10">
39
- <header>
40
- <h1 className="text-3xl font-bold tracking-tight">About This App</h1>
41
- <p className="mt-2 text-muted-foreground text-lg">
42
- Analytics gives you a single place to connect data sources, build
43
- custom dashboards, and ask questions across all of your key metrics.
44
- </p>
45
- </header>
46
-
47
- {/* Capabilities */}
48
- <section>
49
- <h2 className="text-xl font-semibold mb-4">What You Can Do</h2>
50
- <div className="grid gap-4 sm:grid-cols-2">
51
- {capabilities.map((cap) => (
52
- <div
53
- key={cap.title}
54
- className="rounded-lg border border-border bg-card p-5 space-y-2"
55
- >
56
- <div className="flex items-center gap-3">
57
- <div className="flex h-9 w-9 items-center justify-center rounded-md bg-primary/10 text-primary">
58
- <cap.icon className="h-5 w-5" />
59
- </div>
60
- <h3 className="font-medium">{cap.title}</h3>
61
- </div>
62
- <p className="text-sm text-muted-foreground leading-relaxed">
63
- {cap.description}
64
- </p>
65
- </div>
66
- ))}
67
- </div>
68
- </section>
69
-
70
- {/* Available Data Sources */}
71
- <section>
72
- <h2 className="text-xl font-semibold mb-4">Available Data Sources</h2>
73
- {categoryOrder.map((category) => {
74
- const sources = dataSources.filter((s) => s.category === category);
75
- if (sources.length === 0) return null;
76
- return (
77
- <div key={category} className="mb-4">
78
- <h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-2">
79
- {categoryLabels[category]}
80
- </h3>
81
- <div className="grid gap-2 sm:grid-cols-3">
82
- {sources.map((source) => {
83
- const Icon = source.icon;
84
- return (
85
- <div
86
- key={source.id}
87
- className="flex items-center gap-2.5 rounded-lg border border-border bg-card px-3 py-2.5"
88
- >
89
- <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
90
- <Icon className="h-4 w-4" />
91
- </div>
92
- <span className="text-sm font-medium">{source.name}</span>
93
- </div>
94
- );
95
- })}
96
- </div>
97
- </div>
98
- );
99
- })}
100
- </section>
101
-
102
- <footer className="text-xs text-muted-foreground pt-4 border-t border-border">
103
- All data is queried live from the connected sources. BigQuery queries
104
- are capped at 750 GB per query for cost safety.
105
- </footer>
106
- </div>
107
- );
108
- }
@@ -1,9 +0,0 @@
1
- import About from "@/pages/About";
2
-
3
- export function meta() {
4
- return [{ title: "About — Analytics" }];
5
- }
6
-
7
- export default function AboutRoute() {
8
- return <About />;
9
- }