@agent-native/core 0.99.3 → 0.100.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 (382) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +21 -0
  3. package/corpus/core/docs/content/agent-surfaces.mdx +43 -0
  4. package/corpus/core/docs/content/external-agents.mdx +11 -0
  5. package/corpus/core/docs/content/locales/ar-SA/agent-surfaces.mdx +30 -0
  6. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +9 -0
  7. package/corpus/core/docs/content/locales/de-DE/agent-surfaces.mdx +34 -0
  8. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +10 -0
  9. package/corpus/core/docs/content/locales/es-ES/agent-surfaces.mdx +34 -0
  10. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +10 -0
  11. package/corpus/core/docs/content/locales/fr-FR/agent-surfaces.mdx +34 -0
  12. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +11 -0
  13. package/corpus/core/docs/content/locales/hi-IN/agent-surfaces.mdx +31 -0
  14. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +9 -0
  15. package/corpus/core/docs/content/locales/ja-JP/agent-surfaces.mdx +32 -0
  16. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +10 -0
  17. package/corpus/core/docs/content/locales/ko-KR/agent-surfaces.mdx +32 -0
  18. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +9 -0
  19. package/corpus/core/docs/content/locales/pt-BR/agent-surfaces.mdx +33 -0
  20. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +10 -0
  21. package/corpus/core/docs/content/locales/zh-CN/agent-surfaces.mdx +29 -0
  22. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +8 -0
  23. package/corpus/core/docs/content/locales/zh-TW/agent-surfaces.mdx +29 -0
  24. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +8 -0
  25. package/corpus/core/package.json +1 -1
  26. package/corpus/core/src/agent/context-xray/actions/context-evict.ts +11 -0
  27. package/corpus/core/src/agent/context-xray/actions/context-pin.ts +11 -0
  28. package/corpus/core/src/agent/context-xray/actions/context-preview-get.ts +134 -0
  29. package/corpus/core/src/agent/context-xray/actions/context-restore.ts +11 -0
  30. package/corpus/core/src/agent/context-xray/actions/errors.ts +20 -0
  31. package/corpus/core/src/agent/context-xray/manifest.ts +106 -7
  32. package/corpus/core/src/agent/engine/context-directives-transform.ts +5 -1
  33. package/corpus/core/src/agent/production-agent.ts +100 -38
  34. package/corpus/core/src/agent/run-loop-with-resume.ts +7 -2
  35. package/corpus/core/src/client/AgentPanel.tsx +35 -8
  36. package/corpus/core/src/client/agent-page/AgentContextTab.tsx +501 -0
  37. package/corpus/core/src/client/agent-page/AgentJobsTab.tsx +370 -0
  38. package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +1084 -0
  39. package/corpus/core/src/client/agent-page/types.ts +18 -0
  40. package/corpus/core/src/client/agent-page/use-jobs.ts +150 -0
  41. package/corpus/core/src/client/context-xray/ContextMeter.tsx +22 -5
  42. package/corpus/core/src/client/context-xray/ContextTreemap.tsx +16 -1
  43. package/corpus/core/src/client/context-xray/ContextXRayPanel.tsx +168 -3
  44. package/corpus/core/src/client/context-xray/format.ts +6 -0
  45. package/corpus/core/src/client/index.ts +6 -0
  46. package/corpus/core/src/client/resources/ResourcesPanel.tsx +51 -23
  47. package/corpus/core/src/client/settings/AutomationsSection.tsx +407 -387
  48. package/corpus/core/src/jobs/actions/list-recurring-jobs.ts +105 -0
  49. package/corpus/core/src/jobs/actions/manage-recurring-job.ts +85 -0
  50. package/corpus/core/src/jobs/tools.ts +1 -1
  51. package/corpus/core/src/localization/default-messages.ts +110 -0
  52. package/corpus/core/src/mcp/build-server.ts +1 -0
  53. package/corpus/core/src/mcp/connect-route.ts +62 -65
  54. package/corpus/core/src/server/action-discovery.ts +23 -0
  55. package/corpus/core/src/server/agent-chat/prompt-resources.ts +174 -2
  56. package/corpus/core/src/server/agent-chat-plugin.ts +175 -2
  57. package/corpus/core/src/server/auth.ts +1 -7
  58. package/corpus/core/src/server/google-oauth.ts +1 -7
  59. package/corpus/core/src/server/workspace-oauth.ts +31 -0
  60. package/corpus/core/src/shared/context-xray.ts +84 -1
  61. package/corpus/core/src/shared/mcp-connect-content.ts +130 -0
  62. package/corpus/core/src/templates/default/app/routes/_index.tsx +11 -0
  63. package/corpus/core/src/templates/default/app/routes/agent.tsx +33 -0
  64. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  65. package/corpus/core/src/templates/workspace-core/.agents/skills/agent-page/SKILL.md +59 -0
  66. package/corpus/core/src/templates/workspace-core/.agents/skills/context-xray/SKILL.md +25 -0
  67. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +7 -0
  68. package/corpus/core/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +9 -0
  69. package/corpus/core/src/triggers/actions/list-automations.ts +99 -0
  70. package/corpus/core/src/triggers/actions/manage-automation.ts +78 -0
  71. package/corpus/templates/analytics/actions/data-source-status.ts +33 -15
  72. package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
  73. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +149 -24
  74. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +17 -0
  75. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
  76. package/corpus/templates/analytics/app/components/layout/Layout.tsx +1 -0
  77. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +8 -0
  78. package/corpus/templates/analytics/app/i18n/zh-TW.ts +1 -0
  79. package/corpus/templates/analytics/app/i18n-data.ts +1 -0
  80. package/corpus/templates/analytics/app/routes/agent.tsx +5 -0
  81. package/corpus/templates/analytics/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  82. package/corpus/templates/analytics/changelog/2026-07-13-analytics-answers-can-use-built-in-first-party-event-data.md +6 -0
  83. package/corpus/templates/analytics/changelog/2026-07-13-chart-legends-can-filter-to-one-series-or-hide-a-series-on-h.md +6 -0
  84. package/corpus/templates/analytics/changelog/2026-07-13-gpt-5-6-luna-answers-now-recover-normally-instead-of-showing.md +6 -0
  85. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -2
  86. package/corpus/templates/assets/app/components/layout/Header.tsx +1 -0
  87. package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -0
  88. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -0
  89. package/corpus/templates/assets/app/routes/agent.tsx +5 -0
  90. package/corpus/templates/assets/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  91. package/corpus/templates/brain/app/components/layout/Layout.tsx +1 -0
  92. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +4 -1
  93. package/corpus/templates/brain/app/lib/brain.ts +11 -0
  94. package/corpus/templates/brain/app/root.tsx +15 -1
  95. package/corpus/templates/brain/app/routes/agent.tsx +11 -0
  96. package/corpus/templates/brain/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  97. package/corpus/templates/calendar/AGENTS.md +9 -0
  98. package/corpus/templates/calendar/actions/list-events.ts +659 -44
  99. package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +1 -0
  100. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +2 -0
  101. package/corpus/templates/calendar/app/root.tsx +17 -1
  102. package/corpus/templates/calendar/app/routes/_app.agent.tsx +25 -0
  103. package/corpus/templates/calendar/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  104. package/corpus/templates/calendar/changelog/2026-07-13-calendar-inventory-reads-report-source-coverage.md +6 -0
  105. package/corpus/templates/calendar/server/lib/calendar-connector-catalog.ts +8 -0
  106. package/corpus/templates/calendar/server/lib/google-calendar.ts +173 -51
  107. package/corpus/templates/calendar/server/lib/ical-fetcher.ts +13 -2
  108. package/corpus/templates/calendar/server/plugins/agent-chat.ts +5 -3
  109. package/corpus/templates/calendar/shared/api.ts +2 -0
  110. package/corpus/templates/chat/app/components/layout/Header.tsx +1 -0
  111. package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
  112. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +7 -0
  113. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +3 -0
  114. package/corpus/templates/chat/app/root.tsx +24 -2
  115. package/corpus/templates/chat/app/routes/agent.tsx +15 -0
  116. package/corpus/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +6 -0
  117. package/corpus/templates/clips/app/components/library/library-layout.tsx +8 -0
  118. package/corpus/templates/clips/app/i18n/ar-SA.ts +2 -0
  119. package/corpus/templates/clips/app/i18n/de-DE.ts +2 -0
  120. package/corpus/templates/clips/app/i18n/en-US.ts +2 -0
  121. package/corpus/templates/clips/app/i18n/es-ES.ts +2 -0
  122. package/corpus/templates/clips/app/i18n/fr-FR.ts +2 -0
  123. package/corpus/templates/clips/app/i18n/hi-IN.ts +2 -0
  124. package/corpus/templates/clips/app/i18n/ja-JP.ts +2 -0
  125. package/corpus/templates/clips/app/i18n/ko-KR.ts +2 -0
  126. package/corpus/templates/clips/app/i18n/pt-BR.ts +2 -0
  127. package/corpus/templates/clips/app/i18n/zh-CN.ts +2 -0
  128. package/corpus/templates/clips/app/i18n/zh-TW.ts +2 -0
  129. package/corpus/templates/clips/app/root.tsx +7 -1
  130. package/corpus/templates/clips/app/routes/_app.agent.tsx +15 -0
  131. package/corpus/templates/clips/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  132. package/corpus/templates/content/app/components/layout/Layout.tsx +1 -0
  133. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +36 -0
  134. package/corpus/templates/content/app/i18n/zh-TW.ts +2 -0
  135. package/corpus/templates/content/app/i18n-data.ts +44 -6
  136. package/corpus/templates/content/app/root.tsx +8 -0
  137. package/corpus/templates/content/app/routes/_app.agent.tsx +15 -0
  138. package/corpus/templates/content/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  139. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -0
  140. package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -0
  141. package/corpus/templates/design/app/i18n/zh-TW.ts +2 -0
  142. package/corpus/templates/design/app/i18n-data.ts +20 -0
  143. package/corpus/templates/design/app/root.tsx +7 -1
  144. package/corpus/templates/design/app/routes/agent.tsx +15 -0
  145. package/corpus/templates/design/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  146. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +10 -1
  147. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +2 -0
  148. package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
  149. package/corpus/templates/dispatch/app/root.tsx +7 -2
  150. package/corpus/templates/dispatch/app/routes/agent.tsx +18 -0
  151. package/corpus/templates/dispatch/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  152. package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
  153. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +35 -0
  154. package/corpus/templates/forms/app/i18n/ar-SA.ts +2 -0
  155. package/corpus/templates/forms/app/i18n/de-DE.ts +2 -0
  156. package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
  157. package/corpus/templates/forms/app/i18n/es-ES.ts +2 -0
  158. package/corpus/templates/forms/app/i18n/fr-FR.ts +2 -0
  159. package/corpus/templates/forms/app/i18n/hi-IN.ts +2 -0
  160. package/corpus/templates/forms/app/i18n/ja-JP.ts +2 -0
  161. package/corpus/templates/forms/app/i18n/ko-KR.ts +2 -0
  162. package/corpus/templates/forms/app/i18n/pt-BR.ts +2 -0
  163. package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
  164. package/corpus/templates/forms/app/i18n/zh-TW.ts +2 -0
  165. package/corpus/templates/forms/app/root.tsx +6 -1
  166. package/corpus/templates/forms/app/routes/_app.agent.tsx +15 -0
  167. package/corpus/templates/forms/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  168. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +14 -2
  169. package/corpus/templates/macros/app/components/layout/Header.tsx +1 -0
  170. package/corpus/templates/macros/app/root.tsx +17 -2
  171. package/corpus/templates/macros/app/routes/agent.tsx +15 -0
  172. package/corpus/templates/macros/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  173. package/corpus/templates/mail/AGENTS.md +12 -0
  174. package/corpus/templates/mail/actions/list-emails.ts +486 -4
  175. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +42 -0
  176. package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +6 -0
  177. package/corpus/templates/mail/app/routes/agent.tsx +15 -0
  178. package/corpus/templates/mail/changelog/2026-07-13-coverage-aware-connected-inbox-inventory.md +6 -0
  179. package/corpus/templates/mail/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  180. package/corpus/templates/mail/server/db/schema.ts +17 -0
  181. package/corpus/templates/mail/server/lib/google-auth.ts +33 -5
  182. package/corpus/templates/mail/server/lib/inventory-cursor.ts +406 -0
  183. package/corpus/templates/mail/server/lib/list-inbox-emails.ts +21 -2
  184. package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +8 -0
  185. package/corpus/templates/mail/server/plugins/agent-chat.ts +4 -9
  186. package/corpus/templates/mail/server/plugins/db.ts +20 -0
  187. package/corpus/templates/plan/app/components/layout/Header.tsx +1 -0
  188. package/corpus/templates/plan/app/components/layout/Layout.tsx +1 -0
  189. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -0
  190. package/corpus/templates/plan/app/root.tsx +8 -0
  191. package/corpus/templates/plan/app/routes/agent.tsx +15 -0
  192. package/corpus/templates/plan/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  193. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -0
  194. package/corpus/templates/slides/app/components/layout/Layout.tsx +1 -0
  195. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +2 -0
  196. package/corpus/templates/slides/app/root.tsx +10 -1
  197. package/corpus/templates/slides/app/routes/agent.tsx +15 -0
  198. package/corpus/templates/slides/changelog/2026-07-13-new-agent-page-see-and-manage-your-agent-s-context-files-con.md +6 -0
  199. package/dist/agent/context-xray/actions/context-evict.js +5 -2
  200. package/dist/agent/context-xray/actions/context-evict.js.map +1 -1
  201. package/dist/agent/context-xray/actions/context-pin.js +5 -2
  202. package/dist/agent/context-xray/actions/context-pin.js.map +1 -1
  203. package/dist/agent/context-xray/actions/context-preview-get.d.ts +17 -0
  204. package/dist/agent/context-xray/actions/context-preview-get.d.ts.map +1 -0
  205. package/dist/agent/context-xray/actions/context-preview-get.js +94 -0
  206. package/dist/agent/context-xray/actions/context-preview-get.js.map +1 -0
  207. package/dist/agent/context-xray/actions/context-restore.js +5 -2
  208. package/dist/agent/context-xray/actions/context-restore.js.map +1 -1
  209. package/dist/agent/context-xray/actions/errors.d.ts +3 -0
  210. package/dist/agent/context-xray/actions/errors.d.ts.map +1 -1
  211. package/dist/agent/context-xray/actions/errors.js +6 -0
  212. package/dist/agent/context-xray/actions/errors.js.map +1 -1
  213. package/dist/agent/context-xray/manifest.d.ts +18 -1
  214. package/dist/agent/context-xray/manifest.d.ts.map +1 -1
  215. package/dist/agent/context-xray/manifest.js +68 -6
  216. package/dist/agent/context-xray/manifest.js.map +1 -1
  217. package/dist/agent/engine/context-directives-transform.d.ts +2 -0
  218. package/dist/agent/engine/context-directives-transform.d.ts.map +1 -1
  219. package/dist/agent/engine/context-directives-transform.js +2 -1
  220. package/dist/agent/engine/context-directives-transform.js.map +1 -1
  221. package/dist/agent/production-agent.d.ts +15 -0
  222. package/dist/agent/production-agent.d.ts.map +1 -1
  223. package/dist/agent/production-agent.js +74 -36
  224. package/dist/agent/production-agent.js.map +1 -1
  225. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  226. package/dist/agent/run-loop-with-resume.js +6 -3
  227. package/dist/agent/run-loop-with-resume.js.map +1 -1
  228. package/dist/client/AgentPanel.d.ts +5 -1
  229. package/dist/client/AgentPanel.d.ts.map +1 -1
  230. package/dist/client/AgentPanel.js +9 -11
  231. package/dist/client/AgentPanel.js.map +1 -1
  232. package/dist/client/agent-page/AgentContextTab.d.ts +5 -0
  233. package/dist/client/agent-page/AgentContextTab.d.ts.map +1 -0
  234. package/dist/client/agent-page/AgentContextTab.js +202 -0
  235. package/dist/client/agent-page/AgentContextTab.js.map +1 -0
  236. package/dist/client/agent-page/AgentJobsTab.d.ts +3 -0
  237. package/dist/client/agent-page/AgentJobsTab.d.ts.map +1 -0
  238. package/dist/client/agent-page/AgentJobsTab.js +98 -0
  239. package/dist/client/agent-page/AgentJobsTab.js.map +1 -0
  240. package/dist/client/agent-page/AgentTabsPage.d.ts +20 -0
  241. package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -0
  242. package/dist/client/agent-page/AgentTabsPage.js +420 -0
  243. package/dist/client/agent-page/AgentTabsPage.js.map +1 -0
  244. package/dist/client/agent-page/types.d.ts +17 -0
  245. package/dist/client/agent-page/types.d.ts.map +1 -0
  246. package/dist/client/agent-page/types.js +9 -0
  247. package/dist/client/agent-page/types.js.map +1 -0
  248. package/dist/client/agent-page/use-jobs.d.ts +61 -0
  249. package/dist/client/agent-page/use-jobs.d.ts.map +1 -0
  250. package/dist/client/agent-page/use-jobs.js +71 -0
  251. package/dist/client/agent-page/use-jobs.js.map +1 -0
  252. package/dist/client/context-xray/ContextMeter.d.ts +3 -1
  253. package/dist/client/context-xray/ContextMeter.d.ts.map +1 -1
  254. package/dist/client/context-xray/ContextMeter.js +14 -5
  255. package/dist/client/context-xray/ContextMeter.js.map +1 -1
  256. package/dist/client/context-xray/ContextTreemap.d.ts +3 -2
  257. package/dist/client/context-xray/ContextTreemap.d.ts.map +1 -1
  258. package/dist/client/context-xray/ContextTreemap.js +9 -1
  259. package/dist/client/context-xray/ContextTreemap.js.map +1 -1
  260. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  261. package/dist/client/context-xray/ContextXRayPanel.js +95 -20
  262. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  263. package/dist/client/context-xray/format.d.ts.map +1 -1
  264. package/dist/client/context-xray/format.js +12 -0
  265. package/dist/client/context-xray/format.js.map +1 -1
  266. package/dist/client/index.d.ts +3 -0
  267. package/dist/client/index.d.ts.map +1 -1
  268. package/dist/client/index.js +1 -0
  269. package/dist/client/index.js.map +1 -1
  270. package/dist/client/resources/ResourcesPanel.d.ts +9 -1
  271. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  272. package/dist/client/resources/ResourcesPanel.js +26 -10
  273. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  274. package/dist/client/settings/AutomationsSection.d.ts +9 -0
  275. package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
  276. package/dist/client/settings/AutomationsSection.js +128 -147
  277. package/dist/client/settings/AutomationsSection.js.map +1 -1
  278. package/dist/collab/routes.d.ts +1 -1
  279. package/dist/collab/struct-routes.d.ts +1 -1
  280. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  281. package/dist/jobs/actions/list-recurring-jobs.d.ts +21 -0
  282. package/dist/jobs/actions/list-recurring-jobs.d.ts.map +1 -0
  283. package/dist/jobs/actions/list-recurring-jobs.js +74 -0
  284. package/dist/jobs/actions/list-recurring-jobs.js.map +1 -0
  285. package/dist/jobs/actions/manage-recurring-job.d.ts +18 -0
  286. package/dist/jobs/actions/manage-recurring-job.d.ts.map +1 -0
  287. package/dist/jobs/actions/manage-recurring-job.js +68 -0
  288. package/dist/jobs/actions/manage-recurring-job.js.map +1 -0
  289. package/dist/jobs/tools.d.ts +13 -0
  290. package/dist/jobs/tools.d.ts.map +1 -1
  291. package/dist/jobs/tools.js +1 -1
  292. package/dist/jobs/tools.js.map +1 -1
  293. package/dist/localization/default-messages.d.ts +96 -0
  294. package/dist/localization/default-messages.d.ts.map +1 -1
  295. package/dist/localization/default-messages.js +96 -0
  296. package/dist/localization/default-messages.js.map +1 -1
  297. package/dist/mcp/build-server.d.ts.map +1 -1
  298. package/dist/mcp/build-server.js +1 -0
  299. package/dist/mcp/build-server.js.map +1 -1
  300. package/dist/mcp/connect-route.d.ts.map +1 -1
  301. package/dist/mcp/connect-route.js +44 -59
  302. package/dist/mcp/connect-route.js.map +1 -1
  303. package/dist/notifications/routes.d.ts +1 -1
  304. package/dist/observability/routes.d.ts +5 -5
  305. package/dist/progress/routes.d.ts +1 -1
  306. package/dist/resources/handlers.d.ts +3 -3
  307. package/dist/secrets/routes.d.ts +9 -9
  308. package/dist/server/action-discovery.d.ts.map +1 -1
  309. package/dist/server/action-discovery.js +23 -0
  310. package/dist/server/action-discovery.js.map +1 -1
  311. package/dist/server/agent-chat/prompt-resources.d.ts +14 -0
  312. package/dist/server/agent-chat/prompt-resources.d.ts.map +1 -1
  313. package/dist/server/agent-chat/prompt-resources.js +139 -2
  314. package/dist/server/agent-chat/prompt-resources.js.map +1 -1
  315. package/dist/server/agent-chat-plugin.d.ts +1 -0
  316. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  317. package/dist/server/agent-chat-plugin.js +136 -3
  318. package/dist/server/agent-chat-plugin.js.map +1 -1
  319. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  320. package/dist/server/auth.d.ts.map +1 -1
  321. package/dist/server/auth.js +1 -4
  322. package/dist/server/auth.js.map +1 -1
  323. package/dist/server/google-oauth.d.ts.map +1 -1
  324. package/dist/server/google-oauth.js +1 -4
  325. package/dist/server/google-oauth.js.map +1 -1
  326. package/dist/server/workspace-oauth.d.ts +11 -0
  327. package/dist/server/workspace-oauth.d.ts.map +1 -0
  328. package/dist/server/workspace-oauth.js +25 -0
  329. package/dist/server/workspace-oauth.js.map +1 -0
  330. package/dist/shared/context-xray.d.ts +45 -1
  331. package/dist/shared/context-xray.d.ts.map +1 -1
  332. package/dist/shared/context-xray.js +12 -0
  333. package/dist/shared/context-xray.js.map +1 -1
  334. package/dist/shared/mcp-connect-content.d.ts +37 -0
  335. package/dist/shared/mcp-connect-content.d.ts.map +1 -0
  336. package/dist/shared/mcp-connect-content.js +92 -0
  337. package/dist/shared/mcp-connect-content.js.map +1 -0
  338. package/dist/templates/default/app/routes/_index.tsx +11 -0
  339. package/dist/templates/default/app/routes/agent.tsx +33 -0
  340. package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  341. package/dist/templates/workspace-core/.agents/skills/agent-page/SKILL.md +59 -0
  342. package/dist/templates/workspace-core/.agents/skills/context-xray/SKILL.md +25 -0
  343. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +7 -0
  344. package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +9 -0
  345. package/dist/triggers/actions/list-automations.d.ts +24 -0
  346. package/dist/triggers/actions/list-automations.d.ts.map +1 -0
  347. package/dist/triggers/actions/list-automations.js +72 -0
  348. package/dist/triggers/actions/list-automations.js.map +1 -0
  349. package/dist/triggers/actions/manage-automation.d.ts +18 -0
  350. package/dist/triggers/actions/manage-automation.d.ts.map +1 -0
  351. package/dist/triggers/actions/manage-automation.js +60 -0
  352. package/dist/triggers/actions/manage-automation.js.map +1 -0
  353. package/docs/content/agent-surfaces.mdx +43 -0
  354. package/docs/content/external-agents.mdx +11 -0
  355. package/docs/content/locales/ar-SA/agent-surfaces.mdx +30 -0
  356. package/docs/content/locales/ar-SA/external-agents.mdx +9 -0
  357. package/docs/content/locales/de-DE/agent-surfaces.mdx +34 -0
  358. package/docs/content/locales/de-DE/external-agents.mdx +10 -0
  359. package/docs/content/locales/es-ES/agent-surfaces.mdx +34 -0
  360. package/docs/content/locales/es-ES/external-agents.mdx +10 -0
  361. package/docs/content/locales/fr-FR/agent-surfaces.mdx +34 -0
  362. package/docs/content/locales/fr-FR/external-agents.mdx +11 -0
  363. package/docs/content/locales/hi-IN/agent-surfaces.mdx +31 -0
  364. package/docs/content/locales/hi-IN/external-agents.mdx +9 -0
  365. package/docs/content/locales/ja-JP/agent-surfaces.mdx +32 -0
  366. package/docs/content/locales/ja-JP/external-agents.mdx +10 -0
  367. package/docs/content/locales/ko-KR/agent-surfaces.mdx +32 -0
  368. package/docs/content/locales/ko-KR/external-agents.mdx +9 -0
  369. package/docs/content/locales/pt-BR/agent-surfaces.mdx +33 -0
  370. package/docs/content/locales/pt-BR/external-agents.mdx +10 -0
  371. package/docs/content/locales/zh-CN/agent-surfaces.mdx +29 -0
  372. package/docs/content/locales/zh-CN/external-agents.mdx +8 -0
  373. package/docs/content/locales/zh-TW/agent-surfaces.mdx +29 -0
  374. package/docs/content/locales/zh-TW/external-agents.mdx +8 -0
  375. package/package.json +1 -1
  376. package/src/templates/default/app/routes/_index.tsx +11 -0
  377. package/src/templates/default/app/routes/agent.tsx +33 -0
  378. package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
  379. package/src/templates/workspace-core/.agents/skills/agent-page/SKILL.md +59 -0
  380. package/src/templates/workspace-core/.agents/skills/context-xray/SKILL.md +25 -0
  381. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +7 -0
  382. package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +9 -0
@@ -6,9 +6,24 @@ import { z } from "zod";
6
6
 
7
7
  import {
8
8
  getClients,
9
+ getConnectedAccounts,
9
10
  fetchGmailLabelMap,
10
11
  isConnected,
11
12
  } from "../server/lib/google-auth.js";
13
+ import {
14
+ buildMailInventoryPage,
15
+ claimInventoryCursor,
16
+ compareInventoryItems,
17
+ createInventoryCursor,
18
+ inventoryQueryFingerprint,
19
+ releaseInventoryCursorClaim,
20
+ settleInventoryCursorClaim,
21
+ type MailInventoryError,
22
+ type MailInventoryFetchResult,
23
+ type MailInventoryItem,
24
+ type MailInventoryCursorState,
25
+ type MailInventoryCursorClaim,
26
+ } from "../server/lib/inventory-cursor.js";
12
27
  import {
13
28
  getSnoozedThreadIds,
14
29
  getSyntheticEmailsForView,
@@ -38,6 +53,55 @@ function toCompact(emails: any[]): any[] {
38
53
  }));
39
54
  }
40
55
 
56
+ function toInventoryItem(
57
+ email: any,
58
+ includeSnippet: boolean,
59
+ ): MailInventoryItem {
60
+ return {
61
+ id: String(email.id ?? "").slice(0, 256),
62
+ threadId: String(email.threadId ?? email.id ?? "").slice(0, 256),
63
+ accountEmail: String(email.accountEmail ?? "").slice(0, 320),
64
+ date: String(email.date ?? "").slice(0, 64),
65
+ from: email.from?.email
66
+ ? {
67
+ ...(email.from.name
68
+ ? { name: String(email.from.name).slice(0, 160) }
69
+ : {}),
70
+ email: String(email.from.email).slice(0, 320),
71
+ }
72
+ : { email: String(email.from ?? "").slice(0, 320) },
73
+ subject: String(email.subject ?? "").slice(0, 500),
74
+ isUnread: email.hasUnread ?? !email.isRead,
75
+ ...(email.isStarred !== undefined ? { isStarred: email.isStarred } : {}),
76
+ messageCount: email.messageCount ?? 1,
77
+ unreadCount: email.unreadCount ?? (email.isRead ? 0 : 1),
78
+ ...(includeSnippet && email.snippet
79
+ ? { snippet: String(email.snippet).slice(0, 320) }
80
+ : {}),
81
+ };
82
+ }
83
+
84
+ function inventoryError(message: unknown): MailInventoryError {
85
+ const bounded = String(message ?? "Provider request failed")
86
+ .replace(/\bBearer\s+\S+/gi, "Bearer [redacted]")
87
+ .replace(
88
+ /\b(access_token|refresh_token|id_token|token)=([^\s&]+)/gi,
89
+ "$1=[redacted]",
90
+ )
91
+ .slice(0, 240);
92
+ const rateLimited = /\b(?:429|quota|rate.?limit)\b/i.test(bounded);
93
+ const auth = /\b(?:401|403|auth|token|credential|permission)\b/i.test(
94
+ bounded,
95
+ );
96
+ return {
97
+ code: rateLimited ? "rate_limited" : auth ? "authentication" : "provider",
98
+ message: bounded,
99
+ retryable:
100
+ rateLimited ||
101
+ /\b(?:timeout|temporar|unavailable|5\d\d)\b/i.test(bounded),
102
+ };
103
+ }
104
+
41
105
  function latestPerThread(emails: any[]): any[] {
42
106
  const byThread = new Map<
43
107
  string,
@@ -85,6 +149,107 @@ function latestPerThread(emails: any[]): any[] {
85
149
  );
86
150
  }
87
151
 
152
+ async function localInventoryEnvelope(
153
+ emails: any[],
154
+ requestedAccounts: string[] | undefined,
155
+ resolvedAccounts: string[],
156
+ query: { view: string; q?: string },
157
+ limit: number,
158
+ ownerEmail: string,
159
+ cursor?: string,
160
+ ) {
161
+ const normalizedRequested = requestedAccounts
162
+ ? [...new Set(requestedAccounts.map((email) => email.toLowerCase()))]
163
+ : null;
164
+ const queryFingerprint = inventoryQueryFingerprint({
165
+ ...query,
166
+ requestedAccounts: normalizedRequested,
167
+ limit,
168
+ source: "local",
169
+ });
170
+ let claim: MailInventoryCursorClaim | null = null;
171
+ let state: MailInventoryCursorState;
172
+ if (cursor) {
173
+ claim = await claimInventoryCursor(ownerEmail, cursor, queryFingerprint);
174
+ if (!claim) {
175
+ throw new Error(
176
+ "Inventory cursor is invalid, expired, or has already been used.",
177
+ );
178
+ }
179
+ state = claim.state;
180
+ } else {
181
+ const inventoryItems = latestPerThread(emails)
182
+ .map((email) =>
183
+ toInventoryItem(
184
+ {
185
+ ...email,
186
+ accountEmail: email.accountEmail ?? resolvedAccounts[0] ?? "local",
187
+ },
188
+ false,
189
+ ),
190
+ )
191
+ .sort(compareInventoryItems);
192
+ state = {
193
+ queryFingerprint,
194
+ requestedAccounts: normalizedRequested,
195
+ firstPage: true,
196
+ accounts: resolvedAccounts.map((accountEmail) => {
197
+ const pending = inventoryItems.filter(
198
+ (item) =>
199
+ item.accountEmail.toLowerCase() === accountEmail.toLowerCase(),
200
+ );
201
+ return {
202
+ accountEmail,
203
+ status: "ok" as const,
204
+ exhausted: true,
205
+ pending,
206
+ emittedCount: 0,
207
+ knownCount: pending.length,
208
+ emittedThreadIds: [],
209
+ };
210
+ }),
211
+ };
212
+ }
213
+
214
+ try {
215
+ const { items, hasMore } = await buildMailInventoryPage(
216
+ state,
217
+ limit,
218
+ async () => ({ items: [], errors: {}, nextPageTokens: {} }),
219
+ );
220
+ const nextCursor = claim
221
+ ? await settleInventoryCursorClaim(claim, state, hasMore)
222
+ : hasMore
223
+ ? await createInventoryCursor(ownerEmail, state)
224
+ : undefined;
225
+ return {
226
+ version: 1,
227
+ query,
228
+ requestedAccounts: state.requestedAccounts,
229
+ resolvedAccounts: state.accounts.map((account) => account.accountEmail),
230
+ queriedAccounts: state.accounts.map((account) => account.accountEmail),
231
+ accounts: state.accounts.map((account) => ({
232
+ accountEmail: account.accountEmail,
233
+ status: account.status,
234
+ count: account.knownCount ?? account.emittedCount,
235
+ emittedCount: account.emittedCount,
236
+ exhausted: account.exhausted && account.pending.length === 0,
237
+ })),
238
+ coverageComplete: true,
239
+ complete: !hasMore,
240
+ items,
241
+ page: {
242
+ returned: items.length,
243
+ hasMore,
244
+ ...(nextCursor ? { nextCursor } : {}),
245
+ },
246
+ };
247
+ } catch (error) {
248
+ if (claim) await releaseInventoryCursorClaim(claim);
249
+ throw error;
250
+ }
251
+ }
252
+
88
253
  async function readLocalEmails(ownerEmail: string): Promise<any[]> {
89
254
  const data = await getUserSetting(ownerEmail, "local-emails");
90
255
  if (data && Array.isArray((data as any).emails)) {
@@ -112,13 +277,27 @@ export default defineAction({
112
277
  ])
113
278
  .optional()
114
279
  .describe("View to list (default: inbox)"),
115
- q: z.string().optional().describe("Full-text search query"),
280
+ q: z.string().max(500).optional().describe("Full-text search query"),
116
281
  account: z
117
282
  .string()
118
283
  .optional()
119
284
  .describe(
120
285
  "Filter to a specific account email address. By default searches all connected accounts.",
121
286
  ),
287
+ accountEmails: z
288
+ .array(z.string().email())
289
+ .min(1)
290
+ .optional()
291
+ .describe(
292
+ "Inventory only: connected account email addresses to include.",
293
+ ),
294
+ format: z
295
+ .enum(["legacy", "inventory"])
296
+ .optional()
297
+ .describe(
298
+ "Use inventory for a coverage-aware compact multi-account read.",
299
+ ),
300
+ cursor: z.string().max(256).optional().describe("Inventory page cursor."),
122
301
  limit: z.coerce
123
302
  .number()
124
303
  .optional()
@@ -146,7 +325,7 @@ export default defineAction({
146
325
  view,
147
326
  };
148
327
  },
149
- run: async (args) => {
328
+ run: async (args, ctx) => {
150
329
  const view = args.view ?? "inbox";
151
330
  const query = args.q;
152
331
  const limit = args.limit ?? 50;
@@ -155,9 +334,47 @@ export default defineAction({
155
334
  const accountFilter = args.account?.toLowerCase();
156
335
  const ownerEmail = getRequestUserEmail();
157
336
  if (!ownerEmail) throw new Error("no authenticated user");
337
+ if (args.account && args.accountEmails) {
338
+ throw new Error("Pass account or accountEmails, not both.");
339
+ }
340
+ const inventory =
341
+ args.format === "inventory" ||
342
+ (ctx?.caller === "mcp" && args.format === undefined);
343
+ if (inventory && (!Number.isInteger(limit) || limit < 1 || limit > 100)) {
344
+ throw new Error("Inventory limit must be an integer from 1 through 100.");
345
+ }
346
+
347
+ // Inventory is deliberately resolved before any refresh/list call. Apart
348
+ // from preventing a cross-account data leak, this keeps a selected read
349
+ // from touching token state for accounts the caller did not choose.
350
+ const requestedAccounts =
351
+ args.accountEmails ?? (args.account ? [args.account] : undefined);
158
352
 
159
353
  if (view === "snoozed" || view === "scheduled") {
160
354
  let emails = await getSyntheticEmailsForView(ownerEmail, view);
355
+ const syntheticAccountsByLower = new Map<string, string>();
356
+ for (const email of emails) {
357
+ const accountEmail = String(email.accountEmail ?? ownerEmail);
358
+ syntheticAccountsByLower.set(accountEmail.toLowerCase(), accountEmail);
359
+ }
360
+ const syntheticSelectedAccounts = inventory
361
+ ? Array.from(
362
+ new Set(
363
+ (
364
+ requestedAccounts ??
365
+ Array.from(syntheticAccountsByLower.values())
366
+ ).map((email) => email.toLowerCase()),
367
+ ),
368
+ ).map((email) => {
369
+ const available = syntheticAccountsByLower.get(email);
370
+ if (!available) {
371
+ throw new Error(
372
+ `Account ${email} is not available in ${view} mail for this user.`,
373
+ );
374
+ }
375
+ return available;
376
+ })
377
+ : undefined;
161
378
  if (query) {
162
379
  emails = emails.filter((e) => emailMessageMatchesSearch(e, query));
163
380
  }
@@ -166,6 +383,35 @@ export default defineAction({
166
383
  (e) => e.accountEmail?.toLowerCase() === accountFilter,
167
384
  );
168
385
  }
386
+ if (inventory) {
387
+ const selected = new Set(
388
+ (syntheticSelectedAccounts ?? []).map((email) => email.toLowerCase()),
389
+ );
390
+ if (selected.size > 0) {
391
+ emails = emails.filter((email) =>
392
+ selected.has(String(email.accountEmail ?? "").toLowerCase()),
393
+ );
394
+ }
395
+ const syntheticResolvedAccounts =
396
+ syntheticSelectedAccounts && syntheticSelectedAccounts.length > 0
397
+ ? syntheticSelectedAccounts
398
+ : Array.from(
399
+ new Set(
400
+ emails.map((email) =>
401
+ String(email.accountEmail ?? ownerEmail).toLowerCase(),
402
+ ),
403
+ ),
404
+ );
405
+ return await localInventoryEnvelope(
406
+ emails,
407
+ requestedAccounts,
408
+ syntheticResolvedAccounts,
409
+ { view, ...(query ? { q: query } : {}) },
410
+ limit,
411
+ ownerEmail,
412
+ args.cursor,
413
+ );
414
+ }
169
415
  return JSON.stringify(
170
416
  compact ? toCompact(emails.slice(0, limit)) : emails.slice(0, limit),
171
417
  null,
@@ -173,8 +419,192 @@ export default defineAction({
173
419
  );
174
420
  }
175
421
 
176
- if (await isConnected(ownerEmail)) {
177
- const clients = await getClients(ownerEmail);
422
+ const connectedAccounts = inventory
423
+ ? await getConnectedAccounts(ownerEmail)
424
+ : [];
425
+ const connectedByLower = new Map(
426
+ connectedAccounts.map((email) => [email.toLowerCase(), email]),
427
+ );
428
+ const selectedAccounts =
429
+ inventory && connectedAccounts.length > 0
430
+ ? Array.from(
431
+ new Set(
432
+ (requestedAccounts ?? connectedAccounts).map((email) =>
433
+ email.toLowerCase(),
434
+ ),
435
+ ),
436
+ ).map((email) => {
437
+ const owned = connectedByLower.get(email);
438
+ if (!owned)
439
+ throw new Error(
440
+ `Account ${email} is not connected for this user.`,
441
+ );
442
+ return owned;
443
+ })
444
+ : undefined;
445
+
446
+ if (
447
+ (inventory && selectedAccounts && selectedAccounts.length > 0) ||
448
+ (!inventory && (await isConnected(ownerEmail)))
449
+ ) {
450
+ const inventoryAccounts = selectedAccounts ?? [];
451
+ const clients = inventory
452
+ ? inventoryAccounts.map((email) => ({
453
+ email,
454
+ accessToken: "",
455
+ refreshToken: "",
456
+ }))
457
+ : await getClients(ownerEmail);
458
+ if (inventory) {
459
+ const normalizedRequested = requestedAccounts
460
+ ? [...new Set(requestedAccounts.map((email) => email.toLowerCase()))]
461
+ : null;
462
+ const queryFingerprint = inventoryQueryFingerprint({
463
+ view,
464
+ q: query ?? null,
465
+ requestedAccounts: normalizedRequested,
466
+ limit,
467
+ });
468
+ let cursorState: MailInventoryCursorState;
469
+ let cursorClaim: MailInventoryCursorClaim | null = null;
470
+ if (args.cursor) {
471
+ const claimed = await claimInventoryCursor(
472
+ ownerEmail,
473
+ args.cursor,
474
+ queryFingerprint,
475
+ );
476
+ if (!claimed) {
477
+ throw new Error(
478
+ "Inventory cursor is invalid, expired, or has already been used.",
479
+ );
480
+ }
481
+ cursorClaim = claimed;
482
+ cursorState = claimed.state;
483
+ } else {
484
+ cursorState = {
485
+ queryFingerprint,
486
+ requestedAccounts: normalizedRequested,
487
+ firstPage: true,
488
+ accounts: inventoryAccounts.map((accountEmail) => ({
489
+ accountEmail,
490
+ status: "ok",
491
+ exhausted: false,
492
+ pending: [],
493
+ emittedCount: 0,
494
+ knownCount: 0,
495
+ emittedThreadIds: [],
496
+ })),
497
+ };
498
+ }
499
+
500
+ const fetchInventory = async (
501
+ requests: Array<{ accountEmail: string; pageToken?: string }>,
502
+ ): Promise<MailInventoryFetchResult> => {
503
+ const accountEmails = requests.map((request) => request.accountEmail);
504
+ const pageTokens = Object.fromEntries(
505
+ requests
506
+ .filter((request) => request.pageToken)
507
+ .map((request) => [request.accountEmail, request.pageToken!]),
508
+ );
509
+ const listResult = await listInboxEmails({
510
+ ownerEmail,
511
+ view,
512
+ q: query,
513
+ limit,
514
+ pageTokens:
515
+ Object.keys(pageTokens).length > 0 ? pageTokens : undefined,
516
+ threadFormat: "metadata",
517
+ includeRecentMessageCandidates: false,
518
+ accountTokens: accountEmails.map((email) => ({
519
+ email,
520
+ accessToken: "",
521
+ })),
522
+ accountEmails,
523
+ labelMap: new Map(),
524
+ });
525
+ if (!listResult.ok) {
526
+ return {
527
+ items: [],
528
+ errors: Object.fromEntries(
529
+ accountEmails.map((email) => [
530
+ email.toLowerCase(),
531
+ inventoryError(listResult.message),
532
+ ]),
533
+ ),
534
+ nextPageTokens: {},
535
+ };
536
+ }
537
+ return {
538
+ items: latestPerThread(listResult.emails).map((email) =>
539
+ toInventoryItem(email, false),
540
+ ),
541
+ errors: Object.fromEntries(
542
+ listResult.errors.map((error) => [
543
+ error.email.toLowerCase(),
544
+ inventoryError(error.error),
545
+ ]),
546
+ ),
547
+ nextPageTokens: Object.fromEntries(
548
+ Object.entries(listResult.nextPageTokens ?? {}).map(
549
+ ([email, token]) => [email.toLowerCase(), token],
550
+ ),
551
+ ),
552
+ };
553
+ };
554
+
555
+ try {
556
+ const { items, hasMore } = await buildMailInventoryPage(
557
+ cursorState,
558
+ limit,
559
+ fetchInventory,
560
+ );
561
+ const nextCursor = cursorClaim
562
+ ? await settleInventoryCursorClaim(
563
+ cursorClaim,
564
+ cursorState,
565
+ hasMore,
566
+ )
567
+ : hasMore
568
+ ? await createInventoryCursor(ownerEmail, cursorState)
569
+ : undefined;
570
+ const coverageComplete = cursorState.accounts.every(
571
+ (account) => account.status === "ok",
572
+ );
573
+ return {
574
+ version: 1,
575
+ query: { view, ...(query ? { q: query } : {}) },
576
+ requestedAccounts: cursorState.requestedAccounts,
577
+ resolvedAccounts: cursorState.accounts.map(
578
+ (account) => account.accountEmail,
579
+ ),
580
+ queriedAccounts: cursorState.accounts.map(
581
+ (account) => account.accountEmail,
582
+ ),
583
+ accounts: cursorState.accounts.map((account) => ({
584
+ accountEmail: account.accountEmail,
585
+ status: account.status,
586
+ count: account.knownCount ?? account.emittedCount,
587
+ emittedCount: account.emittedCount,
588
+ exhausted:
589
+ account.status === "ok" &&
590
+ account.exhausted &&
591
+ account.pending.length === 0,
592
+ ...(account.error ? { error: account.error } : {}),
593
+ })),
594
+ coverageComplete,
595
+ complete: coverageComplete && !hasMore,
596
+ items,
597
+ page: {
598
+ returned: items.length,
599
+ hasMore,
600
+ ...(nextCursor ? { nextCursor } : {}),
601
+ },
602
+ };
603
+ } catch (error) {
604
+ if (cursorClaim) await releaseInventoryCursorClaim(cursorClaim);
605
+ throw error;
606
+ }
607
+ }
178
608
  const labelMap = new Map<string, string>();
179
609
  await Promise.all(
180
610
  clients.map(async ({ accessToken }) => {
@@ -239,6 +669,37 @@ export default defineAction({
239
669
 
240
670
  // Fallback: local store
241
671
  let emails = await readLocalEmails(ownerEmail);
672
+ const localAccountsByLower = new Map<string, string>();
673
+ for (const email of emails) {
674
+ const accountEmail = String(email.accountEmail ?? "local");
675
+ localAccountsByLower.set(accountEmail.toLowerCase(), accountEmail);
676
+ }
677
+ const localSelectedAccounts = inventory
678
+ ? Array.from(
679
+ new Set(
680
+ (
681
+ requestedAccounts ?? Array.from(localAccountsByLower.values())
682
+ ).map((email) => email.toLowerCase()),
683
+ ),
684
+ ).map((email) => {
685
+ const available = localAccountsByLower.get(email);
686
+ if (!available) {
687
+ throw new Error(
688
+ `Account ${email} is not available in local mail for this user.`,
689
+ );
690
+ }
691
+ return available;
692
+ })
693
+ : undefined;
694
+
695
+ if (localSelectedAccounts && requestedAccounts) {
696
+ const selected = new Set(
697
+ localSelectedAccounts.map((email) => email.toLowerCase()),
698
+ );
699
+ emails = emails.filter((email) =>
700
+ selected.has(String(email.accountEmail ?? "local").toLowerCase()),
701
+ );
702
+ }
242
703
 
243
704
  switch (view) {
244
705
  case "inbox":
@@ -288,6 +749,27 @@ export default defineAction({
288
749
  }
289
750
  }
290
751
 
752
+ if (inventory) {
753
+ const localResolvedAccounts =
754
+ localSelectedAccounts && localSelectedAccounts.length > 0
755
+ ? localSelectedAccounts
756
+ : Array.from(
757
+ new Set(
758
+ emails.map((email) =>
759
+ String(email.accountEmail ?? "local").toLowerCase(),
760
+ ),
761
+ ),
762
+ );
763
+ return await localInventoryEnvelope(
764
+ emails,
765
+ requestedAccounts,
766
+ localResolvedAccounts,
767
+ { view, ...(query ? { q: query } : {}) },
768
+ limit,
769
+ ownerEmail,
770
+ args.cursor,
771
+ );
772
+ }
291
773
  emails = latestPerThread(emails).slice(0, limit);
292
774
  const payload = compact ? toCompact(emails) : emails;
293
775
  if (includeCounts) {
@@ -13,6 +13,7 @@ import { normalizeMailLabel } from "@shared/gmail-labels";
13
13
  import type { Label } from "@shared/types";
14
14
  import {
15
15
  IconMenu2,
16
+ IconBrain,
16
17
  IconSettings,
17
18
  IconSearch,
18
19
  IconCheck,
@@ -144,6 +145,7 @@ function AccountAvatar({
144
145
  function isStandardLayoutPath(pathname: string): boolean {
145
146
  return (
146
147
  pathname === "/settings" ||
148
+ pathname === "/agent" ||
147
149
  pathname === "/team" ||
148
150
  pathname === "/draft-queue" ||
149
151
  pathname.startsWith("/draft-queue/") ||
@@ -195,6 +197,7 @@ export function AppLayout({ children }: AppLayoutProps) {
195
197
  <AgentSidebar
196
198
  position="right"
197
199
  defaultOpen={!isMobile}
200
+ agentPageHref="/agent"
198
201
  emptyStateText={t("agent.emptyState")}
199
202
  suggestions={[
200
203
  t("agent.suggestionSummarize"),
@@ -1748,6 +1751,25 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1748
1751
  <div className="flex items-center gap-1 px-2 py-2">
1749
1752
  <DevDatabaseLink />
1750
1753
  <FeedbackButton className="min-w-0 flex-1" />
1754
+ <Tooltip>
1755
+ <TooltipTrigger asChild>
1756
+ <Link
1757
+ to="/agent"
1758
+ onClick={closeSidebar}
1759
+ aria-label={t("settings.openAgentSettings")}
1760
+ className={cn(
1761
+ "flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",
1762
+ location.pathname === "/agent" &&
1763
+ "bg-accent/60 text-foreground",
1764
+ )}
1765
+ >
1766
+ <IconBrain className="h-4 w-4" />
1767
+ </Link>
1768
+ </TooltipTrigger>
1769
+ <TooltipContent>
1770
+ {t("settings.openAgentSettings")}
1771
+ </TooltipContent>
1772
+ </Tooltip>
1751
1773
  <Tooltip>
1752
1774
  <TooltipTrigger asChild>
1753
1775
  <Link
@@ -1967,6 +1989,7 @@ function StandardLayout({ children }: AppLayoutProps) {
1967
1989
 
1968
1990
  const fallbackTitle = (() => {
1969
1991
  if (location.pathname === "/settings") return t("settings.title");
1992
+ if (location.pathname === "/agent") return t("settings.agentTitle");
1970
1993
  if (location.pathname === "/team") return t("mail.pages.team");
1971
1994
  if (location.pathname.startsWith("/draft-queue"))
1972
1995
  return t("mail.views.draftQueue");
@@ -2101,6 +2124,25 @@ function StandardLayout({ children }: AppLayoutProps) {
2101
2124
  <DevDatabaseLink />
2102
2125
  <FeedbackButton className="min-w-0 flex-1" />
2103
2126
  <div className="flex shrink-0 items-center gap-0.5">
2127
+ <Tooltip>
2128
+ <TooltipTrigger asChild>
2129
+ <Link
2130
+ to="/agent"
2131
+ onClick={() => setSidebarOpen(false)}
2132
+ aria-label={t("settings.openAgentSettings")}
2133
+ className={cn(
2134
+ "flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground",
2135
+ location.pathname === "/agent" &&
2136
+ "bg-accent/60 text-foreground",
2137
+ )}
2138
+ >
2139
+ <IconBrain className="h-4 w-4" />
2140
+ </Link>
2141
+ </TooltipTrigger>
2142
+ <TooltipContent>
2143
+ {t("settings.openAgentSettings")}
2144
+ </TooltipContent>
2145
+ </Tooltip>
2104
2146
  <Tooltip>
2105
2147
  <TooltipTrigger asChild>
2106
2148
  <Link
@@ -1,5 +1,6 @@
1
1
  import { CommandMenu, useT } from "@agent-native/core/client";
2
2
  import {
3
+ IconBrain,
3
4
  IconInbox,
4
5
  IconStar,
5
6
  IconSend,
@@ -74,6 +75,11 @@ const navCommands = [
74
75
  shortcut: "G A",
75
76
  },
76
77
  { labelKey: "commandPalette.goToTrash", icon: IconTrash, route: "/trash" },
78
+ {
79
+ labelKey: "settings.openAgentSettings",
80
+ icon: IconBrain,
81
+ route: "/agent",
82
+ },
77
83
  ];
78
84
 
79
85
  export function CommandPalette({
@@ -0,0 +1,15 @@
1
+ import { AgentTabsPage, useT } from "@agent-native/core/client";
2
+ import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
3
+
4
+ import messages from "@/i18n/en-US";
5
+
6
+ export function meta() {
7
+ return [{ title: messages.settings.agentTitle }];
8
+ }
9
+
10
+ export default function AgentRoute() {
11
+ const t = useT();
12
+ useSetPageTitle(t("settings.agentTitle"));
13
+
14
+ return <AgentTabsPage appName="Mail" />;
15
+ }
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ Mail can now return a compact coverage-aware direct inventory across selected connected inboxes.
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: added
3
+ date: 2026-07-13
4
+ ---
5
+
6
+ New Agent page: see and manage your agent's context, files, connections, jobs, and external access in one place