@agent-native/toolkit 0.201.1 → 0.202.0-nightly-20261006033736

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 (229) hide show
  1. package/agent-native.eject.json +39 -12
  2. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  3. package/dist/app/agentkit/react/components.js +292 -23
  4. package/dist/app/agentkit/react/components.js.map +1 -1
  5. package/dist/app/agentkit/react/context.d.ts +5 -0
  6. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  7. package/dist/app/agentkit/react/context.js +5 -0
  8. package/dist/app/agentkit/react/context.js.map +1 -1
  9. package/dist/app/agentkit/react/styles.css +78 -3
  10. package/dist/app/auth/AuthPage.d.ts.map +1 -1
  11. package/dist/app/auth/AuthPage.js +7 -14
  12. package/dist/app/auth/AuthPage.js.map +1 -1
  13. package/dist/app/auth/server.d.ts +6 -0
  14. package/dist/app/auth/server.d.ts.map +1 -0
  15. package/dist/app/auth/server.js +19 -0
  16. package/dist/app/auth/server.js.map +1 -0
  17. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  18. package/dist/app/chat/AgentKitAssistantChat.js +164 -83
  19. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  20. package/dist/app/chat/AgentSidebar.d.ts +2 -1
  21. package/dist/app/chat/AgentSidebar.d.ts.map +1 -1
  22. package/dist/app/chat/AgentSidebar.js +2 -2
  23. package/dist/app/chat/AgentSidebar.js.map +1 -1
  24. package/dist/app/chat/agentkit-chat/guided-questions.d.ts.map +1 -1
  25. package/dist/app/chat/agentkit-chat/guided-questions.js +13 -3
  26. package/dist/app/chat/agentkit-chat/guided-questions.js.map +1 -1
  27. package/dist/app/chat/chat/surface-types.d.ts +2 -0
  28. package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
  29. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  30. package/dist/app/i18n/catalogs/ar-SA.js +41 -0
  31. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  32. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  33. package/dist/app/i18n/catalogs/de-DE.js +41 -0
  34. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  35. package/dist/app/i18n/catalogs/en-US.d.ts +41 -0
  36. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  37. package/dist/app/i18n/catalogs/en-US.js +41 -0
  38. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  39. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  40. package/dist/app/i18n/catalogs/es-ES.js +41 -0
  41. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  42. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  43. package/dist/app/i18n/catalogs/fr-FR.js +41 -0
  44. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  45. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  46. package/dist/app/i18n/catalogs/hi-IN.js +41 -0
  47. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  48. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  49. package/dist/app/i18n/catalogs/ja-JP.js +41 -0
  50. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  51. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  52. package/dist/app/i18n/catalogs/ko-KR.js +41 -0
  53. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  54. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  55. package/dist/app/i18n/catalogs/pt-BR.js +41 -0
  56. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  57. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  58. package/dist/app/i18n/catalogs/zh-CN.js +41 -0
  59. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  60. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  61. package/dist/app/i18n/catalogs/zh-TW.js +41 -0
  62. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  63. package/dist/app/shared/StarfieldBackground.d.ts +1 -6
  64. package/dist/app/shared/StarfieldBackground.d.ts.map +1 -1
  65. package/dist/app/shared/StarfieldBackground.js +1 -368
  66. package/dist/app/shared/StarfieldBackground.js.map +1 -1
  67. package/dist/app/shared/WaveBackground.d.ts +5 -0
  68. package/dist/app/shared/WaveBackground.d.ts.map +1 -0
  69. package/dist/app/shared/WaveBackground.js +34 -0
  70. package/dist/app/shared/WaveBackground.js.map +1 -0
  71. package/dist/app/shared/WebGlWaveBackground.d.ts +9 -0
  72. package/dist/app/shared/WebGlWaveBackground.d.ts.map +1 -0
  73. package/dist/app/shared/WebGlWaveBackground.js +433 -0
  74. package/dist/app/shared/WebGlWaveBackground.js.map +1 -0
  75. package/dist/app/shared/index.d.ts +1 -0
  76. package/dist/app/shared/index.d.ts.map +1 -1
  77. package/dist/app/shared/index.js +1 -0
  78. package/dist/app/shared/index.js.map +1 -1
  79. package/dist/app/shared/ocean/bloom-blur.wgsl +43 -0
  80. package/dist/app/shared/ocean/bloom-blur.wgsl.js +1 -0
  81. package/dist/app/shared/ocean/bloom-bright.wgsl +21 -0
  82. package/dist/app/shared/ocean/bloom-bright.wgsl.js +1 -0
  83. package/dist/app/shared/ocean/bloom-composite.wgsl +40 -0
  84. package/dist/app/shared/ocean/bloom-composite.wgsl.js +1 -0
  85. package/dist/app/shared/ocean/brand-colors.d.ts +9 -0
  86. package/dist/app/shared/ocean/brand-colors.d.ts.map +1 -0
  87. package/dist/app/shared/ocean/brand-colors.js +45 -0
  88. package/dist/app/shared/ocean/brand-colors.js.map +1 -0
  89. package/dist/app/shared/ocean/camera.d.ts +5 -0
  90. package/dist/app/shared/ocean/camera.d.ts.map +1 -0
  91. package/dist/app/shared/ocean/camera.js +24 -0
  92. package/dist/app/shared/ocean/camera.js.map +1 -0
  93. package/dist/app/shared/ocean/hero-ocean-background.d.ts +8 -0
  94. package/dist/app/shared/ocean/hero-ocean-background.d.ts.map +1 -0
  95. package/dist/app/shared/ocean/hero-ocean-background.js +186 -0
  96. package/dist/app/shared/ocean/hero-ocean-background.js.map +1 -0
  97. package/dist/app/shared/ocean/ifft-stage.wgsl +36 -0
  98. package/dist/app/shared/ocean/ifft-stage.wgsl.js +1 -0
  99. package/dist/app/shared/ocean/initial-spectrum.wgsl +36 -0
  100. package/dist/app/shared/ocean/initial-spectrum.wgsl.js +1 -0
  101. package/dist/app/shared/ocean/noise.wgsl +24 -0
  102. package/dist/app/shared/ocean/noise.wgsl.js +1 -0
  103. package/dist/app/shared/ocean/normal-foam.wgsl +32 -0
  104. package/dist/app/shared/ocean/normal-foam.wgsl.js +1 -0
  105. package/dist/app/shared/ocean/ocean-colors.d.ts +6 -0
  106. package/dist/app/shared/ocean/ocean-colors.d.ts.map +1 -0
  107. package/dist/app/shared/ocean/ocean-colors.js +6 -0
  108. package/dist/app/shared/ocean/ocean-colors.js.map +1 -0
  109. package/dist/app/shared/ocean/ocean-common.wgsl +15 -0
  110. package/dist/app/shared/ocean/ocean-common.wgsl.js +1 -0
  111. package/dist/app/shared/ocean/ocean-graph.d.ts +12 -0
  112. package/dist/app/shared/ocean/ocean-graph.d.ts.map +1 -0
  113. package/dist/app/shared/ocean/ocean-graph.js +16 -0
  114. package/dist/app/shared/ocean/ocean-graph.js.map +1 -0
  115. package/dist/app/shared/ocean/particles.wgsl +139 -0
  116. package/dist/app/shared/ocean/particles.wgsl.js +1 -0
  117. package/dist/app/shared/ocean/present.wgsl +40 -0
  118. package/dist/app/shared/ocean/present.wgsl.js +1 -0
  119. package/dist/app/shared/ocean/renderer.d.ts +66 -0
  120. package/dist/app/shared/ocean/renderer.d.ts.map +1 -0
  121. package/dist/app/shared/ocean/renderer.js +535 -0
  122. package/dist/app/shared/ocean/renderer.js.map +1 -0
  123. package/dist/app/shared/ocean/spectrum.wgsl +35 -0
  124. package/dist/app/shared/ocean/spectrum.wgsl.js +1 -0
  125. package/dist/app/shared/ocean/tuning.d.ts +48 -0
  126. package/dist/app/shared/ocean/tuning.d.ts.map +1 -0
  127. package/dist/app/shared/ocean/tuning.js +74 -0
  128. package/dist/app/shared/ocean/tuning.js.map +1 -0
  129. package/dist/app/shared/ocean/webgpu-support.d.ts +3 -0
  130. package/dist/app/shared/ocean/webgpu-support.d.ts.map +1 -0
  131. package/dist/app/shared/ocean/webgpu-support.js +13 -0
  132. package/dist/app/shared/ocean/webgpu-support.js.map +1 -0
  133. package/dist/app/sharing/AccessRequestApprovalPage.d.ts +23 -0
  134. package/dist/app/sharing/AccessRequestApprovalPage.d.ts.map +1 -0
  135. package/dist/app/sharing/AccessRequestApprovalPage.js +95 -0
  136. package/dist/app/sharing/AccessRequestApprovalPage.js.map +1 -0
  137. package/dist/app/sharing/AccessRequestsSection.d.ts +5 -0
  138. package/dist/app/sharing/AccessRequestsSection.d.ts.map +1 -0
  139. package/dist/app/sharing/AccessRequestsSection.js +47 -0
  140. package/dist/app/sharing/AccessRequestsSection.js.map +1 -0
  141. package/dist/app/sharing/ResourceAccessScreen.d.ts +53 -0
  142. package/dist/app/sharing/ResourceAccessScreen.d.ts.map +1 -0
  143. package/dist/app/sharing/ResourceAccessScreen.js +132 -0
  144. package/dist/app/sharing/ResourceAccessScreen.js.map +1 -0
  145. package/dist/app/sharing/ShareButton.d.ts.map +1 -1
  146. package/dist/app/sharing/ShareButton.js +4 -2
  147. package/dist/app/sharing/ShareButton.js.map +1 -1
  148. package/dist/app/sharing/ShareDialog.d.ts.map +1 -1
  149. package/dist/app/sharing/ShareDialog.js +7 -5
  150. package/dist/app/sharing/ShareDialog.js.map +1 -1
  151. package/dist/app/sharing/index.d.ts +2 -0
  152. package/dist/app/sharing/index.d.ts.map +1 -1
  153. package/dist/app/sharing/index.js +2 -0
  154. package/dist/app/sharing/index.js.map +1 -1
  155. package/dist/app/styles/agent-native.css +21 -1
  156. package/dist/app/styles/tokens/agent-kit.css +3 -1
  157. package/dist/composer/AgentSuggestionBar.d.ts +1 -1
  158. package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
  159. package/dist/composer/AgentSuggestionBar.js +75 -6
  160. package/dist/composer/AgentSuggestionBar.js.map +1 -1
  161. package/package.json +14 -4
  162. package/src/app/agentkit/react/components.tsx +492 -60
  163. package/src/app/agentkit/react/context.tsx +10 -0
  164. package/src/app/agentkit/react/lifecycle.spec.tsx +487 -1
  165. package/src/app/agentkit/react/styles.css +78 -3
  166. package/src/app/auth/AuthPage.spec.tsx +11 -7
  167. package/src/app/auth/AuthPage.tsx +16 -35
  168. package/src/app/auth/server.spec.ts +68 -0
  169. package/src/app/auth/server.ts +29 -0
  170. package/src/app/chat/AgentKitAssistantChat.spec.tsx +287 -290
  171. package/src/app/chat/AgentKitAssistantChat.tsx +219 -116
  172. package/src/app/chat/AgentSidebar.tsx +3 -0
  173. package/src/app/chat/agentkit-chat/guided-questions.flow.spec.tsx +85 -0
  174. package/src/app/chat/agentkit-chat/guided-questions.tsx +12 -5
  175. package/src/app/chat/chat/surface-types.ts +2 -0
  176. package/src/app/i18n/catalogs/ar-SA.ts +44 -0
  177. package/src/app/i18n/catalogs/de-DE.ts +55 -0
  178. package/src/app/i18n/catalogs/en-US.ts +46 -0
  179. package/src/app/i18n/catalogs/es-ES.ts +53 -0
  180. package/src/app/i18n/catalogs/fr-FR.ts +53 -0
  181. package/src/app/i18n/catalogs/hi-IN.ts +47 -0
  182. package/src/app/i18n/catalogs/ja-JP.ts +54 -0
  183. package/src/app/i18n/catalogs/ko-KR.ts +50 -0
  184. package/src/app/i18n/catalogs/pt-BR.ts +52 -0
  185. package/src/app/i18n/catalogs/zh-CN.ts +42 -0
  186. package/src/app/i18n/catalogs/zh-TW.ts +43 -0
  187. package/src/app/shared/StarfieldBackground.tsx +4 -423
  188. package/src/app/shared/WaveBackground.spec.tsx +104 -0
  189. package/src/app/shared/WaveBackground.tsx +60 -0
  190. package/src/app/shared/WebGlWaveBackground.spec.tsx +106 -0
  191. package/src/app/shared/WebGlWaveBackground.tsx +499 -0
  192. package/src/app/shared/index.ts +1 -0
  193. package/src/app/shared/ocean/bloom-blur.wgsl +43 -0
  194. package/src/app/shared/ocean/bloom-bright.wgsl +21 -0
  195. package/src/app/shared/ocean/bloom-composite.wgsl +40 -0
  196. package/src/app/shared/ocean/brand-colors.ts +49 -0
  197. package/src/app/shared/ocean/camera.ts +28 -0
  198. package/src/app/shared/ocean/hero-ocean-background.spec.tsx +369 -0
  199. package/src/app/shared/ocean/hero-ocean-background.tsx +238 -0
  200. package/src/app/shared/ocean/ifft-stage.wgsl +36 -0
  201. package/src/app/shared/ocean/initial-spectrum.wgsl +36 -0
  202. package/src/app/shared/ocean/noise.wgsl +24 -0
  203. package/src/app/shared/ocean/normal-foam.wgsl +32 -0
  204. package/src/app/shared/ocean/ocean-colors.ts +11 -0
  205. package/src/app/shared/ocean/ocean-common.wgsl +15 -0
  206. package/src/app/shared/ocean/ocean-graph.ts +29 -0
  207. package/src/app/shared/ocean/particles.wgsl +139 -0
  208. package/src/app/shared/ocean/present.wgsl +40 -0
  209. package/src/app/shared/ocean/renderer.spec.ts +100 -0
  210. package/src/app/shared/ocean/renderer.ts +693 -0
  211. package/src/app/shared/ocean/spectrum.wgsl +35 -0
  212. package/src/app/shared/ocean/tuning.ts +131 -0
  213. package/src/app/shared/ocean/webgpu-support.ts +12 -0
  214. package/src/app/sharing/AccessRequestApprovalPage.spec.tsx +276 -0
  215. package/src/app/sharing/AccessRequestApprovalPage.tsx +307 -0
  216. package/src/app/sharing/AccessRequestsSection.tsx +163 -0
  217. package/src/app/sharing/ResourceAccessScreen.spec.tsx +235 -0
  218. package/src/app/sharing/ResourceAccessScreen.tsx +331 -0
  219. package/src/app/sharing/ShareButton.spec.tsx +171 -5
  220. package/src/app/sharing/ShareButton.tsx +15 -2
  221. package/src/app/sharing/ShareDialog.spec.tsx +71 -2
  222. package/src/app/sharing/ShareDialog.tsx +24 -2
  223. package/src/app/sharing/index.ts +2 -0
  224. package/src/app/styles/agent-native.css +21 -1
  225. package/src/app/styles/agent-native.spec.ts +16 -3
  226. package/src/app/styles/tokens/agent-kit.css +3 -1
  227. package/src/composer/AgentSuggestionBar.overflow.spec.tsx +277 -0
  228. package/src/composer/AgentSuggestionBar.tsx +113 -8
  229. package/src/wgsl-env.d.ts +6 -0
@@ -53,6 +53,7 @@ const chatMocks = vi.hoisted(() => ({
53
53
  thinkingDisplay: null as any,
54
54
  requestComposerFocus: vi.fn(),
55
55
  readiness: { canChat: true, missing: false, state: "configured" },
56
+ fetchProviderState: vi.fn(async () => chatMocks.readiness.state),
56
57
  fileUploadStatus: {
57
58
  data: { configured: true },
58
59
  isError: false,
@@ -207,9 +208,13 @@ vi.mock("../agentkit/react/index.js", async () => {
207
208
  if (chatMocks.realComposerController) {
208
209
  return React.createElement(AgentKitComposer, props);
209
210
  }
210
- return React.createElement("div", {
211
- "data-testid": "agentkit-composer",
212
- });
211
+ return React.createElement(
212
+ "div",
213
+ {
214
+ "data-testid": "agentkit-composer",
215
+ },
216
+ props.extraActionButton,
217
+ );
213
218
  },
214
219
  AgentApprovalPrompt: () => null,
215
220
  AgentMessageView: ({ value }: any) => {
@@ -352,6 +357,7 @@ vi.mock("@tabler/icons-react", async (importOriginal) => ({
352
357
  "IconAlertTriangle",
353
358
  "IconCheck",
354
359
  "IconChevronDown",
360
+ "IconLoader2",
355
361
  "IconMessage",
356
362
  "IconPlayerStopFilled",
357
363
  "IconQuote",
@@ -479,6 +485,7 @@ vi.mock("@agent-native/core/client/agent-chat", async (importOriginal) => {
479
485
  ExternalAgentNudge: () => null,
480
486
  useDevMode: () => ({ isDevMode: true }),
481
487
  useAgentEngineConfigured: () => chatMocks.readiness,
488
+ fetchAgentEngineConfiguredState: chatMocks.fetchProviderState,
482
489
  filterAgentChatContextItems: (items: unknown[]) => items,
483
490
  formatAgentChatContextItemsForPrompt:
484
491
  actual.formatAgentChatContextItemsForPrompt,
@@ -753,6 +760,9 @@ beforeEach(() => {
753
760
  missing: false,
754
761
  state: "configured",
755
762
  };
763
+ chatMocks.fetchProviderState
764
+ .mockReset()
765
+ .mockImplementation(async () => chatMocks.readiness.state);
756
766
  chatMocks.fileUploadStatus = {
757
767
  data: { configured: true },
758
768
  isError: false,
@@ -1872,7 +1882,7 @@ describe("AgentKitAssistantChat host behavior", () => {
1872
1882
  expect(chatMocks.composerProps.modelStatusChecksEnabled).toBe(false);
1873
1883
  });
1874
1884
 
1875
- it("shows a model catalog retry instead of missing-provider setup", async () => {
1885
+ it("shows missing-provider setup when the model catalog is unavailable", async () => {
1876
1886
  const onRetryModelList = vi.fn();
1877
1887
  chatMocks.readiness = {
1878
1888
  canChat: false,
@@ -1887,6 +1897,30 @@ describe("AgentKitAssistantChat host behavior", () => {
1887
1897
  }),
1888
1898
  );
1889
1899
 
1900
+ expect(chatMocks.setupCardProps).toMatchObject({ attached: true });
1901
+ expect(chatMocks.providerGateProps).toBeNull();
1902
+ expect(container.textContent).not.toContain(
1903
+ "agentChat.setup.modelListUnavailable",
1904
+ );
1905
+
1906
+ expect(onRetryModelList).not.toHaveBeenCalled();
1907
+ });
1908
+
1909
+ it("offers a model catalog retry when AI is configured", async () => {
1910
+ const onRetryModelList = vi.fn();
1911
+ chatMocks.readiness = {
1912
+ canChat: true,
1913
+ missing: false,
1914
+ state: "configured",
1915
+ };
1916
+ await mount(
1917
+ baseProps({
1918
+ providerStatusChecksEnabled: true,
1919
+ modelListError: true,
1920
+ onRetryModelList,
1921
+ }),
1922
+ );
1923
+
1890
1924
  expect(chatMocks.setupCardProps).toBeNull();
1891
1925
  expect(chatMocks.providerGateProps).toMatchObject({
1892
1926
  modelListUnavailable: true,
@@ -1905,224 +1939,291 @@ describe("AgentKitAssistantChat host behavior", () => {
1905
1939
  dispatchEvent.mockRestore();
1906
1940
  });
1907
1941
 
1908
- it("keeps the composer editable while provider readiness is checked", async () => {
1942
+ it("keeps typing available and shows a busy send state during fresh readiness checks", async () => {
1909
1943
  chatMocks.readiness = {
1910
1944
  canChat: false,
1911
1945
  missing: false,
1912
1946
  state: "unknown",
1913
1947
  };
1948
+ let resolveReadiness!: (state: "configured" | "missing") => void;
1949
+ const pendingReadiness = new Promise<"configured" | "missing">(
1950
+ (resolve) => {
1951
+ resolveReadiness = resolve;
1952
+ },
1953
+ );
1954
+ chatMocks.fetchProviderState.mockReturnValueOnce(pendingReadiness);
1914
1955
  await mount(baseProps({ providerStatusChecksEnabled: true }));
1915
1956
 
1916
1957
  expect(chatMocks.composerProps.disabled).toBe(false);
1917
1958
  expect(chatMocks.composerProps.submissionDisabled).toBe(false);
1918
1959
  expect(chatMocks.composerProps.requireAgentEngine).toBe(false);
1919
- await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(true);
1920
- expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
1921
- });
1960
+ await act(async () => {
1961
+ chatMocks.composerProps.onTextChange("Draft while checking");
1962
+ });
1922
1963
 
1923
- it("queues composer sends until provider readiness resolves", async () => {
1924
- chatMocks.readiness = {
1925
- canChat: false,
1926
- missing: false,
1927
- state: "unknown",
1928
- };
1929
- await mount(baseProps({ providerStatusChecksEnabled: true }));
1930
- await flush();
1964
+ let preflight!: Promise<boolean>;
1965
+ await act(async () => {
1966
+ preflight = chatMocks.composerProps.onBeforeSubmit();
1967
+ chatMocks.composerProps.onSubmissionPendingChange(true);
1968
+ await Promise.resolve();
1969
+ });
1970
+ expect(chatMocks.fetchProviderState).toHaveBeenCalledOnce();
1971
+ expect(chatMocks.fetchProviderState).toHaveBeenCalledWith(true, {
1972
+ fresh: true,
1973
+ });
1974
+ expect(
1975
+ container.querySelector('[data-testid="provider-preflight-pending"]'),
1976
+ ).not.toBeNull();
1977
+ expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
1931
1978
 
1932
1979
  await act(async () => {
1933
- await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(
1934
- true,
1935
- );
1980
+ resolveReadiness("configured");
1981
+ await expect(preflight).resolves.toBe(true);
1982
+ chatMocks.composerProps.onSubmissionPendingChange(false);
1983
+ });
1984
+ await act(async () => {
1936
1985
  await chatMocks.composerProps.onSubmit(
1937
- "Send after provider discovery",
1986
+ "Draft while checking",
1938
1987
  [],
1939
1988
  [],
1940
1989
  {},
1941
1990
  );
1942
1991
  });
1943
1992
 
1944
- expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
1945
- const stateKey = [...chatMocks.appState.keys()].find((key) =>
1946
- key.startsWith("agentkit-deferred-provider-submissions:"),
1993
+ expect(
1994
+ container.querySelector('[data-testid="provider-preflight-pending"]'),
1995
+ ).toBeNull();
1996
+ expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
1997
+ expect(chatMocks.control.sendMessage.mock.calls[0]?.[0]?.text).toBe(
1998
+ "Draft while checking",
1947
1999
  );
1948
- expect(stateKey).toBeDefined();
1949
- expect(chatMocks.appState.get(stateKey!)).toMatchObject({
1950
- submissions: [{ text: "Send after provider discovery" }],
2000
+ expect(
2001
+ [...chatMocks.appState.keys()].some((key) =>
2002
+ key.startsWith("agentkit-deferred-provider-submissions:"),
2003
+ ),
2004
+ ).toBe(false);
2005
+ });
2006
+
2007
+ it("blocks stale configured readiness and retains the draft when fresh status is missing", async () => {
2008
+ chatMocks.readiness = {
2009
+ canChat: true,
2010
+ missing: false,
2011
+ state: "configured",
2012
+ };
2013
+ chatMocks.fetchProviderState.mockResolvedValue("missing");
2014
+ await mount(baseProps({ providerStatusChecksEnabled: true }));
2015
+
2016
+ await act(async () => {
2017
+ chatMocks.composerProps.onTextChange("Keep this draft disconnected");
1951
2018
  });
2019
+ expect(chatMocks.composerProps.disabled).toBe(false);
1952
2020
 
1953
2021
  await act(async () => {
1954
- chatMocks.readiness = {
1955
- canChat: true,
1956
- missing: false,
1957
- state: "configured",
1958
- };
1959
- root.render(
1960
- <AgentKitAssistantChat
1961
- {...baseProps({ providerStatusChecksEnabled: true })}
1962
- />,
2022
+ await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(
2023
+ false,
1963
2024
  );
1964
2025
  });
1965
- await flush();
1966
2026
 
1967
- expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
1968
- expect(chatMocks.control.sendMessage.mock.calls[0]?.[0]?.text).toBe(
1969
- "Send after provider discovery",
2027
+ expect(chatMocks.composerProps.disabled).toBe(true);
2028
+ expect(chatMocks.composerProps.submissionDisabled).toBe(true);
2029
+ expect(chatMocks.setupCardProps).toMatchObject({ attached: true });
2030
+ expect(
2031
+ container.querySelector('[data-testid="builder-setup-card"]'),
2032
+ ).not.toBeNull();
2033
+ expect(chatMocks.composerDrafts.get("thread-1")).toBe(
2034
+ "Keep this draft disconnected",
1970
2035
  );
1971
- expect(chatMocks.appState.has(stateKey!)).toBe(false);
2036
+ expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
2037
+ expect(
2038
+ [...chatMocks.appState.keys()].some((key) =>
2039
+ key.startsWith("agentkit-deferred-provider-submissions:"),
2040
+ ),
2041
+ ).toBe(false);
1972
2042
  });
1973
2043
 
1974
- it("preserves queued intent when its run finishes during provider discovery", async () => {
2044
+ it("submits when the fresh result is configured even if passive readiness is unknown", async () => {
1975
2045
  chatMocks.readiness = {
1976
2046
  canChat: false,
1977
2047
  missing: false,
1978
2048
  state: "unknown",
1979
2049
  };
1980
- chatMocks.thread.activeRunIds = ["analytics-run"];
1981
- chatMocks.thread.runs = {
1982
- "analytics-run": {
1983
- id: "analytics-run",
1984
- status: "running",
1985
- lastSequence: 1,
1986
- },
1987
- };
2050
+ chatMocks.fetchProviderState.mockResolvedValue("configured");
1988
2051
  await mount(baseProps({ providerStatusChecksEnabled: true }));
1989
- await flush();
1990
2052
 
1991
2053
  await act(async () => {
1992
2054
  await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(
1993
2055
  true,
1994
2056
  );
2057
+ });
2058
+ await act(async () => {
1995
2059
  await chatMocks.composerProps.onSubmit(
1996
- "Follow up after Analytics Add Panel",
2060
+ "Send after discovery",
1997
2061
  [],
1998
2062
  [],
1999
- { intent: "queued" },
2000
- async () => ({}),
2063
+ {},
2001
2064
  );
2002
2065
  });
2003
2066
 
2004
- expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
2005
- expect(chatMocks.control.queueMessage).not.toHaveBeenCalled();
2006
-
2007
- const stateKey = [...chatMocks.appState.keys()].find((key) =>
2008
- key.startsWith("agentkit-deferred-provider-submissions:"),
2067
+ expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
2068
+ expect(chatMocks.control.sendMessage.mock.calls[0]?.[0]?.text).toBe(
2069
+ "Send after discovery",
2009
2070
  );
2010
- expect(chatMocks.appState.get(stateKey!)).toMatchObject({
2011
- submissions: [
2012
- {
2013
- composerOptions: {
2014
- intent: "queued",
2015
- queuedWhileRunActive: true,
2016
- },
2017
- },
2018
- ],
2071
+ expect(
2072
+ [...chatMocks.appState.keys()].some((key) =>
2073
+ key.startsWith("agentkit-deferred-provider-submissions:"),
2074
+ ),
2075
+ ).toBe(false);
2076
+ });
2077
+
2078
+ it("clears a stale missing submission result after passive readiness confirms reconnection", async () => {
2079
+ chatMocks.readiness = {
2080
+ canChat: false,
2081
+ missing: false,
2082
+ state: "unknown",
2083
+ };
2084
+ chatMocks.fetchProviderState.mockResolvedValue("missing");
2085
+ const props = baseProps({ providerStatusChecksEnabled: true });
2086
+ await mount(props);
2087
+
2088
+ await act(async () => {
2089
+ await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(
2090
+ false,
2091
+ );
2019
2092
  });
2093
+ expect(chatMocks.composerProps.disabled).toBe(true);
2094
+ expect(chatMocks.setupCardProps).not.toBeNull();
2020
2095
 
2021
- chatMocks.thread.activeRunIds = [];
2022
- chatMocks.thread.runs["analytics-run"].status = "completed";
2023
2096
  chatMocks.readiness = {
2024
2097
  canChat: true,
2025
2098
  missing: false,
2026
2099
  state: "configured",
2027
2100
  };
2028
2101
  await act(async () => {
2029
- root.render(
2030
- <AgentKitAssistantChat
2031
- {...baseProps({ providerStatusChecksEnabled: true })}
2032
- />,
2033
- );
2102
+ root.render(<AgentKitAssistantChat {...props} />);
2034
2103
  });
2035
- await flush();
2036
2104
 
2037
- expect(chatMocks.control.sendMessage).toHaveBeenCalledExactlyOnceWith(
2038
- expect.objectContaining({
2039
- text: "Follow up after Analytics Add Panel",
2040
- queuedWhileRunActive: true,
2041
- }),
2105
+ expect(chatMocks.composerProps.disabled).toBe(false);
2106
+ expect(chatMocks.composerProps.submissionDisabled).toBe(false);
2107
+ expect(container.querySelector('[data-testid="builder-setup-card"]')).toBe(
2108
+ null,
2042
2109
  );
2043
- expect(chatMocks.control.queueMessage).not.toHaveBeenCalled();
2044
- expect(chatMocks.appState.has(stateKey!)).toBe(false);
2045
2110
  });
2046
2111
 
2047
- it("keeps the draft rejected if provider status becomes missing before submit", async () => {
2112
+ it("waits for the newest readiness result before authorizing a send", async () => {
2048
2113
  chatMocks.readiness = {
2049
- canChat: false,
2114
+ canChat: true,
2050
2115
  missing: false,
2051
- state: "unknown",
2116
+ state: "configured",
2052
2117
  };
2118
+ let resolveFirst!: (state: "configured" | "missing") => void;
2119
+ let resolveSecond!: (state: "configured" | "missing") => void;
2120
+ chatMocks.fetchProviderState
2121
+ .mockReturnValueOnce(
2122
+ new Promise((resolve) => {
2123
+ resolveFirst = resolve;
2124
+ }),
2125
+ )
2126
+ .mockReturnValueOnce(
2127
+ new Promise((resolve) => {
2128
+ resolveSecond = resolve;
2129
+ }),
2130
+ );
2053
2131
  await mount(baseProps({ providerStatusChecksEnabled: true }));
2054
- await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(true);
2055
2132
 
2133
+ let firstPreflight!: Promise<boolean>;
2134
+ let secondPreflight!: Promise<boolean>;
2135
+ await act(async () => {
2136
+ firstPreflight = chatMocks.composerProps.onBeforeSubmit();
2137
+ await Promise.resolve();
2138
+ });
2139
+ chatMocks.readiness = {
2140
+ canChat: false,
2141
+ missing: true,
2142
+ state: "missing",
2143
+ };
2056
2144
  await act(async () => {
2057
- chatMocks.readiness = {
2058
- canChat: false,
2059
- missing: true,
2060
- state: "missing",
2061
- };
2062
2145
  root.render(
2063
2146
  <AgentKitAssistantChat
2064
2147
  {...baseProps({ providerStatusChecksEnabled: true })}
2065
2148
  />,
2066
2149
  );
2067
2150
  });
2151
+ await act(async () => {
2152
+ secondPreflight = chatMocks.composerProps.onBeforeSubmit();
2153
+ await Promise.resolve();
2154
+ });
2155
+ expect(chatMocks.fetchProviderState).toHaveBeenCalledTimes(2);
2068
2156
 
2069
- await expect(
2070
- chatMocks.composerProps.onSubmit("Keep until connected", [], [], {}),
2071
- ).rejects.toThrow("agentChat.recovery.deferredSubmissionFailed");
2157
+ await act(async () => {
2158
+ resolveFirst("configured");
2159
+ await Promise.resolve();
2160
+ });
2161
+ let firstSettled = false;
2162
+ void firstPreflight.then(() => {
2163
+ firstSettled = true;
2164
+ });
2165
+ await flush();
2166
+ expect(firstSettled).toBe(false);
2167
+ expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
2168
+
2169
+ await act(async () => {
2170
+ resolveSecond("missing");
2171
+ await expect(firstPreflight).resolves.toBe(false);
2172
+ await expect(secondPreflight).resolves.toBe(false);
2173
+ });
2174
+
2175
+ expect(chatMocks.composerProps.disabled).toBe(true);
2176
+ expect(chatMocks.composerProps.submissionDisabled).toBe(true);
2177
+ expect(chatMocks.setupCardProps).toMatchObject({ attached: true });
2072
2178
  expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
2073
- expect(
2074
- [...chatMocks.appState.keys()].some((key) =>
2075
- key.startsWith("agentkit-deferred-provider-submissions:"),
2076
- ),
2077
- ).toBe(false);
2078
2179
  });
2079
2180
 
2080
- it("sends a draft once provider readiness resolves", async () => {
2181
+ it("keeps a successful submit preflight through a transient passive failure", async () => {
2081
2182
  chatMocks.readiness = {
2082
- canChat: false,
2183
+ canChat: true,
2083
2184
  missing: false,
2084
- state: "unknown",
2185
+ state: "configured",
2085
2186
  };
2086
- await mount(
2087
- baseProps({
2088
- providerStatusChecksEnabled: true,
2089
- composerSubmissionDisabled: true,
2187
+ let resolveReadiness!: (state: "configured" | "missing") => void;
2188
+ chatMocks.fetchProviderState.mockReturnValueOnce(
2189
+ new Promise((resolve) => {
2190
+ resolveReadiness = resolve;
2090
2191
  }),
2091
2192
  );
2193
+ const props = baseProps({ providerStatusChecksEnabled: true });
2194
+ await mount(props);
2092
2195
 
2093
- expect(chatMocks.composerProps.submissionDisabled).toBe(true);
2094
- await expect(chatMocks.composerProps.onBeforeSubmit()).resolves.toBe(false);
2196
+ let preflight!: Promise<boolean>;
2197
+ await act(async () => {
2198
+ preflight = chatMocks.composerProps.onBeforeSubmit();
2199
+ await Promise.resolve();
2200
+ });
2201
+ expect(chatMocks.fetchProviderState).toHaveBeenCalledOnce();
2095
2202
 
2096
2203
  await act(async () => {
2097
- chatMocks.readiness = {
2098
- canChat: true,
2099
- missing: false,
2100
- state: "configured",
2101
- };
2102
- root.render(
2103
- <AgentKitAssistantChat
2104
- {...baseProps({
2105
- providerStatusChecksEnabled: true,
2106
- composerSubmissionDisabled: false,
2107
- })}
2108
- />,
2109
- );
2204
+ resolveReadiness("configured");
2205
+ await expect(preflight).resolves.toBe(true);
2110
2206
  });
2111
2207
 
2112
- expect(chatMocks.composerProps.submissionDisabled).toBe(false);
2208
+ chatMocks.readiness = {
2209
+ canChat: false,
2210
+ missing: false,
2211
+ state: "unavailable",
2212
+ };
2113
2213
  await act(async () => {
2114
- await chatMocks.composerProps.onSubmit(
2115
- "Send after discovery",
2116
- [],
2117
- [],
2118
- {},
2119
- );
2214
+ root.render(<AgentKitAssistantChat {...props} />);
2120
2215
  });
2121
2216
 
2122
- expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
2123
- expect(chatMocks.control.sendMessage.mock.calls[0]?.[0]?.text).toBe(
2124
- "Send after discovery",
2217
+ expect(chatMocks.composerProps.disabled).toBe(false);
2218
+ expect(chatMocks.composerProps.submissionDisabled).toBe(false);
2219
+
2220
+ await act(async () =>
2221
+ chatMocks.composerProps.onSubmit("Send", [], [], {
2222
+ intent: "immediate",
2223
+ }),
2125
2224
  );
2225
+ expect(chatMocks.fetchProviderState).toHaveBeenCalledOnce();
2226
+ expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
2126
2227
  });
2127
2228
 
2128
2229
  it("keeps the composer editable when the host blocks submission", async () => {
@@ -2894,49 +2995,27 @@ describe("AgentKitAssistantChat host behavior", () => {
2894
2995
  });
2895
2996
  });
2896
2997
 
2897
- it("durably queues unresolved sends with files and references across remounts", async () => {
2998
+ it("rejects unresolved sends before uploading or queueing their attachments", async () => {
2898
2999
  chatMocks.readiness = {
2899
3000
  canChat: false,
2900
3001
  missing: false,
2901
3002
  state: "unknown",
2902
3003
  };
2903
- const initialCapturedAt = Date.now();
2904
- chatMocks.appState.set("pending-selection-context", {
2905
- text: "Initial selection",
2906
- capturedAt: initialCapturedAt,
2907
- });
2908
- let resolveUpload!: (
2909
- parts: Awaited<ReturnType<typeof chatMocks.control.uploadFiles>>,
2910
- ) => void;
2911
- chatMocks.control.uploadFiles.mockImplementationOnce(
2912
- () => new Promise((resolve) => (resolveUpload = resolve)),
2913
- );
2914
- chatMocks.guidedQuestions = [{ id: "question-1" }];
2915
3004
  const ref = createRef<AssistantChatHandle>();
2916
3005
  container = document.createElement("div");
2917
3006
  document.body.appendChild(container);
2918
3007
  root = createRoot(container);
2919
- const props = baseProps({
2920
- providerStatusChecksEnabled: true,
2921
- tabId: "tab-1",
2922
- });
3008
+ const props = baseProps({ providerStatusChecksEnabled: true });
2923
3009
  await act(async () => {
2924
3010
  root.render(<AgentKitAssistantChat ref={ref} {...props} />);
2925
3011
  });
2926
3012
  const results: CustomEvent[] = [];
2927
3013
  const listener = (event: Event) => results.push(event as CustomEvent);
2928
3014
  window.addEventListener(AGENT_CHAT_SUBMIT_RESULT_EVENT, listener);
2929
- const reference = {
2930
- type: "file",
2931
- path: "notes.txt",
2932
- name: "notes.txt",
2933
- source: "composer",
2934
- } as const;
2935
-
2936
- let deferredSend!: Promise<AssistantChatSubmitResult>;
3015
+ let sendResult!: AssistantChatSubmitResult;
2937
3016
  await act(async () => {
2938
3017
  ref.current?.prefillMessage("Visible composer draft");
2939
- deferredSend = ref.current!.sendMessage(
3018
+ sendResult = await ref.current!.sendMessage(
2940
3019
  "Wait for the provider",
2941
3020
  undefined,
2942
3021
  {
@@ -2948,115 +3027,28 @@ describe("AgentKitAssistantChat host behavior", () => {
2948
3027
  text: "private attachment body",
2949
3028
  },
2950
3029
  ],
2951
- recoveryReferences: [reference],
2952
- } as AssistantChatSendOptions,
3030
+ },
2953
3031
  );
2954
- await new Promise((resolve) => setTimeout(resolve, 0));
2955
3032
  });
2956
- const nextCapturedAt = initialCapturedAt + 1;
2957
- await act(async () => {
2958
- window.dispatchEvent(
2959
- new CustomEvent("agent-panel:selection-attached", {
2960
- detail: { text: "Selection for the next prompt" },
2961
- }),
2962
- );
2963
- chatMocks.appState.set("pending-selection-context", {
2964
- text: "Selection for the next prompt",
2965
- capturedAt: nextCapturedAt,
2966
- });
2967
- resolveUpload([
2968
- {
2969
- type: "file",
2970
- name: "notes.txt",
2971
- mediaType: "text/plain",
2972
- url: "https://files.example.test/notes.txt",
2973
- },
2974
- ]);
2975
- await deferredSend;
3033
+ expect(sendResult).toEqual({
3034
+ status: "rejected",
3035
+ reason: "submission-unavailable",
2976
3036
  });
2977
-
2978
3037
  expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
2979
3038
  expect(results.map((event) => event.detail)).toEqual([
2980
- { submitMessageId: "pending-provider-submit", delivered: true },
2981
- ]);
2982
- expect(chatMocks.composerProps.initialText).toBe("Visible composer draft");
2983
- expect(chatMocks.guidedFlowProps).toMatchObject({
2984
- isSubmissionBlocked: true,
2985
- providerStatus: "unknown",
2986
- });
2987
- const stateKey = [...chatMocks.appState.keys()].find((key) =>
2988
- key.startsWith("agentkit-deferred-provider-submissions:"),
2989
- );
2990
- expect(stateKey).toBeDefined();
2991
- const persisted = chatMocks.appState.get(stateKey!) as {
2992
- submissions: Array<{
2993
- fileParts: unknown[];
2994
- options: {
2995
- pendingSelectionCapturedAt: number | null;
2996
- recoveryReferences: unknown[];
2997
- skipAmbientSelectionContext: boolean;
2998
- };
2999
- }>;
3000
- };
3001
- expect(persisted.submissions[0]).toMatchObject({
3002
- fileParts: [
3003
- {
3004
- type: "file",
3005
- name: "notes.txt",
3006
- url: "https://files.example.test/notes.txt",
3007
- },
3008
- ],
3009
- options: {
3010
- pendingSelectionCapturedAt: initialCapturedAt,
3011
- recoveryReferences: [reference],
3012
- skipAmbientSelectionContext: true,
3039
+ {
3040
+ submitMessageId: "pending-provider-submit",
3041
+ delivered: false,
3042
+ reason: "submission-unavailable",
3013
3043
  },
3014
- });
3015
- expect(JSON.stringify(persisted)).not.toContain("private attachment body");
3016
-
3017
- await unmount();
3018
- root = undefined as unknown as Root;
3019
-
3020
- chatMocks.readiness = {
3021
- canChat: true,
3022
- missing: false,
3023
- state: "configured",
3024
- };
3025
- container = document.createElement("div");
3026
- document.body.appendChild(container);
3027
- root = createRoot(container);
3028
- await act(async () => {
3029
- root.render(<AgentKitAssistantChat ref={ref} {...props} />);
3030
- });
3031
- await flush();
3032
-
3044
+ ]);
3033
3045
  expect(chatMocks.composerProps.initialText).toBe("Visible composer draft");
3034
- expect(chatMocks.control.sendMessage).toHaveBeenCalledOnce();
3035
- const request = chatMocks.control.sendMessage.mock.calls[0]?.[0];
3036
- expect(request).toMatchObject({
3037
- attachments: [
3038
- {
3039
- type: "file",
3040
- name: "notes.txt",
3041
- url: "https://files.example.test/notes.txt",
3042
- },
3043
- ],
3044
- metadata: {
3045
- references: [reference],
3046
- custom: {
3047
- agentNativeDeferredSubmissionId: "pending-provider-submit",
3048
- },
3049
- agentNativeSkipPendingSelectionContext: true,
3050
- },
3051
- });
3052
- expect(request?.text).toContain("Initial selection");
3053
- expect(request?.text).not.toContain("Selection for the next prompt");
3054
- expect(results).toHaveLength(1);
3055
- expect(chatMocks.appState.has(stateKey!)).toBe(false);
3056
- expect(chatMocks.appState.get("pending-selection-context")).toEqual({
3057
- text: "Selection for the next prompt",
3058
- capturedAt: nextCapturedAt,
3059
- });
3046
+ expect(chatMocks.control.uploadFiles).not.toHaveBeenCalled();
3047
+ expect(
3048
+ [...chatMocks.appState.keys()].some((key) =>
3049
+ key.startsWith("agentkit-deferred-provider-submissions:"),
3050
+ ),
3051
+ ).toBe(false);
3060
3052
  window.removeEventListener(AGENT_CHAT_SUBMIT_RESULT_EVENT, listener);
3061
3053
  });
3062
3054
 
@@ -3461,22 +3453,24 @@ describe("AgentKitAssistantChat host behavior", () => {
3461
3453
  />,
3462
3454
  );
3463
3455
  });
3464
- await expect(
3465
- ref.current!.sendMessage("Try again", undefined, {
3466
- submitMessageId: "unavailable-submit",
3467
- }),
3468
- ).resolves.toEqual({ status: "submitted" });
3456
+ await act(async () => {
3457
+ await expect(
3458
+ ref.current!.sendMessage("Try again", undefined, {
3459
+ submitMessageId: "unavailable-submit",
3460
+ }),
3461
+ ).resolves.toEqual({
3462
+ status: "rejected",
3463
+ reason: "submission-unavailable",
3464
+ });
3465
+ });
3469
3466
  expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
3470
3467
  expect(results.at(-1)?.detail).toEqual({
3471
3468
  submitMessageId: "unavailable-submit",
3472
- delivered: true,
3469
+ delivered: false,
3470
+ reason: "submission-unavailable",
3473
3471
  });
3474
3472
 
3475
- chatMocks.readiness = {
3476
- canChat: true,
3477
- missing: false,
3478
- state: "configured",
3479
- };
3473
+ chatMocks.fetchProviderState.mockResolvedValue("configured");
3480
3474
  await act(async () => {
3481
3475
  root.render(
3482
3476
  <AgentKitAssistantChat
@@ -3484,10 +3478,12 @@ describe("AgentKitAssistantChat host behavior", () => {
3484
3478
  {...baseProps({ providerStatusChecksEnabled: true })}
3485
3479
  />,
3486
3480
  );
3487
- await new Promise((resolve) => setTimeout(resolve, 0));
3481
+ await expect(
3482
+ ref.current!.sendMessage("Try again after fresh check"),
3483
+ ).resolves.toEqual({ status: "submitted" });
3488
3484
  });
3489
3485
  expect(chatMocks.control.sendMessage).toHaveBeenCalledWith(
3490
- expect.objectContaining({ text: "Try again" }),
3486
+ expect.objectContaining({ text: "Try again after fresh check" }),
3491
3487
  );
3492
3488
  window.removeEventListener(AGENT_CHAT_SUBMIT_RESULT_EVENT, listener);
3493
3489
  });
@@ -3536,6 +3532,14 @@ describe("AgentKitAssistantChat host behavior", () => {
3536
3532
  expect(chatMocks.control.queueMessage).not.toHaveBeenCalled();
3537
3533
  });
3538
3534
 
3535
+ it("hides the shared guided-question card when the host owns that flow", async () => {
3536
+ chatMocks.guidedQuestions = [{ id: "question-1", question: "Title?" }];
3537
+ await mount(baseProps({ showGuidedQuestions: false }));
3538
+
3539
+ expect(chatMocks.guidedOptions).toMatchObject({ enabled: false });
3540
+ expect(chatMocks.guidedFlowProps).toBeNull();
3541
+ });
3542
+
3539
3543
  it("sends directly when a stale composer render outlives the queued run", async () => {
3540
3544
  chatMocks.thread.activeRunIds = ["run-queued-follow-up"];
3541
3545
  chatMocks.thread.runs = {
@@ -4275,7 +4279,7 @@ describe("AgentKitAssistantChat host behavior", () => {
4275
4279
  expect(chatMocks.control.uploadFiles).not.toHaveBeenCalled();
4276
4280
  });
4277
4281
 
4278
- it("preserves saved file IDs when retrying while the provider is unavailable", async () => {
4282
+ it("keeps saved file IDs when retrying while the provider is unavailable", async () => {
4279
4283
  chatMocks.readiness = {
4280
4284
  canChat: false,
4281
4285
  missing: false,
@@ -4309,24 +4313,17 @@ describe("AgentKitAssistantChat host behavior", () => {
4309
4313
  await new Promise((resolve) => setTimeout(resolve, 0));
4310
4314
  });
4311
4315
 
4312
- const stateKey = [...chatMocks.appState.keys()].find((key) =>
4313
- key.startsWith("agentkit-deferred-provider-submissions:"),
4314
- );
4315
- expect(stateKey).toBeDefined();
4316
- expect(chatMocks.appState.get(stateKey!)).toMatchObject({
4317
- submissions: [
4318
- {
4319
- fileParts: [
4320
- {
4321
- type: "file",
4322
- name: "source.csv",
4323
- mediaType: "text/csv",
4324
- fileId: "file-1",
4325
- },
4326
- ],
4327
- },
4328
- ],
4316
+ expect(chatMocks.thread.messages[0]?.parts).toContainEqual({
4317
+ type: "file",
4318
+ name: "source.csv",
4319
+ mediaType: "text/csv",
4320
+ fileId: "file-1",
4329
4321
  });
4322
+ expect(
4323
+ [...chatMocks.appState.keys()].some((key) =>
4324
+ key.startsWith("agentkit-deferred-provider-submissions:"),
4325
+ ),
4326
+ ).toBe(false);
4330
4327
  expect(chatMocks.control.uploadFiles).not.toHaveBeenCalled();
4331
4328
  expect(chatMocks.control.sendMessage).not.toHaveBeenCalled();
4332
4329
  });