@agent-native/toolkit 0.221.0-same-host-mcp-20261027-20261027081850 → 0.221.0

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/agent-native.eject.json +16 -1
  2. package/dist/app/agentkit/react/components.d.ts +5 -3
  3. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  4. package/dist/app/agentkit/react/components.js +103 -42
  5. package/dist/app/agentkit/react/components.js.map +1 -1
  6. package/dist/app/agentkit/react/styles.css +93 -65
  7. package/dist/app/agentkit/react/voice-transcripts.d.ts +22 -1
  8. package/dist/app/agentkit/react/voice-transcripts.d.ts.map +1 -1
  9. package/dist/app/agentkit/react/voice-transcripts.js +209 -8
  10. package/dist/app/agentkit/react/voice-transcripts.js.map +1 -1
  11. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  12. package/dist/app/chat/AgentKitAssistantChat.js +55 -40
  13. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  14. package/dist/app/chat/agentkit-chat/guided-questions.d.ts +1 -0
  15. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  16. package/dist/app/chat/agentkit-chat/guided-questions.js +18 -6
  17. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  18. package/dist/app/chat/agentkit-chat/index.d.ts +1 -1
  19. package/dist/app/chat/agentkit-chat/index.d.ts.map +1 -1
  20. package/dist/app/chat/agentkit-chat/index.js +1 -1
  21. package/dist/app/chat/agentkit-chat/index.js.map +1 -1
  22. package/dist/app/chat/chat/run-recovery.d.ts.map +1 -1
  23. package/dist/app/chat/chat/run-recovery.js +5 -1
  24. package/dist/app/chat/chat/run-recovery.js.map +1 -1
  25. package/dist/app/chat/composer/runtime-adapters.d.ts.map +1 -1
  26. package/dist/app/chat/composer/runtime-adapters.js +2 -0
  27. package/dist/app/chat/composer/runtime-adapters.js.map +1 -1
  28. package/dist/app/chat/reply-connection-suggestion.d.ts +29 -0
  29. package/dist/app/chat/reply-connection-suggestion.d.ts.map +1 -0
  30. package/dist/app/chat/reply-connection-suggestion.js +42 -0
  31. package/dist/app/chat/reply-connection-suggestion.js.map +1 -0
  32. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  33. package/dist/app/i18n/catalogs/ar-SA.js +7 -0
  34. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  35. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  36. package/dist/app/i18n/catalogs/de-DE.js +7 -0
  37. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  38. package/dist/app/i18n/catalogs/en-US.d.ts +7 -0
  39. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/en-US.js +7 -0
  41. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  42. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/es-ES.js +7 -0
  44. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  45. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/fr-FR.js +7 -0
  47. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  48. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/hi-IN.js +7 -0
  50. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  51. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/ja-JP.js +7 -0
  53. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  54. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  55. package/dist/app/i18n/catalogs/ko-KR.js +7 -0
  56. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  57. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  58. package/dist/app/i18n/catalogs/pt-BR.js +7 -0
  59. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  60. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  61. package/dist/app/i18n/catalogs/zh-CN.js +7 -0
  62. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  63. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  64. package/dist/app/i18n/catalogs/zh-TW.js +7 -0
  65. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  66. package/dist/app/mcp-approval/McpApprovalReview.d.ts +25 -0
  67. package/dist/app/mcp-approval/McpApprovalReview.d.ts.map +1 -0
  68. package/dist/app/mcp-approval/McpApprovalReview.js +342 -0
  69. package/dist/app/mcp-approval/McpApprovalReview.js.map +1 -0
  70. package/dist/app/onboarding/FirstRunOnboarding.d.ts.map +1 -1
  71. package/dist/app/onboarding/FirstRunOnboarding.js +299 -71
  72. package/dist/app/onboarding/FirstRunOnboarding.js.map +1 -1
  73. package/dist/app/onboarding/GettingStartedCard.js +1 -1
  74. package/dist/app/onboarding/GettingStartedCard.js.map +1 -1
  75. package/dist/app/onboarding/first-run-builder-credits-flag.d.ts +2 -0
  76. package/dist/app/onboarding/first-run-builder-credits-flag.d.ts.map +1 -0
  77. package/dist/app/onboarding/first-run-builder-credits-flag.js +8 -0
  78. package/dist/app/onboarding/first-run-builder-credits-flag.js.map +1 -0
  79. package/dist/app/providers/AppProviders.d.ts.map +1 -1
  80. package/dist/app/providers/AppProviders.js +14 -1
  81. package/dist/app/providers/AppProviders.js.map +1 -1
  82. package/dist/app/resources/McpConnectionSuggestion.d.ts +2 -4
  83. package/dist/app/resources/McpConnectionSuggestion.d.ts.map +1 -1
  84. package/dist/app/resources/McpConnectionSuggestion.js +59 -36
  85. package/dist/app/resources/McpConnectionSuggestion.js.map +1 -1
  86. package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
  87. package/dist/app/settings/account/PreferencesSettings.js +14 -1
  88. package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
  89. package/dist/app/settings/account/ThemeFamilySettings.js +2 -2
  90. package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -1
  91. package/dist/app/settings/account/search-entries.d.ts +1 -0
  92. package/dist/app/settings/account/search-entries.d.ts.map +1 -1
  93. package/dist/app/settings/account/search-entries.js +5 -0
  94. package/dist/app/settings/account/search-entries.js.map +1 -1
  95. package/dist/app/settings/shell/SettingsShell.d.ts.map +1 -1
  96. package/dist/app/settings/shell/SettingsShell.js +26 -2
  97. package/dist/app/settings/shell/SettingsShell.js.map +1 -1
  98. package/dist/app/shared/AppShellSkeleton.d.ts.map +1 -1
  99. package/dist/app/shared/AppShellSkeleton.js +4 -10
  100. package/dist/app/shared/AppShellSkeleton.js.map +1 -1
  101. package/dist/app/shared/EnvironmentBadge.d.ts +2 -1
  102. package/dist/app/shared/EnvironmentBadge.d.ts.map +1 -1
  103. package/dist/app/shared/EnvironmentBadge.js +2 -3
  104. package/dist/app/shared/EnvironmentBadge.js.map +1 -1
  105. package/dist/app/shared/is-builder-io-employee.d.ts +8 -0
  106. package/dist/app/shared/is-builder-io-employee.d.ts.map +1 -0
  107. package/dist/app/shared/is-builder-io-employee.js +10 -0
  108. package/dist/app/shared/is-builder-io-employee.js.map +1 -0
  109. package/dist/app/styles/agent-conversation.css +30 -17
  110. package/dist/app/styles/theme-families.css +22 -5
  111. package/dist/app/styles/tokens/agent-kit.css +3 -3
  112. package/dist/composer/PromptComposer.d.ts +15 -3
  113. package/dist/composer/PromptComposer.d.ts.map +1 -1
  114. package/dist/composer/PromptComposer.js +74 -16
  115. package/dist/composer/PromptComposer.js.map +1 -1
  116. package/dist/composer/RealtimeVoiceMode.d.ts +7 -0
  117. package/dist/composer/RealtimeVoiceMode.d.ts.map +1 -1
  118. package/dist/composer/RealtimeVoiceMode.js +9 -2
  119. package/dist/composer/RealtimeVoiceMode.js.map +1 -1
  120. package/dist/composer/TiptapComposer.d.ts +7 -0
  121. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  122. package/dist/composer/TiptapComposer.js +12 -4
  123. package/dist/composer/TiptapComposer.js.map +1 -1
  124. package/dist/composer/VoiceButton.d.ts +2 -0
  125. package/dist/composer/VoiceButton.d.ts.map +1 -1
  126. package/dist/composer/VoiceButton.js +5 -4
  127. package/dist/composer/VoiceButton.js.map +1 -1
  128. package/dist/composer/index.d.ts +2 -2
  129. package/dist/composer/index.d.ts.map +1 -1
  130. package/dist/composer/index.js +1 -1
  131. package/dist/composer/index.js.map +1 -1
  132. package/dist/composer/prompt-attachments.d.ts +20 -0
  133. package/dist/composer/prompt-attachments.d.ts.map +1 -1
  134. package/dist/composer/prompt-attachments.js +188 -11
  135. package/dist/composer/prompt-attachments.js.map +1 -1
  136. package/dist/composer/realtime-voice-transcript.d.ts +27 -0
  137. package/dist/composer/realtime-voice-transcript.d.ts.map +1 -1
  138. package/dist/composer/realtime-voice-transcript.js +34 -1
  139. package/dist/composer/realtime-voice-transcript.js.map +1 -1
  140. package/dist/composer/realtime-voice-turn-metrics.d.ts +43 -0
  141. package/dist/composer/realtime-voice-turn-metrics.d.ts.map +1 -0
  142. package/dist/composer/realtime-voice-turn-metrics.js +132 -0
  143. package/dist/composer/realtime-voice-turn-metrics.js.map +1 -0
  144. package/dist/composer/runtime-adapters.d.ts +4 -1
  145. package/dist/composer/runtime-adapters.d.ts.map +1 -1
  146. package/dist/composer/runtime-adapters.js +2 -1
  147. package/dist/composer/runtime-adapters.js.map +1 -1
  148. package/dist/composer/useRealtimeVoiceMode.d.ts +61 -9
  149. package/dist/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  150. package/dist/composer/useRealtimeVoiceMode.js +536 -99
  151. package/dist/composer/useRealtimeVoiceMode.js.map +1 -1
  152. package/dist/composer/voice-chat-icon.d.ts +7 -0
  153. package/dist/composer/voice-chat-icon.d.ts.map +1 -0
  154. package/dist/composer/voice-chat-icon.js +14 -0
  155. package/dist/composer/voice-chat-icon.js.map +1 -0
  156. package/dist/editor/DragHandle.d.ts +12 -1
  157. package/dist/editor/DragHandle.d.ts.map +1 -1
  158. package/dist/editor/DragHandle.js +165 -41
  159. package/dist/editor/DragHandle.js.map +1 -1
  160. package/dist/editor/RegistryBlockNode.d.ts +20 -0
  161. package/dist/editor/RegistryBlockNode.d.ts.map +1 -1
  162. package/dist/editor/RegistryBlockNode.js +58 -13
  163. package/dist/editor/RegistryBlockNode.js.map +1 -1
  164. package/dist/editor/index.d.ts +2 -2
  165. package/dist/editor/index.d.ts.map +1 -1
  166. package/dist/editor/index.js +1 -1
  167. package/dist/editor/index.js.map +1 -1
  168. package/dist/styles.css +2 -0
  169. package/dist/ui/dropdown-menu.d.ts.map +1 -1
  170. package/dist/ui/dropdown-menu.js +5 -1
  171. package/dist/ui/dropdown-menu.js.map +1 -1
  172. package/package.json +14 -4
  173. package/src/app/agentkit/react/components.regenerate-readiness.spec.tsx +3 -1
  174. package/src/app/agentkit/react/components.spec.tsx +24 -4
  175. package/src/app/agentkit/react/components.tsx +174 -44
  176. package/src/app/agentkit/react/composer-context.spec.tsx +3 -0
  177. package/src/app/agentkit/react/disclosures.spec.tsx +124 -0
  178. package/src/app/agentkit/react/lifecycle.spec.tsx +8 -2
  179. package/src/app/agentkit/react/message-actions.spec.tsx +161 -5
  180. package/src/app/agentkit/react/saved-reply-reload.spec.tsx +206 -0
  181. package/src/app/agentkit/react/styles.css +93 -65
  182. package/src/app/agentkit/react/voice-transcripts.spec.tsx +239 -4
  183. package/src/app/agentkit/react/voice-transcripts.ts +245 -8
  184. package/src/app/chat/AgentKitAssistantChat.spec.tsx +59 -11
  185. package/src/app/chat/AgentKitAssistantChat.tsx +74 -62
  186. package/src/app/chat/agentkit-chat/guided-answers-context.spec.ts +9 -0
  187. package/src/app/chat/agentkit-chat/guided-questions.tsx +17 -7
  188. package/src/app/chat/agentkit-chat/index.ts +1 -0
  189. package/src/app/chat/chat/run-recovery.spec.tsx +45 -0
  190. package/src/app/chat/chat/run-recovery.tsx +6 -1
  191. package/src/app/chat/composer/runtime-adapters.tsx +2 -0
  192. package/src/app/chat/reply-connection-suggestion.spec.ts +121 -0
  193. package/src/app/chat/reply-connection-suggestion.ts +76 -0
  194. package/src/app/i18n/catalogs/ar-SA.ts +10 -0
  195. package/src/app/i18n/catalogs/de-DE.ts +10 -0
  196. package/src/app/i18n/catalogs/en-US.ts +10 -0
  197. package/src/app/i18n/catalogs/es-ES.ts +10 -0
  198. package/src/app/i18n/catalogs/fr-FR.ts +10 -0
  199. package/src/app/i18n/catalogs/hi-IN.ts +10 -0
  200. package/src/app/i18n/catalogs/ja-JP.ts +10 -0
  201. package/src/app/i18n/catalogs/ko-KR.ts +10 -0
  202. package/src/app/i18n/catalogs/pt-BR.ts +10 -0
  203. package/src/app/i18n/catalogs/zh-CN.ts +10 -0
  204. package/src/app/i18n/catalogs/zh-TW.ts +10 -0
  205. package/src/app/mcp-approval/McpApprovalReview.spec.tsx +687 -0
  206. package/src/app/mcp-approval/McpApprovalReview.tsx +913 -0
  207. package/src/app/onboarding/FirstRunOnboarding.spec.tsx +736 -26
  208. package/src/app/onboarding/FirstRunOnboarding.tsx +473 -145
  209. package/src/app/onboarding/GettingStartedCard.tsx +1 -1
  210. package/src/app/onboarding/first-run-builder-credits-flag.spec.ts +13 -0
  211. package/src/app/onboarding/first-run-builder-credits-flag.ts +9 -0
  212. package/src/app/providers/AppProviders.spec.tsx +109 -0
  213. package/src/app/providers/AppProviders.tsx +53 -1
  214. package/src/app/resources/McpConnectionSuggestion.spec.ts +77 -12
  215. package/src/app/resources/McpConnectionSuggestion.tsx +69 -51
  216. package/src/app/settings/VoiceChatSettings.spec.tsx +6 -1
  217. package/src/app/settings/account/PreferencesSettings.spec.tsx +73 -0
  218. package/src/app/settings/account/PreferencesSettings.tsx +24 -7
  219. package/src/app/settings/account/ThemeFamilySettings.tsx +2 -2
  220. package/src/app/settings/account/search-entries.spec.ts +14 -0
  221. package/src/app/settings/account/search-entries.ts +9 -0
  222. package/src/app/settings/shell/SettingsShell.tsx +29 -2
  223. package/src/app/shared/AppShellSkeleton.spec.tsx +2 -2
  224. package/src/app/shared/AppShellSkeleton.tsx +3 -16
  225. package/src/app/shared/EnvironmentBadge.tsx +3 -4
  226. package/src/app/shared/is-builder-io-employee.ts +17 -0
  227. package/src/app/styles/agent-conversation.css +30 -17
  228. package/src/app/styles/theme-families.css +22 -5
  229. package/src/app/styles/theme-families.spec.ts +73 -0
  230. package/src/app/styles/tokens/agent-kit.css +3 -3
  231. package/src/composer/AgentSuggestionBar.overflow.spec.tsx +1 -1
  232. package/src/composer/AttachmentChip.spec.tsx +87 -0
  233. package/src/composer/PromptComposer.context.spec.tsx +8 -4
  234. package/src/composer/PromptComposer.setup-card.spec.tsx +170 -0
  235. package/src/composer/PromptComposer.tsx +125 -14
  236. package/src/composer/RealtimeVoiceMode.spec.tsx +48 -0
  237. package/src/composer/RealtimeVoiceMode.tsx +45 -2
  238. package/src/composer/TiptapComposer.tsx +25 -0
  239. package/src/composer/TiptapComposer.voice-toolbar.spec.tsx +4 -1
  240. package/src/composer/VoiceButton.tsx +8 -3
  241. package/src/composer/index.ts +4 -0
  242. package/src/composer/prompt-attachments.spec.ts +160 -8
  243. package/src/composer/prompt-attachments.ts +221 -12
  244. package/src/composer/realtime-voice-transcript.spec.ts +36 -0
  245. package/src/composer/realtime-voice-transcript.ts +56 -1
  246. package/src/composer/realtime-voice-turn-metrics.spec.ts +175 -0
  247. package/src/composer/realtime-voice-turn-metrics.ts +192 -0
  248. package/src/composer/runtime-adapters.tsx +5 -1
  249. package/src/composer/useRealtimeVoiceMode.session.spec.tsx +487 -2
  250. package/src/composer/useRealtimeVoiceMode.spec.ts +267 -65
  251. package/src/composer/useRealtimeVoiceMode.tsx +716 -139
  252. package/src/composer/voice-chat-icon.tsx +19 -0
  253. package/src/editor/DragHandle.spec.ts +217 -0
  254. package/src/editor/DragHandle.ts +214 -55
  255. package/src/editor/RegistryBlockNode.spec.ts +172 -2
  256. package/src/editor/RegistryBlockNode.tsx +91 -13
  257. package/src/editor/index.ts +4 -0
  258. package/src/styles.css +2 -0
  259. package/src/ui/dropdown-menu.tsx +4 -0
@@ -237,6 +237,11 @@ import {
237
237
  isWaitingOnConnectionRequest,
238
238
  reconcileSettledRun,
239
239
  } from "./reconcile-settled-run.js";
240
+ import {
241
+ pickReplyConnectionSuggestion,
242
+ latestReplyContext,
243
+ type LatestReplyContext,
244
+ } from "./reply-connection-suggestion.js";
240
245
  import { RunStuckBanner } from "./RunStuckBanner.js";
241
246
  import { SESSION_REPLAY_MASK_PROPS } from "./session-replay-privacy.js";
242
247
  import { ThinkingDisplayProvider } from "./thinking-display.js";
@@ -1455,6 +1460,8 @@ interface AgentKitSurfaceContextValue {
1455
1460
  hasRenderedMessages: boolean;
1456
1461
  canChat: boolean;
1457
1462
  setupMissing: boolean;
1463
+ /** Only the server's readiness answer, never the model list's early guess. */
1464
+ setupConfirmedMissing: boolean;
1458
1465
  providerStatus: AgentEngineConfiguredState;
1459
1466
  modelListUnavailable: boolean;
1460
1467
  retryProviderStatus: () => void;
@@ -1476,6 +1483,7 @@ interface AgentKitSurfaceContextValue {
1476
1483
  authSessionAvailable: boolean;
1477
1484
  setupBouncePulse: number;
1478
1485
  bounceSetupCard: () => void;
1486
+ onComposerSetupRequiredChange: (required: boolean) => void;
1479
1487
  isSubmissionInFlight: boolean;
1480
1488
  composerSubmissionPending: boolean;
1481
1489
  onComposerSubmissionPendingChange: (pending: boolean) => void;
@@ -2341,8 +2349,22 @@ const AgentKitAssistantChatBody = forwardRef<
2341
2349
  props.showModelSelector !== false && props.modelListError === true;
2342
2350
  const effectiveReadiness = readiness.state;
2343
2351
  const canChat = !providerChecksEnabled || effectiveReadiness === "configured";
2344
- const setupMissing =
2352
+ const [composerSetupRequired, setComposerSetupRequired] = useState(false);
2353
+ const setupConfirmedMissing =
2345
2354
  providerChecksEnabled && effectiveReadiness === "missing";
2355
+ // The composer's model list knows nothing is connected well before the
2356
+ // readiness check answers; an answer of "configured" still wins. Only this
2357
+ // chat's own card can show on that guess: a host-owned card waits for the
2358
+ // server, and acting on the guess without it closes the prompt with nothing
2359
+ // on screen to explain why.
2360
+ const ownsSetupCard =
2361
+ props.showMissingApiKeySetup !== false && props.setupCardOwner !== "host";
2362
+ const setupMissing =
2363
+ setupConfirmedMissing ||
2364
+ (providerChecksEnabled &&
2365
+ ownsSetupCard &&
2366
+ effectiveReadiness !== "configured" &&
2367
+ composerSetupRequired);
2346
2368
  const providerStatus: AgentEngineConfiguredState = setupMissing
2347
2369
  ? "missing"
2348
2370
  : modelListUnavailable
@@ -4947,6 +4969,7 @@ const AgentKitAssistantChatBody = forwardRef<
4947
4969
  hasRenderedMessages,
4948
4970
  canChat,
4949
4971
  setupMissing,
4972
+ setupConfirmedMissing,
4950
4973
  providerStatus,
4951
4974
  modelListUnavailable,
4952
4975
  retryProviderStatus,
@@ -4971,6 +4994,7 @@ const AgentKitAssistantChatBody = forwardRef<
4971
4994
  authSessionAvailable,
4972
4995
  setupBouncePulse,
4973
4996
  bounceSetupCard,
4997
+ onComposerSetupRequiredChange: setComposerSetupRequired,
4974
4998
  isSubmissionInFlight,
4975
4999
  composerSubmissionPending,
4976
5000
  onComposerSubmissionPendingChange: setComposerSubmissionPending,
@@ -5685,6 +5709,7 @@ function AgentKitComposerSurface({
5685
5709
  showSuggestions,
5686
5710
  setupBouncePulse,
5687
5711
  bounceSetupCard,
5712
+ onComposerSetupRequiredChange,
5688
5713
  contextItems,
5689
5714
  providerContextItems,
5690
5715
  selectionLength,
@@ -5723,6 +5748,7 @@ function AgentKitComposerSurface({
5723
5748
  hasRenderedMessages: boolean;
5724
5749
  setupBouncePulse: number;
5725
5750
  bounceSetupCard: () => void;
5751
+ onComposerSetupRequiredChange: (required: boolean) => void;
5726
5752
  contextItems: AgentChatContextItem[];
5727
5753
  providerContextItems: { current: readonly AgentChatContextItem[] };
5728
5754
  selectionLength: number | null;
@@ -5939,12 +5965,6 @@ function AgentKitComposerSurface({
5939
5965
  },
5940
5966
  onError: (error) => setComposerError(error.message),
5941
5967
  });
5942
- const integration = findMcpConnectionSuggestionIntegration({
5943
- text,
5944
- variant: "composer",
5945
- requestedByUser: true,
5946
- excludedIntegrationIds: props.mcpSuggestionExcludedIntegrationIds,
5947
- });
5948
5968
  const showHomeIntro =
5949
5969
  props.homeIntroSlot &&
5950
5970
  !hasRenderedMessages &&
@@ -6039,15 +6059,6 @@ function AgentKitComposerSurface({
6039
6059
  onRetry={modelListUnavailable ? retryModelList : retryProviderStatus}
6040
6060
  />
6041
6061
  ) : null}
6042
- {integration ? (
6043
- <McpConnectionSuggestion
6044
- text={text}
6045
- variant="composer"
6046
- requestedByUser
6047
- excludedIntegrationIds={props.mcpSuggestionExcludedIntegrationIds}
6048
- integrationId={integration.id}
6049
- />
6050
- ) : null}
6051
6062
  {selectionLength !== null && selectionLength > 0 ? (
6052
6063
  <AgentKitSelectionPill
6053
6064
  length={selectionLength}
@@ -6107,6 +6118,7 @@ function AgentKitComposerSurface({
6107
6118
  initialTextKey={`${props.tabId ?? threadId}:${prefillRevision}`}
6108
6119
  showMissingApiKeySetup={false}
6109
6120
  setupCardVisible={composerShowsSetupCard({ setupMissing, props })}
6121
+ onModelConnectionRequiredChange={onComposerSetupRequiredChange}
6110
6122
  onTextChange={onTextChange}
6111
6123
  announcePendingSubmission={!isThinkingVisibleInTranscript}
6112
6124
  onSubmissionPendingChange={onComposerSubmissionPendingChange}
@@ -6308,68 +6320,66 @@ function AgentKitUserMessage(props: AgentKitRenderProps<AgentMessage>) {
6308
6320
  return <AgentMessageView {...props} value={visible} />;
6309
6321
  }
6310
6322
 
6311
- interface AgentKitSuggestionContext {
6312
- latestUser?: AgentMessage | undefined;
6323
+ interface AgentKitSuggestionContext extends LatestReplyContext {
6313
6324
  runsActive: boolean;
6314
6325
  }
6315
6326
 
6316
- const NO_SUGGESTION_CONTEXT: AgentKitSuggestionContext = { runsActive: true };
6317
-
6318
- function latestUserMessageBefore(
6319
- messages: readonly AgentMessage[],
6320
- messageId: string,
6321
- ): AgentMessage | undefined {
6322
- const index = messages.findIndex((message) => message.id === messageId);
6323
- return messages
6324
- .slice(0, Math.max(0, index))
6325
- .findLast((message) => message.role === "user");
6326
- }
6327
+ const NO_SUGGESTION_CONTEXT: AgentKitSuggestionContext = {
6328
+ isLatest: false,
6329
+ userText: "",
6330
+ agentRequestedProviders: "",
6331
+ runsActive: true,
6332
+ };
6327
6333
 
6328
6334
  function AgentKitMessageSupplement(props: AgentKitRenderProps<AgentMessage>) {
6329
6335
  const value = props.value;
6330
6336
  const t = useT();
6331
6337
  const surface = useAgentKitSurface();
6332
- const offersSuggestion =
6333
- value.role === "assistant" && value.status === "complete";
6338
+ const isAssistant = value.role === "assistant";
6334
6339
  // Every row renders this, so it reads only what it shows; a whole-thread
6335
6340
  // subscription would re-render every row on every streamed delta.
6336
- const { latestUser, runsActive } = useAgentThreadSelector(
6337
- (thread): AgentKitSuggestionContext =>
6338
- offersSuggestion
6339
- ? {
6340
- latestUser: latestUserMessageBefore(thread.messages, value.id),
6341
- runsActive: hasActiveAgentRuns(thread),
6342
- }
6343
- : NO_SUGGESTION_CONTEXT,
6341
+ const suggestion = useAgentThreadSelector(
6342
+ (thread): AgentKitSuggestionContext => {
6343
+ const context = isAssistant
6344
+ ? latestReplyContext(thread, value.id)
6345
+ : undefined;
6346
+ return context?.isLatest
6347
+ ? { ...context, runsActive: hasActiveAgentRuns(thread) }
6348
+ : NO_SUGGESTION_CONTEXT;
6349
+ },
6344
6350
  (previous, next) =>
6345
- previous.latestUser === next.latestUser &&
6351
+ previous.isLatest === next.isLatest &&
6352
+ previous.userText === next.userText &&
6353
+ previous.agentRequestedProviders === next.agentRequestedProviders &&
6346
6354
  previous.runsActive === next.runsActive,
6347
6355
  props.threadId,
6348
6356
  );
6349
- const contextText =
6350
- latestUser?.parts
6351
- .filter((part) => part.type === "text")
6352
- .map((part) =>
6353
- part.type === "text"
6354
- ? splitAgentChatContextFromMessage(part.text).message
6355
- : "",
6356
- )
6357
- .join("\n") ?? "";
6358
6357
  const text = value.parts
6359
6358
  .filter((part) => part.type === "text")
6360
6359
  .map((part) => (part.type === "text" ? part.text : ""))
6361
6360
  .join("\n");
6362
- const integration =
6363
- offersSuggestion && !runsActive
6364
- ? findMcpConnectionSuggestionIntegration({
6365
- text,
6366
- contextText,
6367
- variant: "response",
6368
- requestedByAgent: true,
6369
- excludedIntegrationIds:
6370
- surface.props.mcpSuggestionExcludedIntegrationIds,
6371
- })
6372
- : null;
6361
+ const excludedIntegrationIds =
6362
+ surface.props.mcpSuggestionExcludedIntegrationIds;
6363
+ const replyFinished = value.status === "complete" && !suggestion.runsActive;
6364
+ // The streaming row re-renders on every delta; its ask is read once done.
6365
+ const replyText = replyFinished ? text : "";
6366
+ const integration = useMemo(
6367
+ () =>
6368
+ isAssistant
6369
+ ? pickReplyConnectionSuggestion({
6370
+ context: suggestion,
6371
+ replyText,
6372
+ replyFinished,
6373
+ find: (message) =>
6374
+ findMcpConnectionSuggestionIntegration({
6375
+ text: message,
6376
+ variant: "response",
6377
+ ...(excludedIntegrationIds ? { excludedIntegrationIds } : {}),
6378
+ }),
6379
+ })
6380
+ : null,
6381
+ [excludedIntegrationIds, isAssistant, replyFinished, replyText, suggestion],
6382
+ );
6373
6383
  const runWarning = asRecord(asRecord(value.metadata?.custom)?.runWarning);
6374
6384
  const missingFinalResponse =
6375
6385
  runWarning?.errorCode === "final_response_missing_after_tool";
@@ -6401,7 +6411,7 @@ function AgentKitMessageSupplement(props: AgentKitRenderProps<AgentMessage>) {
6401
6411
  {integration ? (
6402
6412
  <McpConnectionSuggestion
6403
6413
  text={text}
6404
- contextText={contextText}
6414
+ contextText={suggestion.userText}
6405
6415
  variant="response"
6406
6416
  requestedByAgent
6407
6417
  excludedIntegrationIds={
@@ -6886,7 +6896,9 @@ function useResumeAfterAiSetup(
6886
6896
  ): () => void {
6887
6897
  const surface = useAgentKitSurface();
6888
6898
  const sawSetupMissingRef = useRef(false);
6889
- if (surface.setupMissing) sawSetupMissingRef.current = true;
6899
+ // A resend fires without a fresh user action, so only the server's answer
6900
+ // arms it; the model list's early guess can be briefly wrong.
6901
+ if (surface.setupConfirmedMissing) sawSetupMissingRef.current = true;
6890
6902
  const latestRef = useRef({ resendKey, enabled, resend });
6891
6903
  latestRef.current = { resendKey, enabled, resend };
6892
6904
  const resumed = surface.resumedAfterSetup;
@@ -58,6 +58,15 @@ describe("formatGuidedAnswersForAgent", () => {
58
58
  );
59
59
  });
60
60
 
61
+ it("keeps skipped questions in the order the user saw them", () => {
62
+ expect(
63
+ formatGuidedAnswersForAgent({ q2: "No" }, [
64
+ { id: "q1", type: "text-options", question: "Framework?" },
65
+ { id: "q2", type: "text-options", question: "Auth required?" },
66
+ ]),
67
+ ).toBe("Q: Framework?\nA: no answer\nQ: Auth required?\nA: No");
68
+ });
69
+
61
70
  it("keeps meaningful ids as labels when no question is supplied", () => {
62
71
  expect(
63
72
  formatGuidedAnswersForAgent({
@@ -161,18 +161,28 @@ export function formatGuidedAnswersForAgent(
161
161
  .filter((question) => question.question?.trim())
162
162
  .map((question) => [question.id, question.question.trim()] as const),
163
163
  );
164
- return Object.entries(normalizeGuidedAnswers(answers))
165
- .filter(([, value]) => hasGuidedAnswer(value))
166
- .map(([id, value]) => {
167
- const answer = Array.isArray(value) ? value.join(", ") : String(value);
164
+ const normalized = normalizeGuidedAnswers(answers);
165
+ const declaredIds = new Set((questions ?? []).map((question) => question.id));
166
+ // Declared question order keeps the summary in the order the user saw; skipped questions stay visible so the agent can state its assumption.
167
+ const ids = [...new Set([...declaredIds, ...Object.keys(normalized)])];
168
+ return ids
169
+ .flatMap((id) => {
170
+ const value = Object.hasOwn(normalized, id) ? normalized[id] : undefined;
168
171
  const question = questionTextById.get(id);
169
- return question ? `Q: ${question}\nA: ${answer}` : `${id}: ${answer}`;
172
+ if (!hasGuidedAnswer(value)) {
173
+ if (!declaredIds.has(id)) return [];
174
+ return [question ? `Q: ${question}\nA: no answer` : `${id}: no answer`];
175
+ }
176
+ const answer = Array.isArray(value) ? value.join(", ") : String(value);
177
+ return [question ? `Q: ${question}\nA: ${answer}` : `${id}: ${answer}`];
170
178
  })
171
179
  .join("\n");
172
180
  }
173
181
 
174
- const SETTLED_ANSWERS_INSTRUCTION =
175
- "Treat every question below as settled: do not ask it again, and do not ask for a confirmation of it. Continue the work these answers were blocking.";
182
+ export const SETTLED_ANSWERS_INSTRUCTION = [
183
+ "Treat every question below as settled: do not ask it again, and do not ask for a confirmation of it. Continue the work these answers were blocking.",
184
+ "Open your reply with a short summary: one line per question pairing the question with the user's answer in plain words. For a question marked no answer, say so and state the assumption you will use. Then close with one line saying what you will do next.",
185
+ ].join(" ");
176
186
 
177
187
  function defaultGuidedSubmitContext(formattedAnswers: string): string {
178
188
  return [
@@ -15,6 +15,7 @@ export {
15
15
  isOtherGuidedAnswer,
16
16
  makeOtherGuidedAnswer,
17
17
  normalizeGuidedAnswers,
18
+ SETTLED_ANSWERS_INSTRUCTION,
18
19
  type AskUserQuestionInput,
19
20
  type AskUserQuestionOption,
20
21
  type AskUserQuestionResult,
@@ -1247,6 +1247,51 @@ describe("run recovery surfaces", () => {
1247
1247
  );
1248
1248
  });
1249
1249
 
1250
+ it("hides a failed Builder status read on the card but keeps connect errors", async () => {
1251
+ const renderCard = () => (
1252
+ <AgentNativeI18nProvider
1253
+ initialLocale="en-US"
1254
+ initialPreference="en-US"
1255
+ persistPreference={false}
1256
+ >
1257
+ <BuilderSetupCard />
1258
+ </AgentNativeI18nProvider>
1259
+ );
1260
+ builderFlowMock.state.statusUnavailable = true;
1261
+ builderFlowMock.state.errorKind = "status-read";
1262
+ builderFlowMock.state.error = "Connection status is unavailable.";
1263
+ await act(async () => {
1264
+ root.render(renderCard());
1265
+ });
1266
+ expect(container.textContent).not.toContain(
1267
+ "Connection status is unavailable.",
1268
+ );
1269
+
1270
+ builderFlowMock.state.statusUnavailable = false;
1271
+ builderFlowMock.state.errorKind = "connection";
1272
+ builderFlowMock.state.error = "Builder.io sign-in was cancelled.";
1273
+ await act(async () => {
1274
+ root.render(renderCard());
1275
+ });
1276
+ expect(container.textContent).toContain(
1277
+ "Builder.io sign-in was cancelled.",
1278
+ );
1279
+
1280
+ builderFlowMock.state.statusUnavailable = true;
1281
+ builderFlowMock.state.errorKind = "status-read";
1282
+ builderFlowMock.state.error = "Connection status is unavailable.";
1283
+ builderFlowMock.state.terminalError = "Builder.io sign-in was cancelled.";
1284
+ await act(async () => {
1285
+ root.render(renderCard());
1286
+ });
1287
+ expect(container.textContent).toContain(
1288
+ "Builder.io sign-in was cancelled.",
1289
+ );
1290
+ expect(container.textContent).not.toContain(
1291
+ "Connection status is unavailable.",
1292
+ );
1293
+ });
1294
+
1250
1295
  it("records bounded Builder failure outcomes after a setup attempt", async () => {
1251
1296
  const renderCard = () => (
1252
1297
  <AgentNativeI18nProvider
@@ -343,7 +343,12 @@ export function BuilderConnectCta({
343
343
  trackingSource: "assistant_chat_builder_cta",
344
344
  onConnected: handleConnected,
345
345
  });
346
- const { configured, orgName, connecting, error } = flow;
346
+ const { configured, orgName, connecting } = flow;
347
+ // A failed status read changes nothing here: the card only shows while AI
348
+ // is missing, and connecting re-reads status. Its retry lives in Settings.
349
+ // A newer status read still must not hide the connect failure before it.
350
+ const error =
351
+ flow.errorKind === "status-read" ? flow.terminalError : flow.error;
347
352
  useEffect(() => {
348
353
  const attempt = connectAttemptRef.current;
349
354
  if (!attempt) return;
@@ -12,6 +12,7 @@ import {
12
12
  } from "@agent-native/core/client/agent-chat";
13
13
  import { useVoiceProviderStatus } from "@agent-native/core/client/agent-chat";
14
14
  import { SIDEBAR_STATE_CHANGE_EVENT } from "@agent-native/core/client/agent-chat";
15
+ import { trackEvent } from "@agent-native/core/client/analytics";
15
16
  import {
16
17
  appPath,
17
18
  frameworkRoutePrefix,
@@ -103,6 +104,7 @@ export const coreComposerAdapters: CoreComposerRuntimeAdapters = {
103
104
  }),
104
105
  subscribeSidebarState,
105
106
  applyContextReplacements: applyVoiceContextReplacements,
107
+ trackEvent,
106
108
  },
107
109
  };
108
110
 
@@ -0,0 +1,121 @@
1
+ import type {
2
+ AgentConnectionRequest,
3
+ AgentMessage,
4
+ } from "@agent-native/agentkit/protocol";
5
+ import { describe, expect, it } from "vitest";
6
+
7
+ import {
8
+ latestReplyContext,
9
+ pickReplyConnectionSuggestion,
10
+ type LatestReplyContext,
11
+ } from "./reply-connection-suggestion.js";
12
+
13
+ function message(id: string, role: "user" | "assistant", text: string) {
14
+ return {
15
+ id,
16
+ role,
17
+ status: "complete",
18
+ parts: [{ type: "text", text }],
19
+ } as unknown as AgentMessage;
20
+ }
21
+
22
+ const slack = { id: "slack", provider: "slack", name: "Slack" };
23
+ const notion = { id: "notion", provider: "notion", name: "Notion" };
24
+ const find = (text: string) =>
25
+ /Slack/.test(text) ? slack : /Notion/.test(text) ? notion : null;
26
+
27
+ const latest: LatestReplyContext = {
28
+ isLatest: true,
29
+ userText: "Connect Slack",
30
+ agentRequestedProviders: "",
31
+ };
32
+
33
+ describe("latestReplyContext", () => {
34
+ const messages = [
35
+ message("u1", "user", "Connect Slack"),
36
+ message("a1", "assistant", "Working on it."),
37
+ message("u2", "user", "Connect Notion"),
38
+ message("a2", "assistant", "Still working."),
39
+ message("a3", "assistant", "Done."),
40
+ ];
41
+
42
+ it("offers a connection only on the thread's newest message", () => {
43
+ const thread = { messages, connectionRequests: {} };
44
+ expect(latestReplyContext(thread, "a1").isLatest).toBe(false);
45
+ expect(latestReplyContext(thread, "a2").isLatest).toBe(false);
46
+ expect(latestReplyContext(thread, "a3")).toMatchObject({
47
+ isLatest: true,
48
+ userText: "Connect Notion",
49
+ });
50
+ });
51
+
52
+ it("lists every provider the agent asked for, settled or not", () => {
53
+ const request = (
54
+ provider: string,
55
+ status: AgentConnectionRequest["status"],
56
+ ) => ({ id: provider, provider, reason: "missing", status }) as const;
57
+ const context = latestReplyContext(
58
+ {
59
+ messages,
60
+ connectionRequests: {
61
+ one: request("Slack", "requested"),
62
+ two: request("notion", "connected"),
63
+ three: request("linear", "declined"),
64
+ } as Record<string, AgentConnectionRequest>,
65
+ },
66
+ "a3",
67
+ );
68
+ expect(context.agentRequestedProviders).toBe("linear\nnotion\nslack");
69
+ });
70
+ });
71
+
72
+ describe("pickReplyConnectionSuggestion", () => {
73
+ const pick = (
74
+ context: LatestReplyContext,
75
+ replyText: string,
76
+ replyFinished: boolean,
77
+ ) =>
78
+ pickReplyConnectionSuggestion({ context, replyText, replyFinished, find });
79
+
80
+ it("offers nothing until the reply finishes", () => {
81
+ expect(pick(latest, "Connect Notion there.", false)).toBeNull();
82
+ expect(pick(latest, "", true)).toBe(slack);
83
+ });
84
+
85
+ it("never offers anything on an older reply", () => {
86
+ expect(
87
+ pick({ ...latest, isLatest: false }, "Connect Notion.", true),
88
+ ).toBeNull();
89
+ });
90
+
91
+ it("prefers the finished reply's ask over the sent request", () => {
92
+ expect(pick(latest, "Connect Notion to file it.", true)).toBe(notion);
93
+ expect(pick(latest, "Posted it.", true)).toBe(slack);
94
+ });
95
+
96
+ it("matches the agent's request by brand name, not only catalog id", () => {
97
+ const jira = { id: "atlassian", provider: "atlassian", name: "Jira" };
98
+ expect(
99
+ pickReplyConnectionSuggestion({
100
+ context: {
101
+ ...latest,
102
+ userText: "Connect Jira",
103
+ agentRequestedProviders: "jira",
104
+ },
105
+ replyText: "",
106
+ replyFinished: true,
107
+ find: () => jira,
108
+ }),
109
+ ).toBeNull();
110
+ });
111
+
112
+ it("never duplicates the agent's own connection request card", () => {
113
+ expect(
114
+ pick(
115
+ { ...latest, agentRequestedProviders: "slack" },
116
+ "Connect Slack.",
117
+ true,
118
+ ),
119
+ ).toBeNull();
120
+ });
121
+ });
@@ -0,0 +1,76 @@
1
+ import type { AgentThreadState } from "@agent-native/agentkit";
2
+ import { splitAgentChatContextFromMessage } from "@agent-native/core/shared";
3
+
4
+ export interface LatestReplyContext {
5
+ /** Only the thread's newest message offers a connection. */
6
+ isLatest: boolean;
7
+ /** The user message it replies to; a connect started here resumes it. */
8
+ userText: string;
9
+ /** Providers the agent has asked to connect in this thread, one per line. */
10
+ agentRequestedProviders: string;
11
+ }
12
+
13
+ /**
14
+ * Primitives only: a thread selector compares this on every streamed delta.
15
+ */
16
+ export function latestReplyContext(
17
+ thread: Pick<AgentThreadState, "messages" | "connectionRequests">,
18
+ messageId: string,
19
+ ): LatestReplyContext {
20
+ if (thread.messages.at(-1)?.id !== messageId) {
21
+ return { isLatest: false, userText: "", agentRequestedProviders: "" };
22
+ }
23
+ const user = thread.messages.findLast((message) => message.role === "user");
24
+ const userText = (user?.parts ?? [])
25
+ .flatMap((part) =>
26
+ part.type === "text"
27
+ ? [splitAgentChatContextFromMessage(part.text).message]
28
+ : [],
29
+ )
30
+ .join("\n");
31
+ // Settled requests count too: one connected through a workspace connection
32
+ // or declined must not come back as an MCP card.
33
+ const agentRequestedProviders = [
34
+ ...new Set(
35
+ Object.values(thread.connectionRequests).map((request) =>
36
+ request.provider.trim().toLowerCase(),
37
+ ),
38
+ ),
39
+ ]
40
+ .sort()
41
+ .join("\n");
42
+ return { isLatest: true, userText, agentRequestedProviders };
43
+ }
44
+
45
+ /**
46
+ * One card, on the newest reply once it finishes: the reply's own ask, else
47
+ * what the user asked to connect. Never mid-run: a connect resumes the user's
48
+ * prompt, which would send it twice. Never beside the agent's own request card.
49
+ */
50
+ export function pickReplyConnectionSuggestion<
51
+ T extends { id: string; provider: string; name: string },
52
+ >({
53
+ context,
54
+ replyText,
55
+ replyFinished,
56
+ find,
57
+ }: {
58
+ context: LatestReplyContext;
59
+ replyText: string;
60
+ replyFinished: boolean;
61
+ find: (text: string) => T | null;
62
+ }): T | null {
63
+ if (!context.isLatest || !replyFinished) return null;
64
+ const agentRequested = new Set(
65
+ context.agentRequestedProviders.split("\n").filter(Boolean),
66
+ );
67
+ const offered = (integration: T | null) =>
68
+ integration &&
69
+ !agentRequested.has(integration.id.toLowerCase()) &&
70
+ !agentRequested.has(integration.provider.toLowerCase()) &&
71
+ // A Jira request names the brand; the catalog id is "atlassian".
72
+ !agentRequested.has(integration.name.toLowerCase())
73
+ ? integration
74
+ : null;
75
+ return offered(find(replyText)) ?? offered(find(context.userText));
76
+ }
@@ -130,6 +130,8 @@ const messages: ToolkitAgentChatTranslation = {
130
130
  "onboarding.roleOther": "أخرى",
131
131
  "onboarding.roleOtherInputLabel": "صف دورك",
132
132
  "onboarding.skipForNow": "تخطي الآن",
133
+ "onboarding.builderProvisionFailedDetail":
134
+ "تعذّر إنشاء حساب Builder.io الخاص بك. حاول مرة أخرى أو سجّل الدخول بحساب موجود.",
133
135
  "onboarding.saveRoleError": "تعذر حفظ دورك.",
134
136
  "onboarding.builderCreateAccount": "استخدم Builder.io",
135
137
  "onboarding.builderSignInWithAccount": "سجّل الدخول بحساب Builder.io",
@@ -186,6 +188,7 @@ const messages: ToolkitAgentChatTranslation = {
186
188
  "onboarding.creditsSkipGoBack": "رجوع",
187
189
  "onboarding.creditsSkipAnyway": "تخطي على أي حال",
188
190
  "onboarding.creditsUseCustomKeys": "استخدام مفاتيحك الخاصة",
191
+ "onboarding.creditsUseOwnApiKeys": "استخدم مفاتيح API الخاصة بي",
189
192
  "onboarding.creditsAboutLabel": "حول الأرصدة المجانية",
190
193
  "onboarding.creditsActivating": "جارٍ تفعيل الأرصدة المجانية",
191
194
  "onboarding.creditsActivatingTooltip":
@@ -411,6 +414,9 @@ const messages: ToolkitAgentChatTranslation = {
411
414
  "تعذّرت إضافة الملف الذي تم إفلاته. جرّب تنسيقًا آخر.",
412
415
  "composer.openDesktop": "افتح تطبيق سطح المكتب لاستخدام هذه المحادثة.",
413
416
  "composer.removeAttachment": "إزالة {{name}}",
417
+ "composer.attachmentReadFailed": "تعذّرت قراءة هذا الملف",
418
+ "composer.attachmentTooLarge": "حجم الملف أكبر من 8 ميغابايت",
419
+ "composer.attachmentNotUtf8": "الملف ليس نصًا بترميز UTF-8",
414
420
  "composer.scrollToBottom": "التمرير إلى الأسفل",
415
421
  "composer.suggestedPrompts": "اقتراحات المطالبات",
416
422
  "composer.stopResponse": "إيقاف الرد",
@@ -533,6 +539,10 @@ const messages: ToolkitAgentChatTranslation = {
533
539
  "composer.skill.uploadFile": "رفع ملف مهارة",
534
540
  "composer.upload": "رفع",
535
541
  "composer.uploadFailed": "تعذّر رفع الملف المحدد.",
542
+ "composer.imageTooLargeToAttach":
543
+ '"{{name}}" بحجم {{size}} ميغابايت، ولا يمكن إرفاق الصور التي يزيد حجمها على {{limit}} ميغابايت. يُرجى استخدام صورة أصغر.',
544
+ "composer.imageTooManyPixelsToAttach":
545
+ '"{{name}}" بدقة {{megapixels}} ميغابكسل، ولا يمكن إرفاق الصور التي تزيد على {{limit}} ميغابكسل. يُرجى استخدام صورة أصغر.',
536
546
  "composer.fileTooLarge":
537
547
  "هذا الملف أكبر من حد الرفع البالغ {{size}} ميغابايت.",
538
548
  "composer.sessionExpired":
@@ -136,6 +136,8 @@ const messages: ToolkitAgentChatTranslation = {
136
136
  "onboarding.roleOther": "Andere",
137
137
  "onboarding.roleOtherInputLabel": "Beschreibe deine Rolle",
138
138
  "onboarding.skipForNow": "Vorerst überspringen",
139
+ "onboarding.builderProvisionFailedDetail":
140
+ "Dein Builder.io-Konto konnte nicht erstellt werden. Versuche es erneut oder melde dich mit einem bestehenden Konto an.",
139
141
  "onboarding.saveRoleError": "Deine Rolle konnte nicht gespeichert werden.",
140
142
  "onboarding.builderCreateAccount": "Builder.io verwenden",
141
143
  "onboarding.builderSignInWithAccount": "Mit einem Builder.io-Konto anmelden",
@@ -198,6 +200,7 @@ const messages: ToolkitAgentChatTranslation = {
198
200
  "onboarding.creditsSkipGoBack": "Zurück",
199
201
  "onboarding.creditsSkipAnyway": "Trotzdem überspringen",
200
202
  "onboarding.creditsUseCustomKeys": "Eigene Schlüssel verwenden",
203
+ "onboarding.creditsUseOwnApiKeys": "Meine eigenen API-Schlüssel verwenden",
201
204
  "onboarding.creditsAboutLabel": "Über kostenlose Credits",
202
205
  "onboarding.creditsActivating": "Gratis-Credits werden aktiviert",
203
206
  "onboarding.creditsActivatingTooltip":
@@ -438,6 +441,9 @@ const messages: ToolkitAgentChatTranslation = {
438
441
  "Die abgelegte Datei konnte nicht hinzugefügt werden. Versuche ein anderes Format.",
439
442
  "composer.openDesktop": "Öffne Desktop, um diesen Chat zu verwenden.",
440
443
  "composer.removeAttachment": "{{name}} entfernen",
444
+ "composer.attachmentReadFailed": "Datei konnte nicht gelesen werden",
445
+ "composer.attachmentTooLarge": "Datei ist größer als 8 MB",
446
+ "composer.attachmentNotUtf8": "Datei ist kein UTF-8-Text",
441
447
  "composer.scrollToBottom": "Nach unten scrollen",
442
448
  "composer.suggestedPrompts": "Vorgeschlagene Prompts",
443
449
  "composer.stopResponse": "Antwort stoppen",
@@ -1257,6 +1263,10 @@ const messages: ToolkitAgentChatTranslation = {
1257
1263
  "composer.upload": "Hochladen",
1258
1264
  "composer.uploadFailed":
1259
1265
  "Die ausgewählte Datei konnte nicht hochgeladen werden.",
1266
+ "composer.imageTooLargeToAttach":
1267
+ '"{{name}}" ist {{size}} MB groß - Bilder über {{limit}} MB können nicht angehängt werden. Bitte verwende ein kleineres Bild.',
1268
+ "composer.imageTooManyPixelsToAttach":
1269
+ '"{{name}}" hat {{megapixels}} Megapixel - Bilder über {{limit}} Megapixel können nicht angehängt werden. Bitte verwende ein kleineres Bild.',
1260
1270
  "composer.fileTooLarge":
1261
1271
  "Diese Datei ist größer als das Upload-Limit von {{size}} MB.",
1262
1272
  "composer.sessionExpired":