@agent-native/core 0.30.5 → 0.31.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/dist/a2a/client.d.ts +2 -0
  2. package/dist/a2a/client.d.ts.map +1 -1
  3. package/dist/a2a/client.js +6 -4
  4. package/dist/a2a/client.js.map +1 -1
  5. package/dist/a2a/handlers.d.ts.map +1 -1
  6. package/dist/a2a/handlers.js +3 -0
  7. package/dist/a2a/handlers.js.map +1 -1
  8. package/dist/a2a/server.d.ts.map +1 -1
  9. package/dist/a2a/server.js.map +1 -1
  10. package/dist/a2a/task-store.js.map +1 -1
  11. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  12. package/dist/agent/engine/anthropic-engine.js +0 -7
  13. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  14. package/dist/agent/engine/registry.d.ts.map +1 -1
  15. package/dist/agent/engine/registry.js.map +1 -1
  16. package/dist/agent/engine/translate-ai-sdk.d.ts.map +1 -1
  17. package/dist/agent/engine/translate-ai-sdk.js +5 -3
  18. package/dist/agent/engine/translate-ai-sdk.js.map +1 -1
  19. package/dist/agent/production-agent.d.ts.map +1 -1
  20. package/dist/agent/production-agent.js +13 -3
  21. package/dist/agent/production-agent.js.map +1 -1
  22. package/dist/agent/run-manager.d.ts.map +1 -1
  23. package/dist/agent/run-manager.js +14 -6
  24. package/dist/agent/run-manager.js.map +1 -1
  25. package/dist/application-state/store.d.ts.map +1 -1
  26. package/dist/application-state/store.js.map +1 -1
  27. package/dist/brand-kit/brand-signals.d.ts +31 -0
  28. package/dist/brand-kit/brand-signals.d.ts.map +1 -0
  29. package/dist/brand-kit/brand-signals.js +101 -0
  30. package/dist/brand-kit/brand-signals.js.map +1 -0
  31. package/dist/brand-kit/index.d.ts +21 -0
  32. package/dist/brand-kit/index.d.ts.map +1 -0
  33. package/dist/brand-kit/index.js +34 -0
  34. package/dist/brand-kit/index.js.map +1 -0
  35. package/dist/brand-kit/types.d.ts +103 -0
  36. package/dist/brand-kit/types.d.ts.map +1 -0
  37. package/dist/brand-kit/types.js +17 -0
  38. package/dist/brand-kit/types.js.map +1 -0
  39. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  40. package/dist/cli/code-agent-executor.js.map +1 -1
  41. package/dist/cli/create.d.ts.map +1 -1
  42. package/dist/cli/create.js +0 -1
  43. package/dist/cli/create.js.map +1 -1
  44. package/dist/client/AgentNative.js.map +1 -1
  45. package/dist/client/AgentPanel.d.ts.map +1 -1
  46. package/dist/client/AgentPanel.js +0 -2
  47. package/dist/client/AgentPanel.js.map +1 -1
  48. package/dist/client/AssistantChat.d.ts.map +1 -1
  49. package/dist/client/AssistantChat.js +81 -22
  50. package/dist/client/AssistantChat.js.map +1 -1
  51. package/dist/client/IframeEmbed.d.ts.map +1 -1
  52. package/dist/client/IframeEmbed.js.map +1 -1
  53. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  54. package/dist/client/MultiTabAssistantChat.js +1 -1
  55. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  56. package/dist/client/RunStuckBanner.js.map +1 -1
  57. package/dist/client/agent-chat.d.ts.map +1 -1
  58. package/dist/client/agent-chat.js.map +1 -1
  59. package/dist/client/builder-mark.d.ts.map +1 -1
  60. package/dist/client/builder-mark.js.map +1 -1
  61. package/dist/client/components/MissingKeyCard.d.ts.map +1 -1
  62. package/dist/client/components/MissingKeyCard.js.map +1 -1
  63. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  64. package/dist/client/composer/PromptComposer.js +6 -3
  65. package/dist/client/composer/PromptComposer.js.map +1 -1
  66. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  67. package/dist/client/composer/TiptapComposer.js +5 -0
  68. package/dist/client/composer/TiptapComposer.js.map +1 -1
  69. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  70. package/dist/client/composer/VoiceButton.js +9 -0
  71. package/dist/client/composer/VoiceButton.js.map +1 -1
  72. package/dist/client/composer/extensions/FileReference.d.ts.map +1 -1
  73. package/dist/client/composer/extensions/FileReference.js.map +1 -1
  74. package/dist/client/composer/extensions/MentionReference.d.ts.map +1 -1
  75. package/dist/client/composer/extensions/MentionReference.js.map +1 -1
  76. package/dist/client/composer/extensions/SkillReference.d.ts.map +1 -1
  77. package/dist/client/composer/extensions/SkillReference.js.map +1 -1
  78. package/dist/client/conversation/AgentConversation.js +8 -6
  79. package/dist/client/conversation/AgentConversation.js.map +1 -1
  80. package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -1
  81. package/dist/client/conversation/use-near-bottom-autoscroll.js +133 -35
  82. package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -1
  83. package/dist/client/db-admin/DbAdminPage.js.map +1 -1
  84. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  85. package/dist/client/dev-overlay/DevOverlay.js +0 -1
  86. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  87. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  88. package/dist/client/extensions/EmbeddedExtension.js +19 -0
  89. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  90. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  91. package/dist/client/extensions/ExtensionViewer.js +11 -3
  92. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  93. package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
  94. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  95. package/dist/client/mcp-app-host.d.ts.map +1 -1
  96. package/dist/client/mcp-app-host.js +6 -1
  97. package/dist/client/mcp-app-host.js.map +1 -1
  98. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  99. package/dist/client/mcp-apps/McpAppRenderer.js +1 -1
  100. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  101. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  102. package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
  103. package/dist/client/onboarding/SetupButton.js +6 -0
  104. package/dist/client/onboarding/SetupButton.js.map +1 -1
  105. package/dist/client/progress/RunsTray.js.map +1 -1
  106. package/dist/client/resources/McpServerDetail.d.ts.map +1 -1
  107. package/dist/client/resources/McpServerDetail.js.map +1 -1
  108. package/dist/client/settings/AgentsSection.d.ts.map +1 -1
  109. package/dist/client/settings/AgentsSection.js +1 -1
  110. package/dist/client/settings/AgentsSection.js.map +1 -1
  111. package/dist/client/settings/AutomationsSection.js.map +1 -1
  112. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  113. package/dist/client/sharing/ShareButton.js +0 -4
  114. package/dist/client/sharing/ShareButton.js.map +1 -1
  115. package/dist/client/terminal/AgentTerminal.d.ts.map +1 -1
  116. package/dist/client/terminal/AgentTerminal.js +1 -1
  117. package/dist/client/terminal/AgentTerminal.js.map +1 -1
  118. package/dist/client/use-agent-chat.d.ts.map +1 -1
  119. package/dist/client/use-agent-chat.js +20 -4
  120. package/dist/client/use-agent-chat.js.map +1 -1
  121. package/dist/client/use-chat-threads.d.ts.map +1 -1
  122. package/dist/client/use-chat-threads.js +39 -25
  123. package/dist/client/use-chat-threads.js.map +1 -1
  124. package/dist/client/use-db-sync.d.ts.map +1 -1
  125. package/dist/client/use-db-sync.js +8 -0
  126. package/dist/client/use-db-sync.js.map +1 -1
  127. package/dist/client/use-dev-mode.d.ts.map +1 -1
  128. package/dist/client/use-dev-mode.js +25 -9
  129. package/dist/client/use-dev-mode.js.map +1 -1
  130. package/dist/client/useProductionAgent.d.ts.map +1 -1
  131. package/dist/client/useProductionAgent.js +6 -2
  132. package/dist/client/useProductionAgent.js.map +1 -1
  133. package/dist/collab/agent-presence.d.ts.map +1 -1
  134. package/dist/collab/agent-presence.js +1 -1
  135. package/dist/collab/agent-presence.js.map +1 -1
  136. package/dist/collab/awareness.d.ts.map +1 -1
  137. package/dist/collab/awareness.js +8 -0
  138. package/dist/collab/awareness.js.map +1 -1
  139. package/dist/collab/client-struct.js.map +1 -1
  140. package/dist/deploy/build.js +0 -5
  141. package/dist/deploy/build.js.map +1 -1
  142. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  143. package/dist/extensions/fetch-tool.js +4 -1
  144. package/dist/extensions/fetch-tool.js.map +1 -1
  145. package/dist/file-upload/actions/upload-image.d.ts.map +1 -1
  146. package/dist/file-upload/actions/upload-image.js +39 -4
  147. package/dist/file-upload/actions/upload-image.js.map +1 -1
  148. package/dist/integrations/adapters/slack.d.ts.map +1 -1
  149. package/dist/integrations/adapters/slack.js.map +1 -1
  150. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  151. package/dist/integrations/google-docs-poller.js +14 -1
  152. package/dist/integrations/google-docs-poller.js.map +1 -1
  153. package/dist/integrations/plugin.d.ts.map +1 -1
  154. package/dist/integrations/plugin.js.map +1 -1
  155. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  156. package/dist/integrations/webhook-handler.js +10 -1
  157. package/dist/integrations/webhook-handler.js.map +1 -1
  158. package/dist/jobs/scheduler.d.ts.map +1 -1
  159. package/dist/jobs/scheduler.js.map +1 -1
  160. package/dist/mcp/build-server.d.ts.map +1 -1
  161. package/dist/mcp/build-server.js +28 -12
  162. package/dist/mcp/build-server.js.map +1 -1
  163. package/dist/mcp/connect-store.d.ts.map +1 -1
  164. package/dist/mcp/connect-store.js +1 -1
  165. package/dist/mcp/connect-store.js.map +1 -1
  166. package/dist/mcp-client/index.d.ts.map +1 -1
  167. package/dist/mcp-client/index.js +2 -3
  168. package/dist/mcp-client/index.js.map +1 -1
  169. package/dist/notifications/channels.d.ts.map +1 -1
  170. package/dist/notifications/channels.js +3 -2
  171. package/dist/notifications/channels.js.map +1 -1
  172. package/dist/oauth-tokens/store.js.map +1 -1
  173. package/dist/observability/evals.d.ts.map +1 -1
  174. package/dist/observability/evals.js +7 -7
  175. package/dist/observability/evals.js.map +1 -1
  176. package/dist/observability/traces.d.ts.map +1 -1
  177. package/dist/observability/traces.js +15 -5
  178. package/dist/observability/traces.js.map +1 -1
  179. package/dist/org/handlers.d.ts.map +1 -1
  180. package/dist/org/handlers.js +3 -2
  181. package/dist/org/handlers.js.map +1 -1
  182. package/dist/resources/handlers.d.ts +5 -5
  183. package/dist/resources/handlers.d.ts.map +1 -1
  184. package/dist/resources/handlers.js.map +1 -1
  185. package/dist/scripts/db/schema.js.map +1 -1
  186. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  187. package/dist/server/agent-chat-plugin.js +0 -6
  188. package/dist/server/agent-chat-plugin.js.map +1 -1
  189. package/dist/server/auth.d.ts.map +1 -1
  190. package/dist/server/auth.js.map +1 -1
  191. package/dist/server/better-auth-instance.d.ts.map +1 -1
  192. package/dist/server/better-auth-instance.js +0 -3
  193. package/dist/server/better-auth-instance.js.map +1 -1
  194. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  195. package/dist/server/core-routes-plugin.js +1 -2
  196. package/dist/server/core-routes-plugin.js.map +1 -1
  197. package/dist/server/create-server.d.ts.map +1 -1
  198. package/dist/server/create-server.js +0 -23
  199. package/dist/server/create-server.js.map +1 -1
  200. package/dist/server/google-oauth.d.ts.map +1 -1
  201. package/dist/server/google-oauth.js +0 -3
  202. package/dist/server/google-oauth.js.map +1 -1
  203. package/dist/server/poll.d.ts.map +1 -1
  204. package/dist/server/poll.js +49 -18
  205. package/dist/server/poll.js.map +1 -1
  206. package/dist/settings/store.js.map +1 -1
  207. package/dist/sharing/access.d.ts.map +1 -1
  208. package/dist/sharing/access.js +25 -4
  209. package/dist/sharing/access.js.map +1 -1
  210. package/dist/triggers/dispatcher.d.ts.map +1 -1
  211. package/dist/triggers/dispatcher.js.map +1 -1
  212. package/dist/vite/client.d.ts.map +1 -1
  213. package/dist/vite/client.js +2 -0
  214. package/dist/vite/client.js.map +1 -1
  215. package/package.json +3 -2
  216. package/dist/client/conversation/AgentConversation.spec.d.ts +0 -2
  217. package/dist/client/conversation/AgentConversation.spec.d.ts.map +0 -1
  218. package/dist/client/conversation/AgentConversation.spec.js +0 -69
  219. package/dist/client/conversation/AgentConversation.spec.js.map +0 -1
  220. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.d.ts +0 -2
  221. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.d.ts.map +0 -1
  222. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.js +0 -110
  223. package/dist/client/extensions/AgentNativeExtensionFrame.e2e-host.js.map +0 -1
  224. package/dist/client/extensions/AgentNativeExtensionFrame.spec.d.ts +0 -2
  225. package/dist/client/extensions/AgentNativeExtensionFrame.spec.d.ts.map +0 -1
  226. package/dist/client/extensions/AgentNativeExtensionFrame.spec.js +0 -68
  227. package/dist/client/extensions/AgentNativeExtensionFrame.spec.js.map +0 -1
  228. package/dist/client/extensions/ExtensionViewer.spec.d.ts +0 -2
  229. package/dist/client/extensions/ExtensionViewer.spec.d.ts.map +0 -1
  230. package/dist/client/extensions/ExtensionViewer.spec.js +0 -94
  231. package/dist/client/extensions/ExtensionViewer.spec.js.map +0 -1
  232. package/dist/client/guided-questions.flow.spec.d.ts +0 -2
  233. package/dist/client/guided-questions.flow.spec.d.ts.map +0 -1
  234. package/dist/client/guided-questions.flow.spec.js +0 -147
  235. package/dist/client/guided-questions.flow.spec.js.map +0 -1
  236. package/dist/client/settings/useBuilderStatus.spec.d.ts +0 -2
  237. package/dist/client/settings/useBuilderStatus.spec.d.ts.map +0 -1
  238. package/dist/client/settings/useBuilderStatus.spec.js +0 -487
  239. package/dist/client/settings/useBuilderStatus.spec.js.map +0 -1
  240. package/dist/client/sharing/ShareButton.spec.d.ts +0 -2
  241. package/dist/client/sharing/ShareButton.spec.d.ts.map +0 -1
  242. package/dist/client/sharing/ShareButton.spec.js +0 -196
  243. package/dist/client/sharing/ShareButton.spec.js.map +0 -1
  244. package/dist/client/use-chat-models.spec.d.ts +0 -2
  245. package/dist/client/use-chat-models.spec.d.ts.map +0 -1
  246. package/dist/client/use-chat-models.spec.js +0 -39
  247. package/dist/client/use-chat-models.spec.js.map +0 -1
  248. package/dist/client/use-chat-threads.spec.d.ts +0 -2
  249. package/dist/client/use-chat-threads.spec.d.ts.map +0 -1
  250. package/dist/client/use-chat-threads.spec.js +0 -760
  251. package/dist/client/use-chat-threads.spec.js.map +0 -1
  252. package/dist/client/use-db-sync.spec.d.ts +0 -2
  253. package/dist/client/use-db-sync.spec.d.ts.map +0 -1
  254. package/dist/client/use-db-sync.spec.js +0 -107
  255. package/dist/client/use-db-sync.spec.js.map +0 -1
  256. package/dist/server/script-discovery.d.ts +0 -6
  257. package/dist/server/script-discovery.d.ts.map +0 -1
  258. package/dist/server/script-discovery.js +0 -6
  259. package/dist/server/script-discovery.js.map +0 -1
@@ -1,760 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- // @vitest-environment happy-dom
3
- import { act } from "react";
4
- import { createRoot } from "react-dom/client";
5
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
- import { useChatThreads, } from "./use-chat-threads.js";
7
- function jsonResponse(data) {
8
- return new Response(JSON.stringify(data), {
9
- headers: { "Content-Type": "application/json" },
10
- });
11
- }
12
- describe("useChatThreads", () => {
13
- let container;
14
- let root;
15
- beforeEach(() => {
16
- vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
17
- vi.stubGlobal("crypto", { randomUUID: () => "forked-thread" });
18
- window.localStorage.clear();
19
- container = document.createElement("div");
20
- document.body.appendChild(container);
21
- root = createRoot(container);
22
- });
23
- afterEach(() => {
24
- act(() => {
25
- root.unmount();
26
- });
27
- container.remove();
28
- vi.unstubAllGlobals();
29
- });
30
- it("starts fresh when no active thread is saved, even if server history exists", async () => {
31
- const oldThread = {
32
- id: "old-project-thread",
33
- title: "Animated charting tool",
34
- preview: "make the chart more playful",
35
- messageCount: 2,
36
- createdAt: 1,
37
- updatedAt: 2,
38
- scope: null,
39
- };
40
- const fetchMock = vi.fn(async (url, init) => {
41
- if (url === "/chat/threads" && !init) {
42
- return jsonResponse({ threads: [oldThread] });
43
- }
44
- throw new Error(`Unexpected fetch: ${url}`);
45
- });
46
- vi.stubGlobal("fetch", fetchMock);
47
- let hook = null;
48
- function Harness() {
49
- hook = useChatThreads("/chat", "analytics-project");
50
- return null;
51
- }
52
- await act(async () => {
53
- root.render(_jsx(Harness, {}));
54
- });
55
- await act(async () => {
56
- await Promise.resolve();
57
- await Promise.resolve();
58
- });
59
- expect(hook.activeThreadId).toBe("forked-thread");
60
- expect(hook.threads.map((thread) => thread.id)).toEqual([
61
- "forked-thread",
62
- "old-project-thread",
63
- ]);
64
- });
65
- it("keeps a saved active thread when it still exists on the server", async () => {
66
- window.localStorage.setItem("agent-chat-active-thread:analytics-project", "old-project-thread");
67
- const oldThread = {
68
- id: "old-project-thread",
69
- title: "Analytics for Academy",
70
- preview: "show weekly signups",
71
- messageCount: 2,
72
- createdAt: 1,
73
- updatedAt: 2,
74
- scope: null,
75
- };
76
- const fetchMock = vi.fn(async (url, init) => {
77
- if (url === "/chat/threads" && !init) {
78
- return jsonResponse({ threads: [oldThread] });
79
- }
80
- throw new Error(`Unexpected fetch: ${url}`);
81
- });
82
- vi.stubGlobal("fetch", fetchMock);
83
- let hook = null;
84
- function Harness() {
85
- hook = useChatThreads("/chat", "analytics-project");
86
- return null;
87
- }
88
- await act(async () => {
89
- root.render(_jsx(Harness, {}));
90
- });
91
- await act(async () => {
92
- await Promise.resolve();
93
- await Promise.resolve();
94
- });
95
- expect(hook.activeThreadId).toBe("old-project-thread");
96
- expect(hook.threads.map((thread) => thread.id)).toEqual([
97
- "old-project-thread",
98
- ]);
99
- });
100
- it("can ignore a saved active thread and start fresh immediately", async () => {
101
- window.localStorage.setItem("agent-chat-active-thread:brain", "old-brain-thread");
102
- const oldThread = {
103
- id: "old-brain-thread",
104
- title: "Using the Brain demo corpus",
105
- preview: "what should the demo cite?",
106
- messageCount: 2,
107
- createdAt: 1,
108
- updatedAt: 2,
109
- scope: null,
110
- };
111
- const fetchMock = vi.fn(async (url, init) => {
112
- if (url === "/chat/threads" && !init) {
113
- return jsonResponse({ threads: [oldThread] });
114
- }
115
- throw new Error(`Unexpected fetch: ${url}`);
116
- });
117
- vi.stubGlobal("fetch", fetchMock);
118
- let hook = null;
119
- function Harness() {
120
- hook = useChatThreads("/chat", "brain", null, {
121
- restoreActiveThread: false,
122
- });
123
- return null;
124
- }
125
- await act(async () => {
126
- root.render(_jsx(Harness, {}));
127
- });
128
- expect(hook.activeThreadId).toBe("forked-thread");
129
- await act(async () => {
130
- await Promise.resolve();
131
- await Promise.resolve();
132
- });
133
- expect(hook.threads.map((thread) => thread.id)).toEqual([
134
- "forked-thread",
135
- "old-brain-thread",
136
- ]);
137
- });
138
- it("keeps the active general chat visible when entering a scoped surface", async () => {
139
- window.localStorage.setItem("agent-chat-active-thread:forms-app", "general-thread");
140
- const generalThread = {
141
- id: "general-thread",
142
- title: "Create a form",
143
- preview: "make me a form",
144
- messageCount: 2,
145
- createdAt: 1,
146
- updatedAt: 2,
147
- scope: null,
148
- };
149
- const formThread = {
150
- id: "form-thread",
151
- title: "Form edits",
152
- preview: "add another question",
153
- messageCount: 2,
154
- createdAt: 3,
155
- updatedAt: 4,
156
- scope: { type: "form", id: "form-1", label: "Hackathon" },
157
- };
158
- const fetchMock = vi.fn(async (url, init) => {
159
- if (url === "/chat/threads" && !init) {
160
- return jsonResponse({ threads: [generalThread, formThread] });
161
- }
162
- throw new Error(`Unexpected fetch: ${url}`);
163
- });
164
- vi.stubGlobal("fetch", fetchMock);
165
- let hook = null;
166
- function Harness({ scope }) {
167
- hook = useChatThreads("/chat", "forms-app", scope);
168
- return null;
169
- }
170
- await act(async () => {
171
- root.render(_jsx(Harness, { scope: null }));
172
- });
173
- await act(async () => {
174
- await Promise.resolve();
175
- await Promise.resolve();
176
- });
177
- expect(hook.activeThreadId).toBe("general-thread");
178
- await act(async () => {
179
- root.render(_jsx(Harness, { scope: { type: "form", id: "form-1", label: "Hackathon" } }));
180
- });
181
- await act(async () => {
182
- await Promise.resolve();
183
- await Promise.resolve();
184
- });
185
- expect(hook.activeThreadId).toBe("general-thread");
186
- expect(window.localStorage.getItem("agent-chat-active-thread:forms-app:scope:form:form-1")).toBeNull();
187
- expect(window.localStorage.getItem("agent-chat-active-thread:forms-app")).toBe("general-thread");
188
- });
189
- it("switches back to the general chat when leaving a scoped thread", async () => {
190
- window.localStorage.setItem("agent-chat-active-thread:forms-app", "general-thread");
191
- window.localStorage.setItem("agent-chat-active-thread:forms-app:scope:form:form-1", "form-thread");
192
- const generalThread = {
193
- id: "general-thread",
194
- title: "Create a form",
195
- preview: "make me a form",
196
- messageCount: 2,
197
- createdAt: 1,
198
- updatedAt: 2,
199
- scope: null,
200
- };
201
- const formThread = {
202
- id: "form-thread",
203
- title: "Form edits",
204
- preview: "add another question",
205
- messageCount: 2,
206
- createdAt: 3,
207
- updatedAt: 4,
208
- scope: { type: "form", id: "form-1", label: "Hackathon" },
209
- };
210
- const fetchMock = vi.fn(async (url, init) => {
211
- if (url === "/chat/threads" && !init) {
212
- return jsonResponse({ threads: [formThread, generalThread] });
213
- }
214
- throw new Error(`Unexpected fetch: ${url}`);
215
- });
216
- vi.stubGlobal("fetch", fetchMock);
217
- let hook = null;
218
- function Harness({ scope }) {
219
- hook = useChatThreads("/chat", "forms-app", scope);
220
- return null;
221
- }
222
- await act(async () => {
223
- root.render(_jsx(Harness, { scope: { type: "form", id: "form-1", label: "Hackathon" } }));
224
- });
225
- await act(async () => {
226
- await Promise.resolve();
227
- await Promise.resolve();
228
- });
229
- expect(hook.activeThreadId).toBe("form-thread");
230
- await act(async () => {
231
- root.render(_jsx(Harness, { scope: null }));
232
- });
233
- await act(async () => {
234
- await Promise.resolve();
235
- await Promise.resolve();
236
- });
237
- expect(hook.activeThreadId).toBe("general-thread");
238
- });
239
- it("sends the current client snapshot when forking a thread", async () => {
240
- const sourceThread = {
241
- id: "source-thread",
242
- title: "Pipeline",
243
- preview: "make this slide better",
244
- messageCount: 2,
245
- createdAt: 1,
246
- updatedAt: 2,
247
- scope: { type: "dashboard", id: "dash-1", label: "Pipeline" },
248
- };
249
- const fetchMock = vi.fn(async (url, init) => {
250
- if (url === "/chat/threads" && !init) {
251
- return jsonResponse({ threads: [sourceThread] });
252
- }
253
- if (url === "/chat/threads/source-thread/fork") {
254
- return jsonResponse({
255
- ...sourceThread,
256
- id: "forked-thread",
257
- title: "Pipeline (fork)",
258
- });
259
- }
260
- throw new Error(`Unexpected fetch: ${url}`);
261
- });
262
- vi.stubGlobal("fetch", fetchMock);
263
- let hook = null;
264
- function Harness() {
265
- hook = useChatThreads("/chat", "fork-test");
266
- return null;
267
- }
268
- await act(async () => {
269
- root.render(_jsx(Harness, {}));
270
- });
271
- await act(async () => {
272
- await Promise.resolve();
273
- await Promise.resolve();
274
- });
275
- const snapshot = {
276
- threadData: JSON.stringify({ messages: [{ message: { id: "m1" } }] }),
277
- title: "Pipeline",
278
- preview: "make this slide better",
279
- messageCount: 1,
280
- };
281
- let forkedId = null;
282
- await act(async () => {
283
- forkedId = await hook.forkThread("source-thread", snapshot);
284
- });
285
- expect(forkedId).toBe("forked-thread");
286
- const forkCall = fetchMock.mock.calls.find(([url]) => url === "/chat/threads/source-thread/fork");
287
- expect(forkCall).toBeDefined();
288
- expect(JSON.parse(forkCall[1].body)).toEqual({
289
- id: "forked-thread",
290
- source: { ...snapshot, scope: sourceThread.scope },
291
- });
292
- });
293
- it("creates a fork from the client snapshot when the fork endpoint cannot find the source", async () => {
294
- const sourceThread = {
295
- id: "source-thread",
296
- title: "Pipeline",
297
- preview: "make this slide better",
298
- messageCount: 2,
299
- createdAt: 1,
300
- updatedAt: 2,
301
- scope: { type: "deck", id: "deck-1", label: "Pipeline deck" },
302
- };
303
- const fetchMock = vi.fn(async (url, init) => {
304
- if (url === "/chat/threads" && !init) {
305
- return jsonResponse({ threads: [sourceThread] });
306
- }
307
- if (url === "/chat/threads/source-thread/fork") {
308
- return new Response(JSON.stringify({ error: "Thread not found" }), {
309
- status: 404,
310
- headers: { "Content-Type": "application/json" },
311
- });
312
- }
313
- if (url === "/chat/threads" && init?.method === "POST") {
314
- return jsonResponse({
315
- id: "forked-thread",
316
- title: "Pipeline (fork)",
317
- preview: "",
318
- messageCount: 0,
319
- createdAt: 3,
320
- updatedAt: 3,
321
- scope: sourceThread.scope,
322
- });
323
- }
324
- if (url === "/chat/threads/forked-thread" && init?.method === "PUT") {
325
- return jsonResponse({ ok: true });
326
- }
327
- throw new Error(`Unexpected fetch: ${url}`);
328
- });
329
- vi.stubGlobal("fetch", fetchMock);
330
- let hook = null;
331
- function Harness() {
332
- hook = useChatThreads("/chat", "fork-test");
333
- return null;
334
- }
335
- await act(async () => {
336
- root.render(_jsx(Harness, {}));
337
- });
338
- await act(async () => {
339
- await Promise.resolve();
340
- await Promise.resolve();
341
- });
342
- const snapshot = {
343
- threadData: JSON.stringify({ messages: [{ message: { id: "m1" } }] }),
344
- title: "Pipeline",
345
- preview: "make this slide better",
346
- messageCount: 1,
347
- };
348
- let forkedId = null;
349
- await act(async () => {
350
- forkedId = await hook.forkThread("source-thread", snapshot);
351
- });
352
- expect(forkedId).toBe("forked-thread");
353
- const createCall = fetchMock.mock.calls.find(([url, init]) => url === "/chat/threads" && init?.method === "POST");
354
- expect(createCall).toBeDefined();
355
- expect(JSON.parse(createCall[1].body)).toEqual({
356
- id: "forked-thread",
357
- title: "Pipeline (fork)",
358
- scope: sourceThread.scope,
359
- });
360
- const saveCall = fetchMock.mock.calls.find(([url, init]) => url === "/chat/threads/forked-thread" && init?.method === "PUT");
361
- expect(saveCall).toBeDefined();
362
- expect(JSON.parse(saveCall[1].body)).toEqual({
363
- threadData: snapshot.threadData,
364
- title: "Pipeline (fork)",
365
- preview: snapshot.preview,
366
- messageCount: snapshot.messageCount,
367
- scope: sourceThread.scope,
368
- });
369
- });
370
- it("keeps generated titles when later thread saves update the preview", async () => {
371
- const sourceThread = {
372
- id: "thread-1",
373
- title: "Using the Brain demo data for this example",
374
- preview: "Using the Brain demo data for this example",
375
- messageCount: 1,
376
- createdAt: 1,
377
- updatedAt: 2,
378
- scope: null,
379
- };
380
- const fetchMock = vi.fn(async (url, init) => {
381
- if (url === "/chat/threads" && !init) {
382
- return jsonResponse({ threads: [sourceThread] });
383
- }
384
- if (url === "/chat/threads/thread-1" && init?.method === "PUT") {
385
- return jsonResponse({ ok: true });
386
- }
387
- throw new Error(`Unexpected fetch: ${url}`);
388
- });
389
- vi.stubGlobal("fetch", fetchMock);
390
- let hook = null;
391
- function Harness() {
392
- hook = useChatThreads("/chat", "title-test", null, {
393
- autoCreate: false,
394
- });
395
- return null;
396
- }
397
- await act(async () => {
398
- root.render(_jsx(Harness, {}));
399
- });
400
- await act(async () => {
401
- await Promise.resolve();
402
- await Promise.resolve();
403
- });
404
- await act(async () => {
405
- await hook.saveThreadData("thread-1", {
406
- threadData: "",
407
- title: "Brain Demo Setup",
408
- preview: "Using the Brain demo data for this example",
409
- titleSource: "generated",
410
- });
411
- });
412
- await act(async () => {
413
- await hook.saveThreadData("thread-1", {
414
- threadData: JSON.stringify({ messages: [] }),
415
- title: "Using the Brain demo data for this example",
416
- preview: "What should the demo answer cite?",
417
- messageCount: 2,
418
- });
419
- });
420
- const saveCalls = fetchMock.mock.calls.filter(([url, init]) => url === "/chat/threads/thread-1" && init?.method === "PUT");
421
- expect(JSON.parse(saveCalls[0][1].body).title).toBe("Brain Demo Setup");
422
- expect(JSON.parse(saveCalls[1][1].body).title).toBe("Brain Demo Setup");
423
- expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
424
- title: "Brain Demo Setup",
425
- preview: "What should the demo answer cite?",
426
- messageCount: 2,
427
- });
428
- });
429
- it("renames a thread optimistically", async () => {
430
- const sourceThread = {
431
- id: "thread-1",
432
- title: "Old title",
433
- preview: "old preview",
434
- messageCount: 1,
435
- createdAt: 1,
436
- updatedAt: 2,
437
- scope: null,
438
- };
439
- const fetchMock = vi.fn(async (url, init) => {
440
- if (url === "/chat/threads" && !init) {
441
- return jsonResponse({ threads: [sourceThread] });
442
- }
443
- if (url === "/chat/threads/thread-1/rename" && init?.method === "POST") {
444
- return jsonResponse({ ok: true });
445
- }
446
- throw new Error(`Unexpected fetch: ${url}`);
447
- });
448
- vi.stubGlobal("fetch", fetchMock);
449
- let hook = null;
450
- function Harness() {
451
- hook = useChatThreads("/chat", "rename-test", null, {
452
- autoCreate: false,
453
- });
454
- return null;
455
- }
456
- await act(async () => {
457
- root.render(_jsx(Harness, {}));
458
- });
459
- await act(async () => {
460
- await Promise.resolve();
461
- await Promise.resolve();
462
- });
463
- await act(async () => {
464
- await hook.renameThread("thread-1", " New title ");
465
- });
466
- expect(JSON.parse(fetchMock.mock.calls[1][1].body)).toEqual({
467
- title: "New title",
468
- });
469
- expect(hook.threads.find((thread) => thread.id === "thread-1")?.title).toBe("New title");
470
- });
471
- it("rolls back a failed pin update", async () => {
472
- const sourceThread = {
473
- id: "thread-1",
474
- title: "Pinned candidate",
475
- preview: "old preview",
476
- messageCount: 1,
477
- createdAt: 1,
478
- updatedAt: 2,
479
- scope: null,
480
- pinnedAt: null,
481
- };
482
- const fetchMock = vi.fn(async (url, init) => {
483
- if (url === "/chat/threads" && !init) {
484
- return jsonResponse({ threads: [sourceThread] });
485
- }
486
- if (url === "/chat/threads/thread-1/pin" && init?.method === "POST") {
487
- return new Response(JSON.stringify({ error: "nope" }), {
488
- status: 500,
489
- headers: { "Content-Type": "application/json" },
490
- });
491
- }
492
- throw new Error(`Unexpected fetch: ${url}`);
493
- });
494
- vi.stubGlobal("fetch", fetchMock);
495
- let hook = null;
496
- function Harness() {
497
- hook = useChatThreads("/chat", "pin-failure-test", null, {
498
- autoCreate: false,
499
- });
500
- return null;
501
- }
502
- await act(async () => {
503
- root.render(_jsx(Harness, {}));
504
- });
505
- await act(async () => {
506
- await Promise.resolve();
507
- await Promise.resolve();
508
- });
509
- let pinned = true;
510
- await act(async () => {
511
- pinned = await hook.pinThread("thread-1", true);
512
- });
513
- expect(pinned).toBe(false);
514
- expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
515
- pinnedAt: null,
516
- updatedAt: 2,
517
- });
518
- });
519
- it("keeps the active thread when archive fails", async () => {
520
- window.localStorage.setItem("agent-chat-active-thread:archive-failure-test", "thread-1");
521
- const sourceThread = {
522
- id: "thread-1",
523
- title: "Archive candidate",
524
- preview: "old preview",
525
- messageCount: 1,
526
- createdAt: 1,
527
- updatedAt: 2,
528
- scope: null,
529
- archivedAt: null,
530
- };
531
- const fetchMock = vi.fn(async (url, init) => {
532
- if (url === "/chat/threads" && !init) {
533
- return jsonResponse({ threads: [sourceThread] });
534
- }
535
- if (url === "/chat/threads/thread-1/archive" && init?.method === "POST") {
536
- return new Response(JSON.stringify({ error: "nope" }), {
537
- status: 500,
538
- headers: { "Content-Type": "application/json" },
539
- });
540
- }
541
- throw new Error(`Unexpected fetch: ${url}`);
542
- });
543
- vi.stubGlobal("fetch", fetchMock);
544
- let hook = null;
545
- function Harness() {
546
- hook = useChatThreads("/chat", "archive-failure-test", null, {
547
- autoCreate: false,
548
- });
549
- return null;
550
- }
551
- await act(async () => {
552
- root.render(_jsx(Harness, {}));
553
- });
554
- await act(async () => {
555
- await Promise.resolve();
556
- await Promise.resolve();
557
- });
558
- let archived = true;
559
- await act(async () => {
560
- archived = await hook.archiveThread("thread-1");
561
- });
562
- expect(archived).toBe(false);
563
- expect(hook.activeThreadId).toBe("thread-1");
564
- expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
565
- archivedAt: null,
566
- updatedAt: 2,
567
- });
568
- });
569
- it("keeps server pin metadata when local updatedAt is newer for another reason", async () => {
570
- let serverThread = {
571
- id: "thread-1",
572
- title: "Thread",
573
- preview: "old preview",
574
- messageCount: 1,
575
- createdAt: 1,
576
- updatedAt: 2,
577
- scope: null,
578
- pinnedAt: null,
579
- };
580
- const fetchMock = vi.fn(async (url, init) => {
581
- if (url === "/chat/threads" && !init) {
582
- return jsonResponse({ threads: [serverThread] });
583
- }
584
- if (url === "/chat/threads/thread-1" && init?.method === "PUT") {
585
- return jsonResponse({ ok: true });
586
- }
587
- throw new Error(`Unexpected fetch: ${url}`);
588
- });
589
- vi.stubGlobal("fetch", fetchMock);
590
- let hook = null;
591
- function Harness() {
592
- hook = useChatThreads("/chat", "server-pin-merge-test", null, {
593
- autoCreate: false,
594
- });
595
- return null;
596
- }
597
- await act(async () => {
598
- root.render(_jsx(Harness, {}));
599
- });
600
- await act(async () => {
601
- await Promise.resolve();
602
- await Promise.resolve();
603
- });
604
- await act(async () => {
605
- await hook.saveThreadData("thread-1", {
606
- threadData: "{}",
607
- title: "Thread",
608
- preview: "local send",
609
- messageCount: 2,
610
- });
611
- });
612
- serverThread = {
613
- ...serverThread,
614
- pinnedAt: 123,
615
- updatedAt: 3,
616
- };
617
- await act(async () => {
618
- hook.refreshThreads();
619
- await Promise.resolve();
620
- await Promise.resolve();
621
- });
622
- expect(hook.threads.find((thread) => thread.id === "thread-1")).toMatchObject({
623
- pinnedAt: 123,
624
- preview: "local send",
625
- messageCount: 2,
626
- });
627
- });
628
- it("does not restore an archived thread after failed archive if the user moved on", async () => {
629
- window.localStorage.setItem("agent-chat-active-thread:archive-navigation-test", "thread-1");
630
- const threads = [
631
- {
632
- id: "thread-1",
633
- title: "Archive candidate",
634
- preview: "old preview",
635
- messageCount: 1,
636
- createdAt: 1,
637
- updatedAt: 2,
638
- scope: null,
639
- archivedAt: null,
640
- },
641
- {
642
- id: "thread-2",
643
- title: "Next thread",
644
- preview: "keep me open",
645
- messageCount: 1,
646
- createdAt: 3,
647
- updatedAt: 4,
648
- scope: null,
649
- archivedAt: null,
650
- },
651
- ];
652
- let resolveArchive = null;
653
- const fetchMock = vi.fn(async (url, init) => {
654
- if (url === "/chat/threads" && !init) {
655
- return jsonResponse({ threads });
656
- }
657
- if (url === "/chat/threads/thread-1/archive" && init?.method === "POST") {
658
- return new Promise((resolve) => {
659
- resolveArchive = resolve;
660
- });
661
- }
662
- throw new Error(`Unexpected fetch: ${url}`);
663
- });
664
- vi.stubGlobal("fetch", fetchMock);
665
- let hook = null;
666
- function Harness() {
667
- hook = useChatThreads("/chat", "archive-navigation-test", null, {
668
- autoCreate: false,
669
- });
670
- return null;
671
- }
672
- await act(async () => {
673
- root.render(_jsx(Harness, {}));
674
- });
675
- await act(async () => {
676
- await Promise.resolve();
677
- await Promise.resolve();
678
- });
679
- let archivePromise;
680
- await act(async () => {
681
- archivePromise = hook.archiveThread("thread-1");
682
- hook.switchThread("thread-2");
683
- await Promise.resolve();
684
- });
685
- await act(async () => {
686
- resolveArchive(new Response(JSON.stringify({ error: "nope" }), {
687
- status: 500,
688
- headers: { "Content-Type": "application/json" },
689
- }));
690
- await archivePromise;
691
- await Promise.resolve();
692
- await Promise.resolve();
693
- });
694
- expect(hook.activeThreadId).toBe("thread-2");
695
- });
696
- it("preserves a user rename over generated titles and later saves", async () => {
697
- const sourceThread = {
698
- id: "thread-1",
699
- title: "Old title",
700
- preview: "old preview",
701
- messageCount: 1,
702
- createdAt: 1,
703
- updatedAt: 2,
704
- scope: null,
705
- };
706
- let resolveGenerate = null;
707
- const fetchMock = vi.fn(async (url, init) => {
708
- if (url === "/chat/threads" && !init) {
709
- return jsonResponse({ threads: [sourceThread] });
710
- }
711
- if (url === "/chat/generate-title" && init?.method === "POST") {
712
- return new Promise((resolve) => {
713
- resolveGenerate = resolve;
714
- });
715
- }
716
- if (url === "/chat/threads/thread-1/rename" && init?.method === "POST") {
717
- return jsonResponse({ ok: true });
718
- }
719
- if (url === "/chat/threads/thread-1" && init?.method === "PUT") {
720
- return jsonResponse({ ok: true });
721
- }
722
- throw new Error(`Unexpected fetch: ${url}`);
723
- });
724
- vi.stubGlobal("fetch", fetchMock);
725
- let hook = null;
726
- function Harness() {
727
- hook = useChatThreads("/chat", "rename-generated-test", null, {
728
- autoCreate: false,
729
- });
730
- return null;
731
- }
732
- await act(async () => {
733
- root.render(_jsx(Harness, {}));
734
- });
735
- await act(async () => {
736
- await Promise.resolve();
737
- await Promise.resolve();
738
- });
739
- const generatedTitlePromise = hook.generateTitle("thread-1", "Please summarize this chat");
740
- await act(async () => {
741
- await hook.renameThread("thread-1", "User title");
742
- });
743
- await act(async () => {
744
- resolveGenerate(jsonResponse({ title: "Generated title" }));
745
- await generatedTitlePromise;
746
- });
747
- await act(async () => {
748
- await hook.saveThreadData("thread-1", {
749
- threadData: "",
750
- title: "Generated title",
751
- preview: "Please summarize this chat",
752
- titleSource: "generated",
753
- });
754
- });
755
- const saveCall = fetchMock.mock.calls.find(([url, init]) => url === "/chat/threads/thread-1" && init?.method === "PUT");
756
- expect(JSON.parse(saveCall[1].body).title).toBe("User title");
757
- expect(hook.threads.find((thread) => thread.id === "thread-1")?.title).toBe("User title");
758
- });
759
- });
760
- //# sourceMappingURL=use-chat-threads.spec.js.map