@agent-native/core 0.101.6 → 0.101.10

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 (237) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +28 -0
  3. package/corpus/core/docs/content/deployment.mdx +9 -7
  4. package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +9 -7
  5. package/corpus/core/docs/content/locales/de-DE/deployment.mdx +9 -7
  6. package/corpus/core/docs/content/locales/es-ES/deployment.mdx +9 -7
  7. package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +9 -7
  8. package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +9 -7
  9. package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +9 -7
  10. package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +9 -7
  11. package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +9 -7
  12. package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +9 -7
  13. package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +9 -7
  14. package/corpus/core/package.json +1 -1
  15. package/corpus/core/src/a2a/artifact-response.ts +255 -12
  16. package/corpus/core/src/agent/thread-data-builder.ts +84 -11
  17. package/corpus/core/src/client/review/ReviewCommentComposer.tsx +9 -1
  18. package/corpus/core/src/client/review/ReviewThreadPanel.tsx +17 -2
  19. package/corpus/core/src/client/settings/SettingsPanel.tsx +41 -21
  20. package/corpus/core/src/client/settings/useBuilderStatus.ts +28 -9
  21. package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +2 -7
  22. package/corpus/core/src/integrations/a2a-continuation-processor.ts +99 -7
  23. package/corpus/core/src/integrations/adapters/discord.ts +3 -1
  24. package/corpus/core/src/integrations/adapters/email.ts +4 -1
  25. package/corpus/core/src/integrations/adapters/google-docs.ts +4 -1
  26. package/corpus/core/src/integrations/adapters/microsoft-teams.ts +3 -1
  27. package/corpus/core/src/integrations/adapters/slack.ts +38 -9
  28. package/corpus/core/src/integrations/adapters/telegram.ts +32 -10
  29. package/corpus/core/src/integrations/adapters/whatsapp.ts +5 -1
  30. package/corpus/core/src/integrations/index.ts +1 -0
  31. package/corpus/core/src/integrations/types.ts +9 -2
  32. package/corpus/core/src/integrations/webhook-handler.ts +69 -45
  33. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +1 -0
  34. package/corpus/core/src/server/auth.ts +25 -1
  35. package/corpus/core/src/server/builder-browser.ts +353 -1
  36. package/corpus/core/src/server/core-routes-plugin.ts +601 -223
  37. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +80 -1
  38. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +28 -3
  39. package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +5 -1
  40. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +30 -3
  41. package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +196 -0
  42. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +115 -1
  43. package/corpus/templates/calendar/app/lib/out-of-office.ts +45 -0
  44. package/corpus/templates/calendar/changelog/2026-07-14-out-of-office-blocks-now-sit-behind-meetings-and-event-stack.md +6 -0
  45. package/corpus/templates/content/.agents/skills/content/SKILL.md +31 -0
  46. package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +35 -21
  47. package/corpus/templates/content/AGENTS.md +32 -9
  48. package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +87 -0
  49. package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -25
  50. package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +1 -0
  51. package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +427 -18
  52. package/corpus/templates/content/actions/_builder-cms-write-client.ts +17 -73
  53. package/corpus/templates/content/actions/_builder-cms-write-settings.ts +27 -7
  54. package/corpus/templates/content/actions/_builder-source-execution-claim.ts +124 -0
  55. package/corpus/templates/content/actions/_builder-source-execution-preservation.ts +21 -0
  56. package/corpus/templates/content/actions/_builder-source-timings.ts +57 -0
  57. package/corpus/templates/content/actions/_database-source-utils.ts +1071 -170
  58. package/corpus/templates/content/actions/_database-utils.ts +104 -13
  59. package/corpus/templates/content/actions/_local-file-documents.ts +53 -1
  60. package/corpus/templates/content/actions/_preview-document-draft.ts +31 -0
  61. package/corpus/templates/content/actions/_property-utils.ts +7 -1
  62. package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +309 -0
  63. package/corpus/templates/content/actions/configure-document-property.ts +11 -0
  64. package/corpus/templates/content/actions/create-content-database.ts +11 -0
  65. package/corpus/templates/content/actions/create-document.ts +9 -0
  66. package/corpus/templates/content/actions/create-inline-content-database.ts +3 -0
  67. package/corpus/templates/content/actions/execute-builder-source-batch.ts +120 -49
  68. package/corpus/templates/content/actions/execute-builder-source-execution.ts +608 -264
  69. package/corpus/templates/content/actions/export-content-source.ts +1 -0
  70. package/corpus/templates/content/actions/get-content-database.ts +13 -1
  71. package/corpus/templates/content/actions/get-document.ts +12 -2
  72. package/corpus/templates/content/actions/get-preview-document-draft.ts +26 -0
  73. package/corpus/templates/content/actions/import-content-source.ts +6 -0
  74. package/corpus/templates/content/actions/list-documents.ts +3 -0
  75. package/corpus/templates/content/actions/materialize-builder-required-fields.ts +550 -0
  76. package/corpus/templates/content/actions/prepare-builder-source-execution.ts +112 -65
  77. package/corpus/templates/content/actions/prepare-builder-source-review.ts +463 -170
  78. package/corpus/templates/content/actions/preview-builder-source-review.ts +99 -0
  79. package/corpus/templates/content/actions/pull-document.ts +2 -0
  80. package/corpus/templates/content/actions/search-documents.ts +5 -1
  81. package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +2 -2
  82. package/corpus/templates/content/actions/update-document.ts +16 -1
  83. package/corpus/templates/content/actions/update-preview-document-draft.ts +153 -0
  84. package/corpus/templates/content/actions/view-screen.ts +15 -2
  85. package/corpus/templates/content/app/components/editor/DescriptionField.tsx +121 -0
  86. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +14 -0
  87. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +250 -49
  88. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +57 -5
  89. package/corpus/templates/content/app/components/editor/body-hydration.ts +27 -0
  90. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2414 -589
  91. package/corpus/templates/content/app/components/editor/database/settings.tsx +13 -10
  92. package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +358 -75
  93. package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +124 -29
  94. package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +2 -0
  95. package/corpus/templates/content/app/global.css +18 -1
  96. package/corpus/templates/content/app/hooks/use-content-database.ts +68 -0
  97. package/corpus/templates/content/app/hooks/use-documents.ts +53 -4
  98. package/corpus/templates/content/app/i18n/zh-TW.ts +30 -0
  99. package/corpus/templates/content/app/i18n-data.ts +339 -0
  100. package/corpus/templates/content/changelog/2026-07-10-builder-backed-preview-edits-are-preserved-when-article-bodi.md +6 -0
  101. package/corpus/templates/content/changelog/2026-07-10-builder-cms-sources-can-now-be-enabled-for-guarded-staged-or.md +6 -0
  102. package/corpus/templates/content/changelog/2026-07-13-builder-connection-setup-is-now-available-directly-from-conn.md +6 -0
  103. package/corpus/templates/content/changelog/2026-07-13-builder-reviews-now-hide-already-applied-writes-detect-nativ.md +6 -0
  104. package/corpus/templates/content/changelog/2026-07-13-required-builder-publishing-fields-can-now-be-added-directly.md +6 -0
  105. package/corpus/templates/content/changelog/2026-07-13-you-can-now-cancel-a-prepared-builder-update-safely-before-i.md +6 -0
  106. package/corpus/templates/content/changelog/2026-07-14-builder-account-connection-now-remains-available-when-branch.md +6 -0
  107. package/corpus/templates/content/changelog/2026-07-14-builder-backed-articles-now-preserve-fifth-and-sixth-level-h.md +6 -0
  108. package/corpus/templates/content/changelog/2026-07-14-builder-sources-now-review-and-publish-rich-article-updates-.md +6 -0
  109. package/corpus/templates/content/changelog/2026-07-14-builder-writes-now-stop-retries-when-reconciliation-is-needed.md +6 -0
  110. package/corpus/templates/content/changelog/2026-07-14-file-and-media-links-now-validate-before-saving.md +6 -0
  111. package/corpus/templates/content/changelog/2026-07-14-pages-and-databases-can-describe-themselves-with-guidance-fo.md +6 -0
  112. package/corpus/templates/content/changelog/2026-07-14-slack-follow-ups-now-retain-created-content-identity-and-per.md +6 -0
  113. package/corpus/templates/content/parity/matrix.md +27 -25
  114. package/corpus/templates/content/parity/matrix.ts +50 -2
  115. package/corpus/templates/content/server/db/schema.ts +51 -0
  116. package/corpus/templates/content/server/lib/document-context.ts +76 -0
  117. package/corpus/templates/content/server/lib/public-documents.ts +3 -0
  118. package/corpus/templates/content/server/plugins/auth.ts +1 -0
  119. package/corpus/templates/content/server/plugins/db.ts +59 -0
  120. package/corpus/templates/content/server/routes/api/document-agent-context.json.get.ts +5 -0
  121. package/corpus/templates/content/shared/api.ts +87 -1
  122. package/corpus/templates/content/shared/builder-mdx.ts +705 -15
  123. package/corpus/templates/content/shared/content-source.ts +7 -0
  124. package/corpus/templates/content/shared/nfm.ts +3 -3
  125. package/corpus/templates/content/shared/properties.ts +2 -0
  126. package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +52 -7
  127. package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +36 -4
  128. package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
  129. package/corpus/templates/design/app/i18n/ar-SA.ts +1 -0
  130. package/corpus/templates/design/app/i18n/de-DE.ts +1 -0
  131. package/corpus/templates/design/app/i18n/en-US.ts +1 -0
  132. package/corpus/templates/design/app/i18n/es-ES.ts +1 -0
  133. package/corpus/templates/design/app/i18n/fr-FR.ts +1 -0
  134. package/corpus/templates/design/app/i18n/hi-IN.ts +1 -0
  135. package/corpus/templates/design/app/i18n/ja-JP.ts +1 -0
  136. package/corpus/templates/design/app/i18n/ko-KR.ts +1 -0
  137. package/corpus/templates/design/app/i18n/pt-BR.ts +1 -0
  138. package/corpus/templates/design/app/i18n/zh-CN.ts +1 -0
  139. package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
  140. package/corpus/templates/design/app/pages/design-editor/selection-state.ts +8 -0
  141. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +11 -0
  142. package/corpus/templates/design/changelog/2026-07-14-reviewers-can-now-pin-comments-from-the-canvas-toolbar-targe.md +6 -0
  143. package/corpus/templates/design/changelog/2026-07-15-viewer-comment-controls-now-sit-inside-the-read-only-notice-.md +6 -0
  144. package/corpus/templates/design/shared/review-anchor.ts +48 -0
  145. package/corpus/templates/plan/server/plan-mdx.ts +53 -7
  146. package/dist/a2a/artifact-response.d.ts +15 -0
  147. package/dist/a2a/artifact-response.d.ts.map +1 -1
  148. package/dist/a2a/artifact-response.js +204 -5
  149. package/dist/a2a/artifact-response.js.map +1 -1
  150. package/dist/agent/thread-data-builder.d.ts +6 -0
  151. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  152. package/dist/agent/thread-data-builder.js +71 -8
  153. package/dist/agent/thread-data-builder.js.map +1 -1
  154. package/dist/client/review/ReviewCommentComposer.d.ts +2 -1
  155. package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
  156. package/dist/client/review/ReviewCommentComposer.js +3 -3
  157. package/dist/client/review/ReviewCommentComposer.js.map +1 -1
  158. package/dist/client/review/ReviewThreadPanel.d.ts +9 -1
  159. package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
  160. package/dist/client/review/ReviewThreadPanel.js +6 -4
  161. package/dist/client/review/ReviewThreadPanel.js.map +1 -1
  162. package/dist/client/settings/SettingsPanel.d.ts +3 -0
  163. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  164. package/dist/client/settings/SettingsPanel.js +11 -4
  165. package/dist/client/settings/SettingsPanel.js.map +1 -1
  166. package/dist/client/settings/useBuilderStatus.d.ts +8 -4
  167. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  168. package/dist/client/settings/useBuilderStatus.js +19 -6
  169. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  170. package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
  171. package/dist/client/setup-connections/BuilderConnectCard.js +2 -5
  172. package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
  173. package/dist/collab/awareness.d.ts +2 -2
  174. package/dist/collab/awareness.d.ts.map +1 -1
  175. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  176. package/dist/integrations/a2a-continuation-processor.js +72 -6
  177. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  178. package/dist/integrations/adapters/discord.d.ts.map +1 -1
  179. package/dist/integrations/adapters/discord.js +1 -0
  180. package/dist/integrations/adapters/discord.js.map +1 -1
  181. package/dist/integrations/adapters/email.d.ts.map +1 -1
  182. package/dist/integrations/adapters/email.js +2 -0
  183. package/dist/integrations/adapters/email.js.map +1 -1
  184. package/dist/integrations/adapters/google-docs.d.ts.map +1 -1
  185. package/dist/integrations/adapters/google-docs.js +2 -0
  186. package/dist/integrations/adapters/google-docs.js.map +1 -1
  187. package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -1
  188. package/dist/integrations/adapters/microsoft-teams.js +1 -0
  189. package/dist/integrations/adapters/microsoft-teams.js.map +1 -1
  190. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  191. package/dist/integrations/adapters/slack.js +21 -6
  192. package/dist/integrations/adapters/slack.js.map +1 -1
  193. package/dist/integrations/adapters/telegram.d.ts.map +1 -1
  194. package/dist/integrations/adapters/telegram.js +11 -2
  195. package/dist/integrations/adapters/telegram.js.map +1 -1
  196. package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
  197. package/dist/integrations/adapters/whatsapp.js +3 -0
  198. package/dist/integrations/adapters/whatsapp.js.map +1 -1
  199. package/dist/integrations/index.d.ts +1 -1
  200. package/dist/integrations/index.d.ts.map +1 -1
  201. package/dist/integrations/index.js.map +1 -1
  202. package/dist/integrations/types.d.ts +8 -2
  203. package/dist/integrations/types.d.ts.map +1 -1
  204. package/dist/integrations/types.js.map +1 -1
  205. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  206. package/dist/integrations/webhook-handler.js +40 -43
  207. package/dist/integrations/webhook-handler.js.map +1 -1
  208. package/dist/observability/routes.d.ts +5 -5
  209. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  210. package/dist/secrets/routes.d.ts +9 -9
  211. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
  212. package/dist/server/agent-chat/action-filters-a2a.js +1 -0
  213. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
  214. package/dist/server/auth.d.ts +1 -0
  215. package/dist/server/auth.d.ts.map +1 -1
  216. package/dist/server/auth.js +19 -2
  217. package/dist/server/auth.js.map +1 -1
  218. package/dist/server/builder-browser.d.ts +78 -0
  219. package/dist/server/builder-browser.d.ts.map +1 -1
  220. package/dist/server/builder-browser.js +246 -1
  221. package/dist/server/builder-browser.js.map +1 -1
  222. package/dist/server/core-routes-plugin.d.ts +41 -0
  223. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  224. package/dist/server/core-routes-plugin.js +260 -14
  225. package/dist/server/core-routes-plugin.js.map +1 -1
  226. package/docs/content/deployment.mdx +9 -7
  227. package/docs/content/locales/ar-SA/deployment.mdx +9 -7
  228. package/docs/content/locales/de-DE/deployment.mdx +9 -7
  229. package/docs/content/locales/es-ES/deployment.mdx +9 -7
  230. package/docs/content/locales/fr-FR/deployment.mdx +9 -7
  231. package/docs/content/locales/hi-IN/deployment.mdx +9 -7
  232. package/docs/content/locales/ja-JP/deployment.mdx +9 -7
  233. package/docs/content/locales/ko-KR/deployment.mdx +9 -7
  234. package/docs/content/locales/pt-BR/deployment.mdx +9 -7
  235. package/docs/content/locales/zh-CN/deployment.mdx +9 -7
  236. package/docs/content/locales/zh-TW/deployment.mdx +9 -7
  237. package/package.json +2 -2
@@ -53,10 +53,14 @@ export interface BuilderStatus {
53
53
  }
54
54
 
55
55
  /**
56
- * Fetches Builder connection status from /_agent-native/builder/status.
56
+ * Fetches Builder connection status from the neutral connection-status route.
57
+ * The legacy /_agent-native/builder/status route remains available for older
58
+ * clients.
57
59
  * Re-fetches on window focus to detect post-redirect state changes.
58
60
  */
59
- export function useBuilderStatus() {
61
+ export function useBuilderStatus({
62
+ enabled = true,
63
+ }: { enabled?: boolean } = {}) {
60
64
  const [status, setStatus] = useState<BuilderStatus | null>(null);
61
65
  const [loading, setLoading] = useState(true);
62
66
  const [error, setError] = useState<string | null>(null);
@@ -64,6 +68,7 @@ export function useBuilderStatus() {
64
68
  const lastGoodStatusRef = useRef<BuilderStatus | null>(null);
65
69
 
66
70
  const fetchStatus = useCallback(async () => {
71
+ if (!enabled) return;
67
72
  const keepLastGoodStatus = (message: string) => {
68
73
  const lastGoodStatus = lastGoodStatusRef.current;
69
74
  setStatus(lastGoodStatus);
@@ -72,7 +77,9 @@ export function useBuilderStatus() {
72
77
  };
73
78
 
74
79
  try {
75
- const res = await fetch(agentNativePath("/_agent-native/builder/status"));
80
+ const res = await fetch(
81
+ agentNativePath("/_agent-native/connection-status/builder"),
82
+ );
76
83
  if (!res.ok) {
77
84
  keepLastGoodStatus(`Builder status unavailable (${res.status})`);
78
85
  return;
@@ -91,9 +98,18 @@ export function useBuilderStatus() {
91
98
  } finally {
92
99
  setLoading(false);
93
100
  }
94
- }, []);
101
+ }, [enabled]);
95
102
 
96
103
  useEffect(() => {
104
+ if (!enabled) {
105
+ setStatus(null);
106
+ setLoading(false);
107
+ setError(null);
108
+ setStale(false);
109
+ lastGoodStatusRef.current = null;
110
+ return;
111
+ }
112
+ setLoading(true);
97
113
  fetchStatus();
98
114
 
99
115
  function onFocus() {
@@ -115,7 +131,7 @@ export function useBuilderStatus() {
115
131
  fetchStatus,
116
132
  );
117
133
  };
118
- }, [fetchStatus]);
134
+ }, [enabled, fetchStatus]);
119
135
 
120
136
  return { status, loading, error, stale, refetch: fetchStatus };
121
137
  }
@@ -123,7 +139,7 @@ export function useBuilderStatus() {
123
139
  // ─── useBuilderConnectFlow ──────────────────────────────────────────────────
124
140
  //
125
141
  // Shared state machine for the "open Builder CLI-auth popup + poll
126
- // /builder/status until credentials land" interaction. Replaces three
142
+ // /connection-status/builder until credentials land" interaction. Replaces three
127
143
  // near-duplicate inline implementations: `BuilderCliAuthMethod` in
128
144
  // OnboardingPanel, `ConnectBuilderCard`, and `BuilderConnectCta` in
129
145
  // AssistantChat. Each consumer supplies its own popup URL / completion
@@ -158,7 +174,7 @@ export interface BuilderConnectStartOptions {
158
174
 
159
175
  export interface BuilderConnectFlow {
160
176
  configured: boolean;
161
- /** True after at least one successful `/builder/status` response. */
177
+ /** True after at least one successful Builder connection-status response. */
162
178
  statusResolved: boolean;
163
179
  /**
164
180
  * True when the deploy has BUILDER_PRIVATE_KEY set as a fallback. Connect
@@ -176,7 +192,7 @@ export interface BuilderConnectFlow {
176
192
  connecting: boolean;
177
193
  error: string | null;
178
194
  /**
179
- * True once the first `/builder/status` fetch has completed (successfully
195
+ * True once the first Builder connection-status fetch has completed (successfully
180
196
  * or not). Consumers that accept an `initialConfigured` prop (e.g. agent
181
197
  * tool-call results rendered with server-side state) should treat
182
198
  * `configured`/`orgName` as authoritative only once this flips true —
@@ -579,7 +595,10 @@ export function useBuilderConnectFlow(
579
595
  const origin = getCallbackOrigin() || window.location.origin;
580
596
  try {
581
597
  const r = await fetch(
582
- new URL(agentNativePath("/_agent-native/builder/status"), origin).href,
598
+ new URL(
599
+ agentNativePath("/_agent-native/connection-status/builder"),
600
+ origin,
601
+ ).href,
583
602
  );
584
603
  if (!r.ok) return null;
585
604
  return (await r.json()) as {
@@ -30,9 +30,7 @@ export function BuilderConnectCard({
30
30
  ? "Checking"
31
31
  : flow.configured
32
32
  ? connectedLabel
33
- : flow.builderEnabled
34
- ? "Ready to connect"
35
- : "Project not configured";
33
+ : "Ready to connect";
36
34
 
37
35
  return (
38
36
  <section
@@ -73,10 +71,7 @@ export function BuilderConnectCard({
73
71
  <button
74
72
  type="button"
75
73
  onClick={() => flow.start()}
76
- disabled={
77
- flow.connecting ||
78
- (!flow.builderEnabled && flow.hasFetchedStatus)
79
- }
74
+ disabled={flow.connecting}
80
75
  className="mt-3 inline-flex h-8 items-center gap-2 rounded-md border border-border bg-foreground px-3 text-xs font-medium text-background transition-colors hover:bg-foreground/90 disabled:cursor-not-allowed disabled:opacity-60"
81
76
  >
82
77
  {flow.connecting ? (
@@ -1,4 +1,8 @@
1
- import { appendA2AArtifactLinks } from "../a2a/artifact-response.js";
1
+ import {
2
+ appendA2AArtifactLinks,
3
+ extractA2AArtifactIdentities,
4
+ stripA2APersistedArtifactMarkers,
5
+ } from "../a2a/artifact-response.js";
2
6
  import { A2AClient, signA2AToken } from "../a2a/client.js";
3
7
  import type { Task } from "../a2a/types.js";
4
8
  import {
@@ -6,6 +10,8 @@ import {
6
10
  isLlmCredentialError,
7
11
  LLM_MISSING_CREDENTIALS_ERROR_CODE,
8
12
  } from "../agent/engine/credential-errors.js";
13
+ import { extractThreadMeta } from "../agent/thread-data-builder.js";
14
+ import { getThread, updateThreadData } from "../chat-threads/store.js";
9
15
  import { withConfiguredAppBasePath } from "../server/app-base-path.js";
10
16
  import { FRAMEWORK_ROUTE_PREFIX } from "../server/core-routes-plugin.js";
11
17
  import {
@@ -19,9 +25,11 @@ import {
19
25
  type A2AContinuation,
20
26
  } from "./a2a-continuations-store.js";
21
27
  import { signInternalToken } from "./internal-token.js";
28
+ import { getThreadMapping } from "./thread-mapping-store.js";
22
29
  import type {
23
30
  OutgoingMessage,
24
31
  PlatformAdapter,
32
+ PlatformDeliveryReceipt,
25
33
  PlatformRunProgress,
26
34
  } from "./types.js";
27
35
 
@@ -359,8 +367,10 @@ async function deliverAndCompleteA2AContinuation(
359
367
  if (!deliveryContinuation) return;
360
368
 
361
369
  try {
362
- const outgoing = adapter.formatAgentResponse(text);
363
- await withTimeout(
370
+ const outgoing = adapter.formatAgentResponse(
371
+ stripA2APersistedArtifactMarkers(text),
372
+ );
373
+ const deliveryReceipt = await withTimeout(
364
374
  deliverA2AContinuationResponse(
365
375
  adapter,
366
376
  deliveryContinuation,
@@ -371,6 +381,27 @@ async function deliverAndCompleteA2AContinuation(
371
381
  PLATFORM_SEND_TIMEOUT_MS,
372
382
  `${deliveryContinuation.platform} response delivery timed out`,
373
383
  );
384
+ let persistenceError: unknown;
385
+ for (let attempt = 0; attempt < 3; attempt += 1) {
386
+ try {
387
+ await persistA2AContinuationDelivery(
388
+ deliveryContinuation,
389
+ outgoing,
390
+ deliveryReceipt,
391
+ text,
392
+ );
393
+ persistenceError = undefined;
394
+ break;
395
+ } catch (err) {
396
+ persistenceError = err;
397
+ }
398
+ }
399
+ if (persistenceError) {
400
+ console.error(
401
+ `[integrations] Delivered A2A continuation ${deliveryContinuation.id} but could not persist its thread history:`,
402
+ persistenceError,
403
+ );
404
+ }
374
405
  } catch (err) {
375
406
  if (deliveryContinuation.attempts >= MAX_ATTEMPTS) {
376
407
  await failA2AContinuation(
@@ -392,7 +423,7 @@ async function deliverA2AContinuationResponse(
392
423
  message: OutgoingMessage,
393
424
  progress: PlatformRunProgress | null,
394
425
  status: "done" | "error",
395
- ): Promise<void> {
426
+ ): Promise<PlatformDeliveryReceipt> {
396
427
  if (progress) {
397
428
  try {
398
429
  await progress.onEvent({
@@ -400,8 +431,9 @@ async function deliverA2AContinuationResponse(
400
431
  agent: continuation.agentName,
401
432
  status,
402
433
  });
403
- await progress.complete(message);
404
- return;
434
+ const receipt = await progress.complete(message);
435
+ if (receipt?.status === "delivered") return receipt;
436
+ throw new Error("Continuation progress completed without delivery proof");
405
437
  } catch {
406
438
  // A resumed Slack stream can no longer be finalized (for example when
407
439
  // chat.stopStream rejects). Preserve the final answer with the same
@@ -417,9 +449,69 @@ async function deliverA2AContinuationResponse(
417
449
  }
418
450
  }
419
451
  }
420
- await adapter.sendResponse(message, continuation.incoming, {
452
+ const receipt = await adapter.sendResponse(message, continuation.incoming, {
421
453
  placeholderRef: continuation.placeholderRef ?? undefined,
422
454
  });
455
+ if (receipt?.status !== "delivered") {
456
+ throw new Error("Continuation response completed without delivery proof");
457
+ }
458
+ return receipt;
459
+ }
460
+
461
+ async function persistA2AContinuationDelivery(
462
+ continuation: A2AContinuation,
463
+ outgoing: OutgoingMessage,
464
+ receipt: PlatformDeliveryReceipt,
465
+ artifactText: string,
466
+ ): Promise<void> {
467
+ const mapping = await getThreadMapping(
468
+ continuation.platform,
469
+ continuation.externalThreadId,
470
+ );
471
+ if (!mapping) return;
472
+ const thread = await getThread(mapping.internalThreadId);
473
+ if (!thread) return;
474
+
475
+ let repo: any;
476
+ try {
477
+ repo = JSON.parse(thread.threadData || "{}");
478
+ } catch {
479
+ repo = {};
480
+ }
481
+ if (!Array.isArray(repo.messages)) repo.messages = [];
482
+
483
+ const artifacts = extractA2AArtifactIdentities([
484
+ { tool: "call-agent", result: artifactText },
485
+ ]);
486
+ const metadata: Record<string, unknown> = {
487
+ integrationDeliveryAttempted: true,
488
+ integrationDelivery: {
489
+ platform: continuation.platform,
490
+ status: "delivered",
491
+ text: outgoing.text,
492
+ deliveredAt: new Date().toISOString(),
493
+ ...(receipt.messageRefs?.length
494
+ ? { messageRefs: receipt.messageRefs }
495
+ : {}),
496
+ },
497
+ };
498
+ if (artifacts.length > 0) metadata.integrationArtifacts = artifacts;
499
+
500
+ repo.messages.push({
501
+ id: `msg-${Date.now()}-assistant-continuation`,
502
+ role: "assistant",
503
+ content: [{ type: "text", text: outgoing.text }],
504
+ createdAt: new Date().toISOString(),
505
+ metadata,
506
+ });
507
+ const meta = extractThreadMeta(repo);
508
+ await updateThreadData(
509
+ mapping.internalThreadId,
510
+ JSON.stringify(repo),
511
+ meta.title || thread.title || "Integration Chat",
512
+ meta.preview || thread.preview || "",
513
+ repo.messages.length,
514
+ );
423
515
  }
424
516
 
425
517
  async function rescheduleAndRedispatchA2AContinuation(
@@ -9,6 +9,7 @@ import type {
9
9
  IntegrationStatus,
10
10
  OutgoingMessage,
11
11
  PlatformAdapter,
12
+ PlatformDeliveryReceipt,
12
13
  } from "../types.js";
13
14
 
14
15
  const DISCORD_MAX_CONTENT_LENGTH = 2_000;
@@ -209,7 +210,7 @@ export function discordAdapter(): PlatformAdapter {
209
210
  async sendResponse(
210
211
  message: OutgoingMessage,
211
212
  context: IncomingMessage,
212
- ): Promise<void> {
213
+ ): Promise<void | PlatformDeliveryReceipt> {
213
214
  const applicationId = readString(context.platformContext.applicationId);
214
215
  const interactionToken = readString(
215
216
  context.responseContext?.interactionToken,
@@ -236,6 +237,7 @@ export function discordAdapter(): PlatformAdapter {
236
237
  chunk,
237
238
  );
238
239
  }
240
+ return { status: "delivered" };
239
241
  },
240
242
 
241
243
  formatAgentResponse(text: string): OutgoingMessage {
@@ -18,6 +18,7 @@ import type {
18
18
  OutgoingMessage,
19
19
  IntegrationStatus,
20
20
  OutboundTarget,
21
+ PlatformDeliveryReceipt,
21
22
  } from "../types.js";
22
23
 
23
24
  /** Max body length before truncation */
@@ -249,7 +250,7 @@ export function emailAdapter(): PlatformAdapter {
249
250
  async sendResponse(
250
251
  message: OutgoingMessage,
251
252
  context: IncomingMessage,
252
- ): Promise<void> {
253
+ ): Promise<void | PlatformDeliveryReceipt> {
253
254
  const agentAddress = await resolveSecret("EMAIL_AGENT_ADDRESS");
254
255
  if (!agentAddress) {
255
256
  console.error("[email] EMAIL_AGENT_ADDRESS not configured");
@@ -284,7 +285,9 @@ export function emailAdapter(): PlatformAdapter {
284
285
  });
285
286
  } catch (err) {
286
287
  console.error("[email] Failed to send response:", err);
288
+ throw err;
287
289
  }
290
+ return { status: "delivered" };
288
291
  },
289
292
 
290
293
  async sendMessageToTarget(
@@ -6,6 +6,7 @@ import type {
6
6
  IncomingMessage,
7
7
  OutgoingMessage,
8
8
  IntegrationStatus,
9
+ PlatformDeliveryReceipt,
9
10
  } from "../types.js";
10
11
 
11
12
  /** Google Docs comment replies have no formal length limit but keep it reasonable */
@@ -303,7 +304,7 @@ export function googleDocsAdapter(): PlatformAdapter {
303
304
  async sendResponse(
304
305
  message: OutgoingMessage,
305
306
  context: IncomingMessage,
306
- ): Promise<void> {
307
+ ): Promise<void | PlatformDeliveryReceipt> {
307
308
  const fileId = context.platformContext.fileId as string;
308
309
  const commentId = context.platformContext.commentId as string;
309
310
 
@@ -319,8 +320,10 @@ export function googleDocsAdapter(): PlatformAdapter {
319
320
  await replyToComment(fileId, commentId, chunk, accessToken);
320
321
  } catch (err) {
321
322
  console.error("[google-docs] Failed to send reply:", err);
323
+ throw err;
322
324
  }
323
325
  }
326
+ return { status: "delivered" };
324
327
  },
325
328
 
326
329
  formatAgentResponse(text: string): OutgoingMessage {
@@ -8,6 +8,7 @@ import type {
8
8
  IntegrationStatus,
9
9
  OutgoingMessage,
10
10
  PlatformAdapter,
11
+ PlatformDeliveryReceipt,
11
12
  } from "../types.js";
12
13
 
13
14
  const BOT_FRAMEWORK_SCOPE = "https://api.botframework.com/.default";
@@ -201,7 +202,7 @@ export function microsoftTeamsAdapter(): PlatformAdapter {
201
202
  async sendResponse(
202
203
  message: OutgoingMessage,
203
204
  context: IncomingMessage,
204
- ): Promise<void> {
205
+ ): Promise<void | PlatformDeliveryReceipt> {
205
206
  const serviceUrl = normalizeServiceUrl(
206
207
  context.platformContext.serviceUrl,
207
208
  );
@@ -242,6 +243,7 @@ export function microsoftTeamsAdapter(): PlatformAdapter {
242
243
  `Microsoft Teams reply failed (HTTP ${response.status})`,
243
244
  );
244
245
  }
246
+ return { status: "delivered" };
245
247
  },
246
248
 
247
249
  formatAgentResponse(text: string): OutgoingMessage {
@@ -23,6 +23,7 @@ import type {
23
23
  OutboundTarget,
24
24
  PlatformRunProgress,
25
25
  PlatformRunProgressRef,
26
+ PlatformDeliveryReceipt,
26
27
  IntegrationContextMessage,
27
28
  IntegrationFileReference,
28
29
  } from "../types.js";
@@ -431,11 +432,12 @@ export function slackAdapter(
431
432
  message: OutgoingMessage,
432
433
  context: IncomingMessage,
433
434
  opts?: { placeholderRef?: string },
434
- ): Promise<void> {
435
+ ): Promise<void | PlatformDeliveryReceipt> {
435
436
  const token = await resolveBotToken(context);
436
437
  if (!token) {
437
- console.error("[slack] SLACK_BOT_TOKEN not configured");
438
- return;
438
+ throw new Error(
439
+ "[slack] Cannot deliver response: no Slack bot token is configured",
440
+ );
439
441
  }
440
442
 
441
443
  const channelId = context.platformContext.channelId as string;
@@ -458,6 +460,7 @@ export function slackAdapter(
458
460
  return;
459
461
  }
460
462
  const restChunks = chunks.slice(1);
463
+ const messageRefs: string[] = [];
461
464
 
462
465
  const finalBlocks =
463
466
  blocks ??
@@ -489,14 +492,29 @@ export function slackAdapter(
489
492
  const data = (await res.json()) as {
490
493
  ok: boolean;
491
494
  error?: string;
495
+ ts?: string;
492
496
  };
493
497
  if (!data.ok) {
494
498
  console.error("[slack] chat.update error:", data.error);
495
499
  // Fall back to a fresh post so the user still sees a reply
496
- await postFresh(token, channelId, threadTs, baseBody);
500
+ const postedTs = await postFresh(
501
+ token,
502
+ channelId,
503
+ threadTs,
504
+ baseBody,
505
+ );
506
+ if (postedTs) messageRefs.push(postedTs);
507
+ } else {
508
+ messageRefs.push(data.ts || placeholderRef);
497
509
  }
498
510
  } else {
499
- await postFresh(token, channelId, threadTs, baseBody);
511
+ const postedTs = await postFresh(
512
+ token,
513
+ channelId,
514
+ threadTs,
515
+ baseBody,
516
+ );
517
+ if (postedTs) messageRefs.push(postedTs);
500
518
  }
501
519
 
502
520
  // Clear the AI-assistant "is thinking…" status now that we've
@@ -507,14 +525,19 @@ export function slackAdapter(
507
525
 
508
526
  // Overflow chunks (rare) — post as plain follow-ups in the same thread
509
527
  for (const chunk of restChunks) {
510
- await postFresh(token, channelId, threadTs, {
528
+ const postedTs = await postFresh(token, channelId, threadTs, {
511
529
  channel: channelId,
512
530
  text: chunk,
513
531
  unfurl_links: false,
514
532
  unfurl_media: false,
515
533
  mrkdwn: true,
516
534
  });
535
+ if (postedTs) messageRefs.push(postedTs);
517
536
  }
537
+ return {
538
+ status: "delivered",
539
+ ...(messageRefs.length > 0 ? { messageRefs } : {}),
540
+ };
518
541
  } catch (err) {
519
542
  console.error("[slack] Failed to send message:", err);
520
543
  throw err;
@@ -992,7 +1015,7 @@ async function postFresh(
992
1015
  channelId: string,
993
1016
  threadTs: string | undefined,
994
1017
  body: Record<string, unknown>,
995
- ): Promise<void> {
1018
+ ): Promise<string | undefined> {
996
1019
  const hasBlocks =
997
1020
  Array.isArray(body.blocks) && (body.blocks as unknown[]).length > 0;
998
1021
  if (
@@ -1000,7 +1023,7 @@ async function postFresh(
1000
1023
  body.text.trim().length === 0 &&
1001
1024
  !hasBlocks
1002
1025
  ) {
1003
- return;
1026
+ return undefined;
1004
1027
  }
1005
1028
 
1006
1029
  const payload: Record<string, unknown> = {
@@ -1016,11 +1039,16 @@ async function postFresh(
1016
1039
  },
1017
1040
  body: JSON.stringify(payload),
1018
1041
  });
1019
- const data = (await res.json()) as { ok: boolean; error?: string };
1042
+ const data = (await res.json()) as {
1043
+ ok: boolean;
1044
+ error?: string;
1045
+ ts?: string;
1046
+ };
1020
1047
  if (!data.ok) {
1021
1048
  console.error("[slack] chat.postMessage error:", data.error);
1022
1049
  throw new Error(data.error || "chat.postMessage failed");
1023
1050
  }
1051
+ return data.ts;
1024
1052
  }
1025
1053
 
1026
1054
  async function slackApiFetch(
@@ -1871,6 +1899,7 @@ function createSlackRunProgress(
1871
1899
  : {}),
1872
1900
  });
1873
1901
  setSlackAssistantStatus(token, channel, threadTs, "");
1902
+ return { status: "delivered", messageRefs: [streamTs] };
1874
1903
  },
1875
1904
  async fail(message) {
1876
1905
  if (pendingTimer) clearTimeout(pendingTimer);
@@ -10,6 +10,7 @@ import type {
10
10
  OutgoingMessage,
11
11
  IntegrationStatus,
12
12
  OutboundTarget,
13
+ PlatformDeliveryReceipt,
13
14
  } from "../types.js";
14
15
 
15
16
  /** Telegram's max message length */
@@ -194,7 +195,7 @@ export function telegramAdapter(): PlatformAdapter {
194
195
  async sendResponse(
195
196
  message: OutgoingMessage,
196
197
  context: IncomingMessage,
197
- ): Promise<void> {
198
+ ): Promise<void | PlatformDeliveryReceipt> {
198
199
  const token = await resolveSecret("TELEGRAM_BOT_TOKEN");
199
200
  if (!token) {
200
201
  console.error("[telegram] TELEGRAM_BOT_TOKEN not configured");
@@ -235,22 +236,43 @@ export function telegramAdapter(): PlatformAdapter {
235
236
  if (!data.ok) {
236
237
  // Retry without Markdown if parsing fails
237
238
  if (data.description?.includes("parse")) {
238
- await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
239
- method: "POST",
240
- headers: { "Content-Type": "application/json" },
241
- body: JSON.stringify({
242
- ...body,
243
- parse_mode: undefined,
244
- }),
245
- });
239
+ const retry = await fetch(
240
+ `https://api.telegram.org/bot${token}/sendMessage`,
241
+ {
242
+ method: "POST",
243
+ headers: { "Content-Type": "application/json" },
244
+ body: JSON.stringify({
245
+ ...body,
246
+ parse_mode: undefined,
247
+ }),
248
+ },
249
+ );
250
+ if (!retry.ok) {
251
+ throw new Error(
252
+ `Telegram sendMessage retry failed (HTTP ${retry.status})`,
253
+ );
254
+ }
255
+ const retryData = (await retry.json()) as {
256
+ ok: boolean;
257
+ description?: string;
258
+ };
259
+ if (!retryData.ok) {
260
+ throw new Error(
261
+ `Telegram sendMessage retry failed: ${retryData.description ?? "unknown error"}`,
262
+ );
263
+ }
246
264
  } else {
247
- console.error("[telegram] sendMessage error:", data.description);
265
+ throw new Error(
266
+ `Telegram sendMessage failed: ${data.description ?? "unknown error"}`,
267
+ );
248
268
  }
249
269
  }
250
270
  } catch (err) {
251
271
  console.error("[telegram] Failed to send message:", err);
272
+ throw err;
252
273
  }
253
274
  }
275
+ return { status: "delivered" };
254
276
  },
255
277
 
256
278
  async sendMessageToTarget(
@@ -8,6 +8,7 @@ import type {
8
8
  IncomingMessage,
9
9
  OutgoingMessage,
10
10
  IntegrationStatus,
11
+ PlatformDeliveryReceipt,
11
12
  } from "../types.js";
12
13
 
13
14
  /** WhatsApp's max message length */
@@ -240,7 +241,7 @@ export function whatsappAdapter(): PlatformAdapter {
240
241
  async sendResponse(
241
242
  message: OutgoingMessage,
242
243
  context: IncomingMessage,
243
- ): Promise<void> {
244
+ ): Promise<void | PlatformDeliveryReceipt> {
244
245
  const accessToken = await resolveSecret("WHATSAPP_ACCESS_TOKEN");
245
246
  const phoneNumberId = await resolveSecret("WHATSAPP_PHONE_NUMBER_ID");
246
247
  if (!accessToken || !phoneNumberId) {
@@ -279,11 +280,14 @@ export function whatsappAdapter(): PlatformAdapter {
279
280
  if (!res.ok) {
280
281
  const data = await res.json().catch(() => ({}));
281
282
  console.error("[whatsapp] sendMessage error:", data);
283
+ throw new Error(`WhatsApp sendMessage failed (HTTP ${res.status})`);
282
284
  }
283
285
  } catch (err) {
284
286
  console.error("[whatsapp] Failed to send message:", err);
287
+ throw err;
285
288
  }
286
289
  }
290
+ return { status: "delivered" };
287
291
  },
288
292
 
289
293
  formatAgentResponse(text: string): OutgoingMessage {
@@ -15,6 +15,7 @@ export type {
15
15
  IntegrationConversationType,
16
16
  IntegrationTriggerKind,
17
17
  PlatformRunProgress,
18
+ PlatformDeliveryReceipt,
18
19
  } from "./types.js";
19
20
  export { assertPlatformCapability } from "./types.js";
20
21
 
@@ -127,6 +127,13 @@ export interface OutgoingMessage {
127
127
  platformContext: Record<string, unknown>;
128
128
  }
129
129
 
130
+ /** Provider-confirmed references for a successfully delivered response. */
131
+ export interface PlatformDeliveryReceipt {
132
+ status: "delivered";
133
+ /** Opaque provider message ids/timestamps; never message content. */
134
+ messageRefs?: string[];
135
+ }
136
+
130
137
  /**
131
138
  * Proactive outbound message target for a platform.
132
139
  * Used when the agent needs to send to a saved destination instead of replying
@@ -197,7 +204,7 @@ export interface PlatformRunProgress {
197
204
  /** Receive normalized agent events. Implementations should throttle writes. */
198
205
  onEvent(event: AgentChatEvent): Promise<void> | void;
199
206
  /** Finalize the provider-native progress surface with the answer. */
200
- complete(message: OutgoingMessage): Promise<void>;
207
+ complete(message: OutgoingMessage): Promise<void | PlatformDeliveryReceipt>;
201
208
  /** Mark the provider-native surface failed and leave a retryable explanation. */
202
209
  fail?(message: string): Promise<void>;
203
210
  }
@@ -316,7 +323,7 @@ export interface PlatformAdapter {
316
323
  message: OutgoingMessage,
317
324
  context: IncomingMessage,
318
325
  opts?: { placeholderRef?: string },
319
- ): Promise<void>;
326
+ ): Promise<void | PlatformDeliveryReceipt>;
320
327
 
321
328
  /**
322
329
  * Send a short best-effort system notice to the conversation the incoming