@agent-native/core 0.151.2 → 0.152.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 (259) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +1 -1
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +24 -0
  4. package/corpus/templates/analytics/actions/bigquery-query.ts +21 -0
  5. package/corpus/templates/analytics/app/components/ConnectionTestStatus.tsx +65 -0
  6. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +3 -3
  7. package/corpus/templates/analytics/app/pages/DataSources.tsx +15 -37
  8. package/corpus/templates/analytics/app/root.tsx +0 -1
  9. package/corpus/templates/analytics/changelog/2026-08-11-analytics-custom-blocks-keep-loading-with-legacy-bigquery-action.md +6 -0
  10. package/corpus/templates/analytics/changelog/2026-08-11-analytics-routes-company-knowledge-and-slack-context-questio.md +6 -0
  11. package/corpus/templates/analytics/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  12. package/corpus/templates/analytics/public/manifest.json +0 -1
  13. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +5 -0
  14. package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
  15. package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +1 -1
  16. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +24 -0
  17. package/corpus/templates/assets/app/root.tsx +0 -1
  18. package/corpus/templates/assets/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  19. package/corpus/templates/assets/public/manifest.json +0 -1
  20. package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +1 -1
  21. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +24 -0
  22. package/corpus/templates/brain/app/root.tsx +0 -1
  23. package/corpus/templates/brain/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  24. package/corpus/templates/brain/public/manifest.json +0 -1
  25. package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +1 -1
  26. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +24 -0
  27. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +0 -53
  28. package/corpus/templates/calendar/app/i18n-data.ts +0 -80
  29. package/corpus/templates/calendar/app/root.tsx +0 -1
  30. package/corpus/templates/calendar/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  31. package/corpus/templates/calendar/changelog/2026-08-11-google-calendar-connection-buttons-now-open-the-sign-in-flow.md +6 -0
  32. package/corpus/templates/calendar/public/manifest.json +0 -1
  33. package/corpus/templates/calendar/server/plugins/auth.ts +0 -10
  34. package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  35. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  36. package/corpus/templates/chat/app/root.tsx +0 -1
  37. package/corpus/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  38. package/corpus/templates/chat/public/manifest.json +0 -1
  39. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +24 -0
  40. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +1 -1
  41. package/corpus/templates/clips/app/components/player/share-dialog.tsx +6 -0
  42. package/corpus/templates/clips/app/components/sharing/share-ui.tsx +20 -3
  43. package/corpus/templates/clips/app/i18n/en-US.ts +4 -4
  44. package/corpus/templates/clips/app/root.tsx +0 -1
  45. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +1 -3
  46. package/corpus/templates/clips/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  47. package/corpus/templates/clips/changelog/2026-08-11-clips-desktop-settings-are-now-easier-to-scan-with-a-wider-t.md +6 -0
  48. package/corpus/templates/clips/changelog/2026-08-11-google-calendar-connections-from-meetings-now-open-directly.md +6 -0
  49. package/corpus/templates/clips/changelog/2026-08-11-recording-viewers-can-comment-and-react.md +6 -0
  50. package/corpus/templates/clips/changelog/2026-08-11-system-audio-recording-now-lives-inside-the-microphone-menu-.md +6 -0
  51. package/corpus/templates/clips/changelog/2026-08-11-timestamped-comments-stay-on-the-video-for-three-seconds-wh.md +6 -0
  52. package/corpus/templates/clips/desktop/src/app.tsx +773 -1001
  53. package/corpus/templates/clips/desktop/src/components/MediaDeviceRow.tsx +15 -27
  54. package/corpus/templates/clips/desktop/src/styles.css +364 -5
  55. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +1 -1
  56. package/corpus/templates/clips/public/manifest.json +0 -1
  57. package/corpus/templates/content/.agents/skills/sharing/SKILL.md +1 -1
  58. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +24 -0
  59. package/corpus/templates/content/AGENTS.md +3 -0
  60. package/corpus/templates/content/actions/resolve-content-landing.ts +120 -0
  61. package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +196 -30
  62. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +9 -0
  63. package/corpus/templates/content/app/i18n-data.ts +58 -0
  64. package/corpus/templates/content/app/lib/content-landing.ts +22 -0
  65. package/corpus/templates/content/app/root.tsx +0 -1
  66. package/corpus/templates/content/app/routes/_app._index.tsx +36 -26
  67. package/corpus/templates/content/changelog/2026-08-03-choose-text-or-a-heading-from-one-compact-formatting-control.md +6 -0
  68. package/corpus/templates/content/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  69. package/corpus/templates/content/changelog/2026-08-11-content-opens-your-last-page-on-return-and-gives-new-users-a.md +6 -0
  70. package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +7 -1
  71. package/corpus/templates/content/docs/solutions/evidence/content-text-selector/README.md +26 -0
  72. package/corpus/templates/content/parity/matrix.md +1 -0
  73. package/corpus/templates/content/parity/matrix.ts +22 -0
  74. package/corpus/templates/content/public/manifest.json +0 -1
  75. package/corpus/templates/content/shared/content-landing.ts +17 -0
  76. package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +1 -1
  77. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +24 -0
  78. package/corpus/templates/crm/app/root.tsx +0 -1
  79. package/corpus/templates/crm/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  80. package/corpus/templates/crm/public/manifest.json +0 -1
  81. package/corpus/templates/design/.agents/skills/sharing/SKILL.md +1 -1
  82. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +24 -0
  83. package/corpus/templates/design/app/i18n/en-US.ts +5 -0
  84. package/corpus/templates/design/app/root.tsx +0 -1
  85. package/corpus/templates/design/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  86. package/corpus/templates/design/changelog/2026-08-11-design-sharing-now-identifies-viewers-who-can-add-review-com.md +6 -0
  87. package/corpus/templates/design/public/manifest.json +0 -1
  88. package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +1 -1
  89. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +24 -0
  90. package/corpus/templates/dispatch/AGENTS.md +9 -0
  91. package/corpus/templates/dispatch/actions/list-dispatch-usage-metrics.ts +5 -19
  92. package/corpus/templates/dispatch/actions/view-screen.ts +10 -3
  93. package/corpus/templates/dispatch/app/root.tsx +0 -1
  94. package/corpus/templates/dispatch/app/routes/settings.tsx +13 -1
  95. package/corpus/templates/dispatch/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  96. package/corpus/templates/dispatch/changelog/2026-08-11-clicking-the-dispatch-logo-returns-to-the-overview-page.md +6 -0
  97. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-no-longer-links-to-itself-from-the-app-switcher.md +6 -0
  98. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-settings-now-link-directly-to-admin.md +6 -0
  99. package/corpus/templates/dispatch/changelog/2026-08-11-dispatch-shows-usage-trends-recent-prompts-and-an-agent-revi.md +6 -0
  100. package/corpus/templates/dispatch/changelog/2026-08-11-human-friendly-app-names.md +6 -0
  101. package/corpus/templates/dispatch/public/manifest.json +0 -1
  102. package/corpus/templates/dispatch/server/lib/identity-sso.ts +432 -158
  103. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +204 -123
  104. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +1 -0
  105. package/corpus/templates/factory/.agents/skills/sharing/SKILL.md +1 -1
  106. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +24 -0
  107. package/corpus/templates/factory/app/root.tsx +0 -1
  108. package/corpus/templates/factory/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  109. package/corpus/templates/factory/public/manifest.json +0 -1
  110. package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +1 -1
  111. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +24 -0
  112. package/corpus/templates/forms/app/root.tsx +0 -1
  113. package/corpus/templates/forms/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  114. package/corpus/templates/forms/public/manifest.json +0 -1
  115. package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +1 -1
  116. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +24 -0
  117. package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +1 -1
  118. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +24 -0
  119. package/corpus/templates/mail/app/root.tsx +0 -1
  120. package/corpus/templates/mail/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  121. package/corpus/templates/mail/changelog/2026-08-11-google-sign-in-now-opens-the-gmail-connection-flow-directly.md +6 -0
  122. package/corpus/templates/mail/public/manifest.json +0 -1
  123. package/corpus/templates/mail/server/plugins/auth.ts +0 -10
  124. package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +1 -1
  125. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +24 -0
  126. package/corpus/templates/plan/app/i18n/en-US.ts +2 -0
  127. package/corpus/templates/plan/app/pages/PlansPage.tsx +6 -0
  128. package/corpus/templates/plan/app/root.tsx +0 -1
  129. package/corpus/templates/plan/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  130. package/corpus/templates/plan/changelog/2026-08-11-plan-sharing-now-identifies-viewers-who-can-add-comments.md +6 -0
  131. package/corpus/templates/plan/public/manifest.json +0 -1
  132. package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +1 -1
  133. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +24 -0
  134. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +6 -0
  135. package/corpus/templates/slides/app/i18n/en-US.ts +2 -0
  136. package/corpus/templates/slides/app/root.tsx +0 -1
  137. package/corpus/templates/slides/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  138. package/corpus/templates/slides/changelog/2026-08-11-share-dialog-uses-commenter-terminology.md +6 -0
  139. package/corpus/templates/slides/public/manifest.json +0 -1
  140. package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +1 -1
  141. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +24 -0
  142. package/corpus/templates/tasks/app/root.tsx +0 -1
  143. package/corpus/templates/tasks/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  144. package/corpus/templates/tasks/public/manifest.json +0 -1
  145. package/dist/agent/production-agent.d.ts +8 -0
  146. package/dist/agent/production-agent.js +67 -22
  147. package/dist/agent/run-manager.d.ts +7 -0
  148. package/dist/agent/run-manager.js +46 -3
  149. package/dist/agent/tool-approval-migrations.d.ts +40 -0
  150. package/dist/agent/tool-approval-migrations.js +51 -0
  151. package/dist/agent/tool-approval-store.js +5 -20
  152. package/dist/cli/templates-meta.js +2 -2
  153. package/dist/client/AgentPanel.js +10 -1
  154. package/dist/client/AssistantChat.d.ts +3 -0
  155. package/dist/client/AssistantChat.js +151 -141
  156. package/dist/client/agent-page/AgentTabsPage.js +2 -2
  157. package/dist/client/chat/attachment-adapters.js +8 -2
  158. package/dist/client/chat/tool-call-display.d.ts +1 -0
  159. package/dist/client/chat/tool-call-display.js +3 -1
  160. package/dist/client/chat-first.js +11 -5
  161. package/dist/client/guided-questions.d.ts +15 -1
  162. package/dist/client/guided-questions.js +33 -15
  163. package/dist/client/hooks/index.d.ts +1 -1
  164. package/dist/client/hooks/index.js +1 -1
  165. package/dist/client/org/OrgSwitcher.d.ts +3 -1
  166. package/dist/client/org/OrgSwitcher.js +22 -16
  167. package/dist/client/org/WorkspaceNotice.js +3 -1
  168. package/dist/client/resources/index.d.ts +1 -1
  169. package/dist/client/resources/index.js +1 -1
  170. package/dist/client/resources/use-mcp-servers.d.ts +1 -0
  171. package/dist/client/resources/use-mcp-servers.js +14 -0
  172. package/dist/client/settings/AccountSettingsCard.js +8 -4
  173. package/dist/client/settings/SettingsPanel.js +46 -13
  174. package/dist/client/settings/SettingsTabsPage.js +8 -3
  175. package/dist/client/sharing/ShareButton.d.ts +7 -1
  176. package/dist/client/sharing/ShareButton.js +14 -7
  177. package/dist/client/sharing/ShareDialog.js +5 -1
  178. package/dist/client/sharing/useShareButtonController.d.ts +4 -0
  179. package/dist/client/sharing/useShareButtonController.js +15 -0
  180. package/dist/client/sharing/useShareDialogController.d.ts +7 -0
  181. package/dist/client/sharing/useShareDialogController.js +14 -0
  182. package/dist/client/sse-event-processor.js +37 -0
  183. package/dist/client/use-session.d.ts +2 -0
  184. package/dist/client/use-session.js +69 -5
  185. package/dist/deploy/build.js +1 -1
  186. package/dist/file-upload/pre-upload-attachments.d.ts +3 -4
  187. package/dist/file-upload/pre-upload-attachments.js +65 -17
  188. package/dist/ingestion/index.d.ts +1 -0
  189. package/dist/ingestion/index.js +1 -0
  190. package/dist/ingestion/office.d.ts +3 -3
  191. package/dist/ingestion/office.js +24 -2
  192. package/dist/ingestion/spreadsheet.d.ts +41 -0
  193. package/dist/ingestion/spreadsheet.js +172 -0
  194. package/dist/integrations/adapters/slack.js +7 -3
  195. package/dist/integrations/webhook-handler.js +11 -3
  196. package/dist/localization/default-messages.d.ts +3 -0
  197. package/dist/localization/default-messages.js +3 -0
  198. package/dist/mcp/embed-app.js +20 -9
  199. package/dist/notifications/routes.d.ts +3 -3
  200. package/dist/oauth-tokens/migrations.d.ts +8 -0
  201. package/dist/oauth-tokens/migrations.js +36 -0
  202. package/dist/observability/routes.d.ts +5 -5
  203. package/dist/org/workspace-url.d.ts +8 -0
  204. package/dist/org/workspace-url.js +26 -2
  205. package/dist/progress/routes.d.ts +1 -1
  206. package/dist/secrets/routes.d.ts +6 -6
  207. package/dist/server/agent-chat/context-tools.js +27 -6
  208. package/dist/server/agent-chat-plugin.js +16 -8
  209. package/dist/server/auth.d.ts +0 -11
  210. package/dist/server/auth.js +37 -20
  211. package/dist/server/better-auth-migrations.js +23 -0
  212. package/dist/server/email-template.d.ts +5 -0
  213. package/dist/server/email-template.js +9 -0
  214. package/dist/server/embed-route.js +17 -5
  215. package/dist/server/identity-sso-store.d.ts +40 -66
  216. package/dist/server/identity-sso-store.js +187 -150
  217. package/dist/server/identity-sso.d.ts +17 -73
  218. package/dist/server/identity-sso.js +294 -297
  219. package/dist/server/onboarding-html.d.ts +0 -12
  220. package/dist/server/onboarding-html.js +46 -269
  221. package/dist/server/realtime-token.d.ts +1 -1
  222. package/dist/server/release-migrations.js +8 -0
  223. package/dist/server/transcribe-voice.d.ts +1 -1
  224. package/dist/shared/index.d.ts +1 -1
  225. package/dist/shared/index.js +1 -1
  226. package/dist/shared/workspace-app-id.d.ts +2 -0
  227. package/dist/shared/workspace-app-id.js +10 -0
  228. package/dist/sharing/actions/share-resource.d.ts +1 -0
  229. package/dist/sharing/actions/share-resource.js +20 -5
  230. package/dist/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  231. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  232. package/dist/templates/chat/app/root.tsx +0 -1
  233. package/dist/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  234. package/dist/templates/chat/public/manifest.json +0 -1
  235. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
  236. package/dist/templates/default/app/root.tsx +0 -1
  237. package/dist/templates/default/public/manifest.json +0 -1
  238. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
  239. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
  240. package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
  241. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
  242. package/docs/content/cross-app-sso.mdx +85 -27
  243. package/docs/content/template-mail.mdx +0 -6
  244. package/package.json +4 -3
  245. package/src/templates/chat/.agents/skills/sharing/SKILL.md +1 -1
  246. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +24 -0
  247. package/src/templates/chat/app/root.tsx +0 -1
  248. package/src/templates/chat/changelog/2026-08-11-browser-no-longer-offers-desktop-install.md +6 -0
  249. package/src/templates/chat/public/manifest.json +0 -1
  250. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +24 -0
  251. package/src/templates/default/app/root.tsx +0 -1
  252. package/src/templates/default/public/manifest.json +0 -1
  253. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +24 -0
  254. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +22 -11
  255. package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +1 -1
  256. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +24 -0
  257. package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +0 -6
  258. package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +0 -51
  259. package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +0 -6
@@ -84,6 +84,30 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
84
84
  page. If the needed context is not visible, ask for an export, transcript, or
85
85
  attachment and treat that artifact as imported source material.
86
86
 
87
+ ### Spreadsheet sources
88
+
89
+ Spreadsheet attachments are valid source artifacts for this workflow:
90
+
91
+ - CSV files can be read as tabular text. XLS and XLSX uploads are parsed into
92
+ bounded worksheet metadata and representative rows when the host supports
93
+ workbook ingestion. Treat the preview as untrusted user data, preserve the
94
+ workbook name and worksheet names, and record row/column limits and any
95
+ truncation in the source brief.
96
+ - A Google Sheets URL is a live provider source, not proof that the sheet is
97
+ readable. Use an authenticated Google Sheets/Drive connection and the
98
+ provider API catalog/docs/request path to read only the required sheet or
99
+ range. If that connection is unavailable, ask for a CSV/XLSX export or the
100
+ required connection; do not use a public export URL to bypass access.
101
+ - Decide whether the generated app needs a one-time snapshot or a refreshable
102
+ source. For a snapshot, pass bounded sample context and provenance to the
103
+ Builder handoff. For a live source, preserve the provider/file identity,
104
+ worksheet or range, and refresh semantics, then implement a scoped action for
105
+ reads or refreshes. Never copy workbook bytes, base64 data, credentials, or a
106
+ full unbounded sheet into SQL, application state, or the handoff prompt.
107
+ - Do not claim the app imported the whole workbook when only a preview was
108
+ available. Keep unreadable, partial, and failed source states distinct from
109
+ an empty sheet.
110
+
87
111
  For local code-agent runtimes, deliver a fresh app in a new directory,
88
112
  implement the repeatable workflow with buttons and agent handoffs, start its dev
89
113
  server, verify the main path, and continue through build/deployment handoff. Do
@@ -234,7 +234,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
234
234
  dangerouslySetInnerHTML={{ __html: LOCALE_INIT_SCRIPT }}
235
235
  />
236
236
  <link rel="icon" type="image/svg+xml" href={appPath("/favicon.svg")} />
237
- <link rel="manifest" href={appPath("/manifest.json")} />
238
237
  <meta name="theme-color" content="#3B82F6" />
239
238
  <meta name="mobile-web-app-capable" content="yes" />
240
239
  <meta
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Chrome no longer offers to install Mail as a desktop app.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Google sign-in now opens the Gmail connection flow directly
@@ -3,7 +3,6 @@
3
3
  "short_name": "Mail",
4
4
  "description": "Email client",
5
5
  "start_url": ".",
6
- "display": "standalone",
7
6
  "background_color": "#111111",
8
7
  "theme_color": "#3B82F6",
9
8
  "icons": [
@@ -36,16 +36,6 @@ export default createAuthPlugin({
36
36
  runLocalCommand:
37
37
  "npx @agent-native/core@latest create my-mail-app --template mail",
38
38
  },
39
- googleSignInNotice: {
40
- host: "mail.agent-native.com",
41
- title: "Google may show a warning",
42
- body: [
43
- "You'll see this screen because this demo uses Agent-Native's Google app, not a Google-reviewed public app.",
44
- "It's safe to continue: click Advanced, then “Go to … (unsafe)” to finish signing in.",
45
- ],
46
- continueLabel: "Continue to Google",
47
- cancelLabel: "Run locally",
48
- },
49
39
  // Gmail Pub/Sub push notifications POST here from Google's servers — no
50
40
  // user session. The handler itself verifies the OIDC token when
51
41
  // GMAIL_PUSH_AUDIENCE is configured.
@@ -189,7 +189,7 @@ The framework auto-mounts these actions in every template — no per-template bo
189
189
 
190
190
  | Action | Args | Purpose |
191
191
  | -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
192
- | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link used in the notification email. |
192
+ | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
193
193
  | `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
194
194
  | `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
195
195
  | `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
@@ -84,6 +84,30 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
84
84
  page. If the needed context is not visible, ask for an export, transcript, or
85
85
  attachment and treat that artifact as imported source material.
86
86
 
87
+ ### Spreadsheet sources
88
+
89
+ Spreadsheet attachments are valid source artifacts for this workflow:
90
+
91
+ - CSV files can be read as tabular text. XLS and XLSX uploads are parsed into
92
+ bounded worksheet metadata and representative rows when the host supports
93
+ workbook ingestion. Treat the preview as untrusted user data, preserve the
94
+ workbook name and worksheet names, and record row/column limits and any
95
+ truncation in the source brief.
96
+ - A Google Sheets URL is a live provider source, not proof that the sheet is
97
+ readable. Use an authenticated Google Sheets/Drive connection and the
98
+ provider API catalog/docs/request path to read only the required sheet or
99
+ range. If that connection is unavailable, ask for a CSV/XLSX export or the
100
+ required connection; do not use a public export URL to bypass access.
101
+ - Decide whether the generated app needs a one-time snapshot or a refreshable
102
+ source. For a snapshot, pass bounded sample context and provenance to the
103
+ Builder handoff. For a live source, preserve the provider/file identity,
104
+ worksheet or range, and refresh semantics, then implement a scoped action for
105
+ reads or refreshes. Never copy workbook bytes, base64 data, credentials, or a
106
+ full unbounded sheet into SQL, application state, or the handoff prompt.
107
+ - Do not claim the app imported the whole workbook when only a preview was
108
+ available. Keep unreadable, partial, and failed source states distinct from
109
+ an empty sheet.
110
+
87
111
  For local code-agent runtimes, deliver a fresh app in a new directory,
88
112
  implement the repeatable workflow with buttons and agent handoffs, start its dev
89
113
  server, verify the main path, and continue through build/deployment handoff. Do
@@ -377,6 +377,8 @@ const messages = {
377
377
  "Private by default. Invite people, share with your org, or set Public for anyone-with-link review.",
378
378
  peopleAccess: "People with {{noun}} access",
379
379
  generalAccess: "General {{noun}} access",
380
+ commenterRoleLabel: "Commenter",
381
+ commenterRoleDescription: "Can view and add comments",
380
382
  shareAria: "Share {{noun}}",
381
383
  share: "Share {{noun}}",
382
384
  shareThis: "Share this {{noun}}",
@@ -6218,6 +6218,12 @@ function PlanShareControl({
6218
6218
  shareUrlPlacement="top"
6219
6219
  peopleAccessLabel={t("plansPage.share.peopleAccess", { noun })}
6220
6220
  generalAccessLabel={t("plansPage.share.generalAccess", { noun })}
6221
+ roleCopy={{
6222
+ viewer: {
6223
+ label: t("plansPage.share.commenterRoleLabel"),
6224
+ description: t("plansPage.share.commenterRoleDescription"),
6225
+ },
6226
+ }}
6221
6227
  accessNote={buildShareAccessNote(t, noun)}
6222
6228
  visibilityCopy={buildShareVisibilityCopy(t, noun)}
6223
6229
  trigger="icon"
@@ -111,7 +111,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
111
111
  suppressHydrationWarning
112
112
  dangerouslySetInnerHTML={{ __html: LOCALE_INIT_SCRIPT }}
113
113
  />
114
- <link rel="manifest" href={appPath("/manifest.json")} />
115
114
  <meta name="theme-color" content="#71717A" />
116
115
  <meta name="mobile-web-app-capable" content="yes" />
117
116
  <meta
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Chrome no longer offers to install Plan as a desktop app.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Plan sharing now identifies viewers who can add comments
@@ -3,7 +3,6 @@
3
3
  "short_name": "Plan",
4
4
  "description": "Generate and review coding-agent plans with diagrams, wireframes, prototypes, annotations, sharing, and feedback.",
5
5
  "start_url": ".",
6
- "display": "standalone",
7
6
  "background_color": "#111111",
8
7
  "theme_color": "#71717A",
9
8
  "icons": [
@@ -189,7 +189,7 @@ The framework auto-mounts these actions in every template — no per-template bo
189
189
 
190
190
  | Action | Args | Purpose |
191
191
  | -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
192
- | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link used in the notification email. |
192
+ | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
193
193
  | `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
194
194
  | `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
195
195
  | `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
@@ -84,6 +84,30 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
84
84
  page. If the needed context is not visible, ask for an export, transcript, or
85
85
  attachment and treat that artifact as imported source material.
86
86
 
87
+ ### Spreadsheet sources
88
+
89
+ Spreadsheet attachments are valid source artifacts for this workflow:
90
+
91
+ - CSV files can be read as tabular text. XLS and XLSX uploads are parsed into
92
+ bounded worksheet metadata and representative rows when the host supports
93
+ workbook ingestion. Treat the preview as untrusted user data, preserve the
94
+ workbook name and worksheet names, and record row/column limits and any
95
+ truncation in the source brief.
96
+ - A Google Sheets URL is a live provider source, not proof that the sheet is
97
+ readable. Use an authenticated Google Sheets/Drive connection and the
98
+ provider API catalog/docs/request path to read only the required sheet or
99
+ range. If that connection is unavailable, ask for a CSV/XLSX export or the
100
+ required connection; do not use a public export URL to bypass access.
101
+ - Decide whether the generated app needs a one-time snapshot or a refreshable
102
+ source. For a snapshot, pass bounded sample context and provenance to the
103
+ Builder handoff. For a live source, preserve the provider/file identity,
104
+ worksheet or range, and refresh semantics, then implement a scoped action for
105
+ reads or refreshes. Never copy workbook bytes, base64 data, credentials, or a
106
+ full unbounded sheet into SQL, application state, or the handoff prompt.
107
+ - Do not claim the app imported the whole workbook when only a preview was
108
+ available. Keep unreadable, partial, and failed source states distinct from
109
+ an empty sheet.
110
+
87
111
  For local code-agent runtimes, deliver a fresh app in a new directory,
88
112
  implement the repeatable workflow with buttons and agent handoffs, start its dev
89
113
  server, verify the main path, and continue through build/deployment handoff. Do
@@ -824,6 +824,12 @@ export default function EditorToolbar({
824
824
  resourceType="deck"
825
825
  resourceId={deckId}
826
826
  resourceTitle={deckTitle}
827
+ roleCopy={{
828
+ viewer: {
829
+ label: t("editorToolbar.commenterRoleLabel"),
830
+ description: t("editorToolbar.commenterRoleDescription"),
831
+ },
832
+ }}
827
833
  shareUrl={primaryShareLink.url}
828
834
  shareUrlLabel={primaryShareLink.label}
829
835
  shareUrlDescription={primaryShareLink.description}
@@ -205,6 +205,8 @@ const messages = {
205
205
  usingDesignSystem: "Using {{title}}",
206
206
  usingLinkedDesignSystem: "Using a linked design system",
207
207
  viewOnly: "View only",
208
+ commenterRoleLabel: "Commenter",
209
+ commenterRoleDescription: "Can view and add comments",
208
210
  slideSettings: "Slide settings",
209
211
  layout: "Layout",
210
212
  background: "Background",
@@ -163,7 +163,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
163
163
  dangerouslySetInnerHTML={{ __html: LOCALE_INIT_SCRIPT }}
164
164
  />
165
165
  <link rel="icon" type="image/svg+xml" href={appPath("/favicon.svg")} />
166
- <link rel="manifest" href={appPath("/manifest.json")} />
167
166
  <meta name="theme-color" content="#EC4899" />
168
167
  <meta name="mobile-web-app-capable" content="yes" />
169
168
  <meta
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Chrome no longer offers to install Slides as a desktop app.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: improved
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Share dialog roles now use Commenter terminology for people who can view and add comments.
@@ -3,7 +3,6 @@
3
3
  "short_name": "Slides",
4
4
  "description": "AI slide deck creator",
5
5
  "start_url": ".",
6
- "display": "standalone",
7
6
  "background_color": "#111111",
8
7
  "theme_color": "#EC4899",
9
8
  "icons": [
@@ -189,7 +189,7 @@ The framework auto-mounts these actions in every template — no per-template bo
189
189
 
190
190
  | Action | Args | Purpose |
191
191
  | -------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------- |
192
- | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link used in the notification email. |
192
+ | `share-resource` | `resourceType, resourceId, principalType, principalId, role, notify?, resourceUrl?, message?` | Grant a user or org access. `notify` defaults to true for individual user shares; `resourceUrl` can provide the direct app link and `message` an optional short note for the notification email. |
193
193
  | `unshare-resource` | `resourceType, resourceId, principalType, principalId` | Revoke access. |
194
194
  | `list-resource-shares` | `resourceType, resourceId` | Current visibility + all share grants. |
195
195
  | `set-resource-visibility` | `resourceType, resourceId, visibility` | Change to `private` / `org` / `public`. |
@@ -84,6 +84,30 @@ private web access, invent an importer, add fake OAuth, or scrape a logged-in
84
84
  page. If the needed context is not visible, ask for an export, transcript, or
85
85
  attachment and treat that artifact as imported source material.
86
86
 
87
+ ### Spreadsheet sources
88
+
89
+ Spreadsheet attachments are valid source artifacts for this workflow:
90
+
91
+ - CSV files can be read as tabular text. XLS and XLSX uploads are parsed into
92
+ bounded worksheet metadata and representative rows when the host supports
93
+ workbook ingestion. Treat the preview as untrusted user data, preserve the
94
+ workbook name and worksheet names, and record row/column limits and any
95
+ truncation in the source brief.
96
+ - A Google Sheets URL is a live provider source, not proof that the sheet is
97
+ readable. Use an authenticated Google Sheets/Drive connection and the
98
+ provider API catalog/docs/request path to read only the required sheet or
99
+ range. If that connection is unavailable, ask for a CSV/XLSX export or the
100
+ required connection; do not use a public export URL to bypass access.
101
+ - Decide whether the generated app needs a one-time snapshot or a refreshable
102
+ source. For a snapshot, pass bounded sample context and provenance to the
103
+ Builder handoff. For a live source, preserve the provider/file identity,
104
+ worksheet or range, and refresh semantics, then implement a scoped action for
105
+ reads or refreshes. Never copy workbook bytes, base64 data, credentials, or a
106
+ full unbounded sheet into SQL, application state, or the handoff prompt.
107
+ - Do not claim the app imported the whole workbook when only a preview was
108
+ available. Keep unreadable, partial, and failed source states distinct from
109
+ an empty sheet.
110
+
87
111
  For local code-agent runtimes, deliver a fresh app in a new directory,
88
112
  implement the repeatable workflow with buttons and agent handoffs, start its dev
89
113
  server, verify the main path, and continue through build/deployment handoff. Do
@@ -85,7 +85,6 @@ export function Layout({ children }: { children: React.ReactNode }) {
85
85
  suppressHydrationWarning
86
86
  dangerouslySetInnerHTML={{ __html: LOCALE_INIT_SCRIPT }}
87
87
  />
88
- <link rel="manifest" href={appPath("/manifest.json")} />
89
88
  <meta name="theme-color" content="#18181B" />
90
89
  <meta name="mobile-web-app-capable" content="yes" />
91
90
  <meta
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-08-11
4
+ ---
5
+
6
+ Chrome no longer offers to install Tasks as a desktop app.
@@ -3,7 +3,6 @@
3
3
  "short_name": "Tasks",
4
4
  "description": "Workspace app for Tasks.",
5
5
  "start_url": ".",
6
- "display": "standalone",
7
6
  "background_color": "#111111",
8
7
  "theme_color": "#18181B",
9
8
  "icons": [
@@ -235,6 +235,14 @@ export interface ActionEntry {
235
235
  * `needsApproval` option. See `packages/core/docs/content/actions.mdx`.
236
236
  */
237
237
  needsApproval?: boolean | ((args: any, ctx?: import("../action.js").ActionRunContext) => boolean | Promise<boolean>);
238
+ /**
239
+ * The action hands control back to the user: once it succeeds the loop stops
240
+ * the turn instead of asking the model for another step, and any remaining
241
+ * tool calls in the same assistant message do not execute. Only for actions
242
+ * whose whole purpose is to wait on a human (`ask-question`) — telling the
243
+ * model to stop in the tool result does not make it stop.
244
+ */
245
+ endsTurn?: boolean;
238
246
  /** Which framework tool group contributed this action. Set by the framework,
239
247
  * never by an app: apps own their action names, and a tagged action is one
240
248
  * the app can switch off wholesale through `frameworkTools`. Tagged actions
@@ -36,7 +36,7 @@ import { EngineError } from "./engine/types.js";
36
36
  import { getDefaultMaxIterations, getDefaultMaxRunInputTokens, MAX_AGENT_MAX_ITERATIONS, MIN_AGENT_MAX_ITERATIONS, normalizeMaxIterations, normalizeMaxRunInputTokens, readAgentLoopSettings, } from "./loop-settings.js";
37
37
  import { maybeCompactThread, buildObservationalContext, hasObservationalMemory, serializeObservationalMemoryBlock, } from "./observational-memory/index.js";
38
38
  import { ProcessorChain, TripWire, toolCallsFromContent, } from "./processors.js";
39
- import { startRun, subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, abortRunDurably, abortTurnDurably, tryClaimRunSlot, isHostedRuntime, resolveRunSoftTimeoutMs, resolveRunToolTimeoutCeilingMs, } from "./run-manager.js";
39
+ import { startRun, subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, abortRunDurably, abortTurnDurably, tryClaimRunSlot, isHostedRuntime, resolveRunSoftTimeoutMs, resolveRunToolTimeoutCeilingMs, endsAfterCompletedToolWithoutAssistantFinal, } from "./run-manager.js";
40
40
  import { writeLedgerEntry, readLedgerEntry, clearLedgerForThread, insertRun, insertRunEvent, isTurnAborted, markRunAborted, updateRunHeartbeat, updateRunStatusIfRunning, setRunError, setRunTerminalReason, claimBackgroundRun, readBackgroundRunClaim, recordRunDiagnostic, countRunsForTurn, RUN_DIAG_STAGE, UNCLAIMED_BACKGROUND_RUN_GRACE_MS, } from "./run-store.js";
41
41
  import { buildCurrentTimeUserContext } from "./runtime-context.js";
42
42
  import { consumeAgentToolApproval, createAgentToolApproval, } from "./tool-approval-store.js";
@@ -3823,6 +3823,23 @@ export async function runAgentLoop(opts) {
3823
3823
  emptyFinalResponseRetries = 0;
3824
3824
  flushUnstreamedAssistantText();
3825
3825
  let requestedActionStop = null;
3826
+ // An `endsTurn` action ran and handed control to the user. Distinct from
3827
+ // `requestedActionStop`, which also covers failure stops that must not
3828
+ // suppress the remaining tool calls.
3829
+ let turnYieldedToUser = false;
3830
+ // Called by every path that completes a tool call successfully — a fresh
3831
+ // invocation, a journal replay, a ledger recovery. A replayed
3832
+ // `ask-question` that skipped this would let the resumed run ask a second
3833
+ // time over the card the user is already looking at.
3834
+ const noteToolCallSucceeded = (actionEntry) => {
3835
+ if (actionEntry.endsTurn !== true)
3836
+ return;
3837
+ turnYieldedToUser = true;
3838
+ requestedActionStop ??= {
3839
+ message: "Waiting for your answer before continuing.",
3840
+ errorCode: "awaiting-user-input",
3841
+ };
3842
+ };
3826
3843
  const noteRepeatedToolCall = (toolName, input) => {
3827
3844
  const key = toolCallCacheKey(toolName, input);
3828
3845
  const count = (repeatedToolCalls.get(key) ?? 0) + 1;
@@ -4167,6 +4184,7 @@ export async function runAgentLoop(opts) {
4167
4184
  completedSideEffect: true,
4168
4185
  });
4169
4186
  recordToolResult(result, false);
4187
+ noteToolCallSucceeded(actionEntry);
4170
4188
  return {
4171
4189
  type: "tool-result",
4172
4190
  toolCallId: toolCall.id,
@@ -4220,6 +4238,7 @@ export async function runAgentLoop(opts) {
4220
4238
  ...(actionEntry.chatUI ? { chatUI: actionEntry.chatUI } : {}),
4221
4239
  });
4222
4240
  recordToolResult(result, false);
4241
+ noteToolCallSucceeded(actionEntry);
4223
4242
  return {
4224
4243
  type: "tool-result",
4225
4244
  toolCallId: toolCall.id,
@@ -4645,6 +4664,7 @@ export async function runAgentLoop(opts) {
4645
4664
  });
4646
4665
  recordToolResult(result, isError);
4647
4666
  if (!isError) {
4667
+ noteToolCallSucceeded(actionEntry);
4648
4668
  if (cacheKey) {
4649
4669
  readOnlyToolResultCache.set(cacheKey, result);
4650
4670
  }
@@ -4715,7 +4735,46 @@ export async function runAgentLoop(opts) {
4715
4735
  parallelBatchKind = null;
4716
4736
  toolResultParts.push(...(await Promise.all(batch.map(runToolCall))));
4717
4737
  };
4738
+ // An `endsTurn` action already handed control to the user, so the rest of
4739
+ // this assistant message belongs to a turn that is over. Report those calls
4740
+ // as not executed rather than running them: a second `ask-question` would
4741
+ // overwrite the first one's card before anyone could answer it.
4742
+ const skipToolCallAfterYield = (toolCall) => {
4743
+ const result = `Not executed: ${toolCall.name} was called after an action that ends the turn. ` +
4744
+ `The turn is paused for the user's answer — call it again on a later turn if still needed.`;
4745
+ send({
4746
+ type: "tool_start",
4747
+ id: toolCall.id,
4748
+ tool: toolCall.name,
4749
+ input: toolCall.input,
4750
+ });
4751
+ send({
4752
+ type: "tool_done",
4753
+ id: toolCall.id,
4754
+ tool: toolCall.name,
4755
+ input: toolCall.input,
4756
+ result,
4757
+ completedSideEffect: false,
4758
+ });
4759
+ toolResultHistory.push({
4760
+ name: toolCall.name,
4761
+ content: result,
4762
+ isError: false,
4763
+ });
4764
+ return {
4765
+ type: "tool-result",
4766
+ toolCallId: toolCall.id,
4767
+ toolName: toolCall.name,
4768
+ toolInput: JSON.stringify(toolCall.input ?? {}),
4769
+ content: result,
4770
+ };
4771
+ };
4718
4772
  for (const toolCall of toolCallParts) {
4773
+ if (turnYieldedToUser) {
4774
+ await flushParallelBatch();
4775
+ toolResultParts.push(skipToolCallAfterYield(toolCall));
4776
+ continue;
4777
+ }
4719
4778
  const batchKind = getParallelBatchKind(toolCall);
4720
4779
  if (batchKind) {
4721
4780
  if (parallelBatchKind && parallelBatchKind !== batchKind) {
@@ -4829,6 +4888,13 @@ export async function runAgentLoop(opts) {
4829
4888
  message: terminalActionStop.message,
4830
4889
  });
4831
4890
  }
4891
+ else if (terminalActionStop?.errorCode === "awaiting-user-input") {
4892
+ reportOutcome({
4893
+ state: "input_required",
4894
+ code: "awaiting_user_input",
4895
+ message: terminalActionStop.message,
4896
+ });
4897
+ }
4832
4898
  else if (terminalActionStop) {
4833
4899
  reportOutcome({
4834
4900
  state: "failed",
@@ -4970,27 +5036,6 @@ export function lastUnfinishedPreparingActionToolFromEvents(events) {
4970
5036
  }
4971
5037
  return latest?.tool;
4972
5038
  }
4973
- function endsAfterCompletedToolWithoutAssistantFinal(run) {
4974
- let completedToolAfterLastAssistantText = false;
4975
- for (const { event } of run.events) {
4976
- if (event.type === "text" && event.text.trim().length > 0) {
4977
- completedToolAfterLastAssistantText = false;
4978
- continue;
4979
- }
4980
- if (event.type === "tool_done" && event.isError !== true) {
4981
- completedToolAfterLastAssistantText = true;
4982
- continue;
4983
- }
4984
- if (event.type === "clear" ||
4985
- event.type === "error" ||
4986
- event.type === "missing_api_key" ||
4987
- event.type === "auto_continue" ||
4988
- event.type === "loop_limit") {
4989
- completedToolAfterLastAssistantText = false;
4990
- }
4991
- }
4992
- return completedToolAfterLastAssistantText;
4993
- }
4994
5039
  function lastUnfinishedPreparingActionTool(run) {
4995
5040
  return lastUnfinishedPreparingActionToolFromEvents(run.events.map(({ event }) => event));
4996
5041
  }
@@ -317,6 +317,13 @@ export declare function isHostedRuntime(): boolean;
317
317
  export declare function resolveRunSoftTimeoutMs(overrideMs?: number, options?: ResolveRunSoftTimeoutOptions): number;
318
318
  export declare function resolveCompletedRunRetentionMs(): number;
319
319
  export declare function resolveErroredRunRetentionMs(): number;
320
+ /**
321
+ * A completed tool with no later assistant text is an unfinished turn, not a
322
+ * successful terminal response. Keep this predicate beside the run-manager's
323
+ * terminal synthesis so the run-manager and production continuation paths use
324
+ * the same boundary evidence.
325
+ */
326
+ export declare function endsAfterCompletedToolWithoutAssistantFinal(run: ActiveRun): boolean;
320
327
  /**
321
328
  * Start a new agent run in the background.
322
329
  * `runFn` receives a `send` callback and an `AbortSignal`.
@@ -416,6 +416,34 @@ function isTerminalRunEvent(event) {
416
416
  event.type === "loop_limit" ||
417
417
  event.type === "auto_continue");
418
418
  }
419
+ /**
420
+ * A completed tool with no later assistant text is an unfinished turn, not a
421
+ * successful terminal response. Keep this predicate beside the run-manager's
422
+ * terminal synthesis so the run-manager and production continuation paths use
423
+ * the same boundary evidence.
424
+ */
425
+ export function endsAfterCompletedToolWithoutAssistantFinal(run) {
426
+ let completedToolAfterLastAssistantText = false;
427
+ for (const { event } of run.events) {
428
+ if (event.type === "text" && event.text.trim().length > 0) {
429
+ completedToolAfterLastAssistantText = false;
430
+ continue;
431
+ }
432
+ if (event.type === "tool_done" && event.isError !== true) {
433
+ completedToolAfterLastAssistantText =
434
+ event.chatUI === undefined && event.mcpApp === undefined;
435
+ continue;
436
+ }
437
+ if (event.type === "clear" ||
438
+ event.type === "error" ||
439
+ event.type === "missing_api_key" ||
440
+ event.type === "auto_continue" ||
441
+ event.type === "loop_limit") {
442
+ completedToolAfterLastAssistantText = false;
443
+ }
444
+ }
445
+ return completedToolAfterLastAssistantText;
446
+ }
419
447
  function terminalEventForcesErroredStatus(event) {
420
448
  return event?.type === "error" || event?.type === "missing_api_key";
421
449
  }
@@ -1220,6 +1248,20 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
1220
1248
  terminalEventForcesErroredStatus(terminalEvent)
1221
1249
  ? "errored"
1222
1250
  : "completed";
1251
+ const shouldAutoContinueAfterCompletedTool = finalStatus === "completed" &&
1252
+ endsAfterCompletedToolWithoutAssistantFinal(run) &&
1253
+ (!terminalEventForCompletion ||
1254
+ (terminalEventForCompletion.event.type === "done" &&
1255
+ terminalEventForCompletion.event.reason !== "user"));
1256
+ const completedToolContinuationEvent = shouldAutoContinueAfterCompletedTool
1257
+ ? {
1258
+ type: "auto_continue",
1259
+ reason: "stream_ended",
1260
+ }
1261
+ : null;
1262
+ if (completedToolContinuationEvent) {
1263
+ terminalEvent = completedToolContinuationEvent;
1264
+ }
1223
1265
  const terminalReason = terminalReasonForRun(finalStatus, terminalEvent, run.abortReason, completionError);
1224
1266
  // A run that stopped at a continuation boundary did not finish, so it is
1225
1267
  // not `completed`. Persisted directly here rather than left for
@@ -1247,8 +1289,9 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
1247
1289
  // insertRunEvent's `ON CONFLICT (run_id, seq) DO NOTHING`, so the
1248
1290
  // client would never see the terminal/continuation signal. We always
1249
1291
  // re-stamp the seq at emit time (max-seq+1) just below.
1250
- const terminalEvent = finalStatus === "completed"
1251
- ? (terminalEventForCompletion?.event ?? { type: "done" })
1292
+ const terminalEventToEmit = finalStatus === "completed"
1293
+ ? (completedToolContinuationEvent ??
1294
+ terminalEventForCompletion?.event ?? { type: "done" })
1252
1295
  : terminalEventForCompletion?.event.type === "error" ||
1253
1296
  terminalEventForCompletion?.event.type === "missing_api_key"
1254
1297
  ? terminalEventForCompletion.event
@@ -1274,7 +1317,7 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
1274
1317
  // terminal event was stashed.
1275
1318
  const terminal = {
1276
1319
  seq: run.events.length,
1277
- event: terminalEvent,
1320
+ event: terminalEventToEmit,
1278
1321
  };
1279
1322
  try {
1280
1323
  await emitRunEvent(terminal, { surfacePersistenceError: true });