@btst/stack 2.2.0 → 2.4.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 (237) hide show
  1. package/dist/packages/stack/src/client/components/compose.cjs +1 -2
  2. package/dist/packages/stack/src/client/components/compose.mjs +1 -2
  3. package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.cjs +71 -0
  4. package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.mjs +68 -0
  5. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +54 -7
  6. package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +54 -7
  7. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +2 -2
  8. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +2 -2
  9. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +89 -22
  10. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +90 -23
  11. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +110 -33
  12. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +112 -35
  13. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +1 -1
  14. package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +1 -1
  15. package/dist/packages/stack/src/plugins/ai-chat/schemas.cjs +17 -1
  16. package/dist/packages/stack/src/plugins/ai-chat/schemas.mjs +17 -1
  17. package/dist/packages/stack/src/plugins/blog/api/plugin.cjs +52 -1
  18. package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +52 -1
  19. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.cjs +18 -0
  20. package/dist/packages/stack/src/plugins/blog/api/query-key-defs.mjs +15 -0
  21. package/dist/packages/stack/src/plugins/blog/api/serializers.cjs +21 -0
  22. package/dist/packages/stack/src/plugins/blog/api/serializers.mjs +18 -0
  23. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +15 -2
  24. package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +16 -3
  25. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +24 -1
  26. package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +24 -1
  27. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.cjs +26 -0
  28. package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.mjs +24 -0
  29. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +30 -1
  30. package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +30 -1
  31. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -0
  32. package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -0
  33. package/dist/packages/stack/src/plugins/blog/client/plugin.cjs +15 -0
  34. package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +16 -1
  35. package/dist/packages/stack/src/plugins/cms/api/getters.cjs +10 -0
  36. package/dist/packages/stack/src/plugins/cms/api/getters.mjs +10 -1
  37. package/dist/packages/stack/src/plugins/cms/api/mutations.cjs +48 -0
  38. package/dist/packages/stack/src/plugins/cms/api/mutations.mjs +46 -0
  39. package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +75 -0
  40. package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +76 -1
  41. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +29 -0
  42. package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +26 -0
  43. package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +15 -0
  44. package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +16 -1
  45. package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +9 -0
  46. package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +9 -1
  47. package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +62 -1
  48. package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +63 -2
  49. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +37 -0
  50. package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +33 -0
  51. package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +15 -0
  52. package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +16 -1
  53. package/dist/packages/stack/src/plugins/kanban/api/mutations.cjs +91 -0
  54. package/dist/packages/stack/src/plugins/kanban/api/mutations.mjs +87 -0
  55. package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +34 -1
  56. package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +34 -1
  57. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.cjs +26 -0
  58. package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.mjs +23 -0
  59. package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +30 -0
  60. package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +26 -0
  61. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +7 -3
  62. package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +7 -3
  63. package/dist/packages/stack/src/plugins/kanban/client/plugin.cjs +10 -0
  64. package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +11 -1
  65. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +89 -0
  66. package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +89 -0
  67. package/dist/packages/stack/src/plugins/utils.cjs +6 -0
  68. package/dist/packages/stack/src/plugins/utils.mjs +6 -1
  69. package/dist/plugins/ai-chat/api/index.d.cts +1 -1
  70. package/dist/plugins/ai-chat/api/index.d.mts +1 -1
  71. package/dist/plugins/ai-chat/api/index.d.ts +1 -1
  72. package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
  73. package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
  74. package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
  75. package/dist/plugins/ai-chat/client/context/page-ai-context.cjs +92 -0
  76. package/dist/plugins/ai-chat/client/context/page-ai-context.d.cts +84 -0
  77. package/dist/plugins/ai-chat/client/context/page-ai-context.d.mts +84 -0
  78. package/dist/plugins/ai-chat/client/context/page-ai-context.d.ts +84 -0
  79. package/dist/plugins/ai-chat/client/context/page-ai-context.mjs +88 -0
  80. package/dist/plugins/ai-chat/client/hooks/index.d.cts +1 -1
  81. package/dist/plugins/ai-chat/client/hooks/index.d.mts +1 -1
  82. package/dist/plugins/ai-chat/client/hooks/index.d.ts +1 -1
  83. package/dist/plugins/ai-chat/client/index.d.cts +2 -2
  84. package/dist/plugins/ai-chat/client/index.d.mts +2 -2
  85. package/dist/plugins/ai-chat/client/index.d.ts +2 -2
  86. package/dist/plugins/ai-chat/query-keys.d.cts +1 -1
  87. package/dist/plugins/ai-chat/query-keys.d.mts +1 -1
  88. package/dist/plugins/ai-chat/query-keys.d.ts +1 -1
  89. package/dist/plugins/blog/api/index.cjs +5 -0
  90. package/dist/plugins/blog/api/index.d.cts +19 -4
  91. package/dist/plugins/blog/api/index.d.mts +19 -4
  92. package/dist/plugins/blog/api/index.d.ts +19 -4
  93. package/dist/plugins/blog/api/index.mjs +2 -0
  94. package/dist/plugins/blog/client/hooks/index.d.cts +3 -3
  95. package/dist/plugins/blog/client/hooks/index.d.mts +3 -3
  96. package/dist/plugins/blog/client/hooks/index.d.ts +3 -3
  97. package/dist/plugins/blog/client/index.d.cts +1 -1
  98. package/dist/plugins/blog/client/index.d.mts +1 -1
  99. package/dist/plugins/blog/client/index.d.ts +1 -1
  100. package/dist/plugins/blog/query-keys.cjs +6 -5
  101. package/dist/plugins/blog/query-keys.d.cts +8 -387
  102. package/dist/plugins/blog/query-keys.d.mts +8 -387
  103. package/dist/plugins/blog/query-keys.d.ts +8 -387
  104. package/dist/plugins/blog/query-keys.mjs +6 -5
  105. package/dist/plugins/client/index.cjs +1 -0
  106. package/dist/plugins/client/index.d.cts +8 -1
  107. package/dist/plugins/client/index.d.mts +8 -1
  108. package/dist/plugins/client/index.d.ts +8 -1
  109. package/dist/plugins/client/index.mjs +1 -1
  110. package/dist/plugins/cms/api/index.cjs +8 -0
  111. package/dist/plugins/cms/api/index.d.cts +7 -219
  112. package/dist/plugins/cms/api/index.d.mts +7 -219
  113. package/dist/plugins/cms/api/index.d.ts +7 -219
  114. package/dist/plugins/cms/api/index.mjs +3 -1
  115. package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
  116. package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
  117. package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
  118. package/dist/plugins/cms/query-keys.cjs +2 -1
  119. package/dist/plugins/cms/query-keys.d.cts +5 -9
  120. package/dist/plugins/cms/query-keys.d.mts +5 -9
  121. package/dist/plugins/cms/query-keys.d.ts +5 -9
  122. package/dist/plugins/cms/query-keys.mjs +2 -1
  123. package/dist/plugins/form-builder/api/index.cjs +6 -0
  124. package/dist/plugins/form-builder/api/index.d.cts +7 -211
  125. package/dist/plugins/form-builder/api/index.d.mts +7 -211
  126. package/dist/plugins/form-builder/api/index.d.ts +7 -211
  127. package/dist/plugins/form-builder/api/index.mjs +2 -1
  128. package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
  129. package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
  130. package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
  131. package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
  132. package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
  133. package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
  134. package/dist/plugins/form-builder/query-keys.cjs +3 -2
  135. package/dist/plugins/form-builder/query-keys.d.cts +6 -6
  136. package/dist/plugins/form-builder/query-keys.d.mts +6 -6
  137. package/dist/plugins/form-builder/query-keys.d.ts +6 -6
  138. package/dist/plugins/form-builder/query-keys.mjs +3 -2
  139. package/dist/plugins/kanban/api/index.cjs +10 -0
  140. package/dist/plugins/kanban/api/index.d.cts +17 -392
  141. package/dist/plugins/kanban/api/index.d.mts +17 -392
  142. package/dist/plugins/kanban/api/index.d.ts +17 -392
  143. package/dist/plugins/kanban/api/index.mjs +3 -0
  144. package/dist/plugins/kanban/client/components/index.d.cts +1 -1
  145. package/dist/plugins/kanban/client/components/index.d.mts +1 -1
  146. package/dist/plugins/kanban/client/components/index.d.ts +1 -1
  147. package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
  148. package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
  149. package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
  150. package/dist/plugins/kanban/client/index.d.cts +1 -1
  151. package/dist/plugins/kanban/client/index.d.mts +1 -1
  152. package/dist/plugins/kanban/client/index.d.ts +1 -1
  153. package/dist/plugins/kanban/query-keys.cjs +2 -9
  154. package/dist/plugins/kanban/query-keys.d.cts +4 -16
  155. package/dist/plugins/kanban/query-keys.d.mts +4 -16
  156. package/dist/plugins/kanban/query-keys.d.ts +4 -16
  157. package/dist/plugins/kanban/query-keys.mjs +2 -9
  158. package/dist/plugins/ui-builder/index.d.cts +1 -1
  159. package/dist/plugins/ui-builder/index.d.mts +1 -1
  160. package/dist/plugins/ui-builder/index.d.ts +1 -1
  161. package/dist/shared/stack.B7ONvlD_.d.mts +293 -0
  162. package/dist/shared/{stack.BeSm90va.d.ts → stack.BEn34wW6.d.ts} +60 -2
  163. package/dist/shared/stack.BUkC2EsZ.d.cts +327 -0
  164. package/dist/shared/{stack.DaOcgmrM.d.ts → stack.BV9hnvu4.d.cts} +31 -7
  165. package/dist/shared/{stack.DaOcgmrM.d.cts → stack.BV9hnvu4.d.mts} +31 -7
  166. package/dist/shared/{stack.DaOcgmrM.d.mts → stack.BV9hnvu4.d.ts} +31 -7
  167. package/dist/shared/stack.BepFXT3w.d.mts +500 -0
  168. package/dist/shared/stack.CL8ts1Mu.d.ts +419 -0
  169. package/dist/shared/{stack.CXjzTMsb.d.cts → stack.CVDTkMoO.d.cts} +7 -1
  170. package/dist/shared/{stack.CXjzTMsb.d.mts → stack.CVDTkMoO.d.mts} +7 -1
  171. package/dist/shared/{stack.CXjzTMsb.d.ts → stack.CVDTkMoO.d.ts} +7 -1
  172. package/dist/shared/stack.CczspVn2.d.mts +327 -0
  173. package/dist/shared/stack.CgWzG5jH.d.ts +500 -0
  174. package/dist/shared/stack.D3GB6wKv.d.cts +500 -0
  175. package/dist/shared/stack.DASmUVjX.d.ts +327 -0
  176. package/dist/shared/{stack.QD1y_7NY.d.cts → stack.DJaKVY7v.d.cts} +1 -1
  177. package/dist/shared/{stack.QD1y_7NY.d.mts → stack.DJaKVY7v.d.mts} +1 -1
  178. package/dist/shared/{stack.QD1y_7NY.d.ts → stack.DJaKVY7v.d.ts} +1 -1
  179. package/dist/shared/{stack.Dg09R0oB.d.mts → stack.DTDxgFj8.d.mts} +60 -2
  180. package/dist/shared/{stack.CMh_EdxW.d.cts → stack.DWoCZff7.d.cts} +60 -2
  181. package/dist/shared/{stack.CIrIsc-A.d.cts → stack.DdI5W6MB.d.cts} +7 -1
  182. package/dist/shared/{stack.CIrIsc-A.d.mts → stack.DdI5W6MB.d.mts} +7 -1
  183. package/dist/shared/{stack.CIrIsc-A.d.ts → stack.DdI5W6MB.d.ts} +7 -1
  184. package/dist/shared/stack.Dk5r4W1F.d.mts +419 -0
  185. package/dist/shared/stack.Kq2-QzOC.d.ts +293 -0
  186. package/dist/shared/stack.heOA9gzA.d.cts +419 -0
  187. package/dist/shared/stack.kcdnD4gA.d.cts +293 -0
  188. package/package.json +16 -3
  189. package/src/client/components/compose.tsx +7 -4
  190. package/src/plugins/ai-chat/api/page-tools.ts +111 -0
  191. package/src/plugins/ai-chat/api/plugin.ts +180 -9
  192. package/src/plugins/ai-chat/client/components/chat-input.tsx +2 -2
  193. package/src/plugins/ai-chat/client/components/chat-interface.tsx +154 -58
  194. package/src/plugins/ai-chat/client/components/chat-layout.tsx +166 -32
  195. package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +1 -1
  196. package/src/plugins/ai-chat/client/context/page-ai-context.tsx +240 -0
  197. package/src/plugins/ai-chat/schemas.ts +16 -0
  198. package/src/plugins/blog/api/index.ts +2 -0
  199. package/src/plugins/blog/api/plugin.ts +85 -0
  200. package/src/plugins/blog/api/query-key-defs.ts +46 -0
  201. package/src/plugins/blog/api/serializers.ts +27 -0
  202. package/src/plugins/blog/client/components/forms/post-forms.tsx +29 -2
  203. package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +28 -0
  204. package/src/plugins/blog/client/components/pages/fill-blog-form-handler.ts +38 -0
  205. package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +33 -1
  206. package/src/plugins/blog/client/components/pages/post-page.internal.tsx +20 -0
  207. package/src/plugins/blog/client/plugin.tsx +19 -0
  208. package/src/plugins/blog/query-keys.ts +5 -7
  209. package/src/plugins/client/index.ts +1 -1
  210. package/src/plugins/cms/api/getters.ts +24 -0
  211. package/src/plugins/cms/api/index.ts +14 -1
  212. package/src/plugins/cms/api/mutations.ts +84 -0
  213. package/src/plugins/cms/api/plugin.ts +114 -0
  214. package/src/plugins/cms/api/query-key-defs.ts +53 -0
  215. package/src/plugins/cms/api/serializers.ts +12 -0
  216. package/src/plugins/cms/client/plugin.tsx +19 -0
  217. package/src/plugins/cms/query-keys.ts +2 -1
  218. package/src/plugins/form-builder/api/getters.ts +23 -0
  219. package/src/plugins/form-builder/api/index.ts +15 -2
  220. package/src/plugins/form-builder/api/plugin.ts +91 -0
  221. package/src/plugins/form-builder/api/query-key-defs.ts +79 -0
  222. package/src/plugins/form-builder/api/serializers.ts +12 -0
  223. package/src/plugins/form-builder/client/plugin.tsx +19 -0
  224. package/src/plugins/form-builder/query-keys.ts +6 -2
  225. package/src/plugins/kanban/api/index.ts +9 -0
  226. package/src/plugins/kanban/api/mutations.ts +169 -0
  227. package/src/plugins/kanban/api/plugin.ts +61 -0
  228. package/src/plugins/kanban/api/query-key-defs.ts +54 -0
  229. package/src/plugins/kanban/api/serializers.ts +49 -0
  230. package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
  231. package/src/plugins/kanban/client/plugin.tsx +13 -0
  232. package/src/plugins/kanban/query-keys.ts +2 -9
  233. package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
  234. package/src/plugins/utils.ts +19 -0
  235. package/dist/shared/{stack.BkYlUT_8.d.cts → stack.BQmuNl5p.d.cts} +6 -6
  236. package/dist/shared/{stack.BkYlUT_8.d.mts → stack.BQmuNl5p.d.mts} +6 -6
  237. package/dist/shared/{stack.BkYlUT_8.d.ts → stack.BQmuNl5p.d.ts} +6 -6
@@ -7,13 +7,14 @@ import { ChatMessage } from './chat-message.mjs';
7
7
  import { ChatInput } from './chat-input.mjs';
8
8
  import { StackAttribution } from '../../../../../../ui/src/components/stack-attribution.mjs';
9
9
  import { ScrollArea } from '../../../../../../ui/src/components/scroll-area.mjs';
10
- import { DefaultChatTransport } from 'ai';
10
+ import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
11
11
  import { cn } from '../../../../../../ui/src/lib/utils.mjs';
12
12
  import { usePluginOverrides, useBasePath } from '@btst/stack/context';
13
13
  import { AI_CHAT_LOCALIZATION } from '../localization/index.mjs';
14
14
  import { createApiClient } from '@btst/stack/plugins/client';
15
15
  import { createAiChatQueryKeys } from '../../../../../../../plugins/ai-chat/query-keys.mjs';
16
16
  import { useConversation, useConversations } from '../hooks/chat-hooks.mjs';
17
+ import { usePageAIContext } from '../../../../../../../plugins/ai-chat/client/context/page-ai-context.mjs';
17
18
 
18
19
  function ChatInterface({
19
20
  apiPath = "/api/chat",
@@ -38,6 +39,7 @@ function ChatInterface({
38
39
  );
39
40
  const basePath = useBasePath();
40
41
  const isPublicMode = mode === "public";
42
+ const pageAIContext = usePageAIContext();
41
43
  const localization = { ...AI_CHAT_LOCALIZATION, ...customLocalization };
42
44
  const queryClient = useQueryClient();
43
45
  const conversationsListQueryKey = useMemo(() => {
@@ -81,13 +83,25 @@ function ChatInterface({
81
83
  !initialMessages || initialMessages.length === 0
82
84
  )
83
85
  );
86
+ const pageAIContextRef = useRef(pageAIContext);
87
+ useEffect(() => {
88
+ pageAIContextRef.current = pageAIContext;
89
+ }, [pageAIContext]);
84
90
  const transport = useMemo(
85
91
  () => new DefaultChatTransport({
86
92
  api: apiPath,
87
93
  // In public mode, don't send conversationId
88
94
  body: isPublicMode ? void 0 : () => ({ conversationId: conversationIdRef.current }),
89
- // Handle edit operations by using truncated messages from the ref
95
+ // Handle edit operations and inject page context
90
96
  prepareSendMessagesRequest: ({ messages: hookMessages }) => {
97
+ const currentPageContext = pageAIContextRef.current;
98
+ const pageContextBody = currentPageContext?.pageDescription ? {
99
+ pageContext: currentPageContext.pageDescription,
100
+ availableTools: Object.keys(
101
+ currentPageContext.clientTools ?? {}
102
+ ),
103
+ routeName: currentPageContext.routeName
104
+ } : {};
91
105
  if (editMessagesRef.current !== null) {
92
106
  const newUserMessage = hookMessages[hookMessages.length - 1];
93
107
  const messagesToSend = [...editMessagesRef.current];
@@ -98,22 +112,63 @@ function ChatInterface({
98
112
  return {
99
113
  body: {
100
114
  messages: messagesToSend,
101
- conversationId: conversationIdRef.current
115
+ conversationId: conversationIdRef.current,
116
+ ...pageContextBody
102
117
  }
103
118
  };
104
119
  }
105
120
  return {
106
121
  body: {
107
122
  messages: hookMessages,
108
- conversationId: conversationIdRef.current
123
+ conversationId: conversationIdRef.current,
124
+ ...pageContextBody
109
125
  }
110
126
  };
111
127
  }
112
128
  }),
113
129
  [apiPath, isPublicMode]
114
130
  );
115
- const { messages, sendMessage, status, error, setMessages, regenerate } = useChat({
131
+ const addToolOutputRef = useRef(null);
132
+ const {
133
+ messages,
134
+ sendMessage,
135
+ status,
136
+ error,
137
+ setMessages,
138
+ regenerate,
139
+ addToolOutput
140
+ } = useChat({
116
141
  transport,
142
+ // Automatically resubmit after all client-side tool results are provided
143
+ sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
144
+ onToolCall: async ({ toolCall }) => {
145
+ const toolName = toolCall.toolName;
146
+ const handler = pageAIContextRef.current?.clientTools?.[toolName];
147
+ if (handler) {
148
+ try {
149
+ const result = await handler(toolCall.input);
150
+ addToolOutputRef.current?.({
151
+ tool: toolName,
152
+ toolCallId: toolCall.toolCallId,
153
+ output: result
154
+ });
155
+ } catch (err) {
156
+ addToolOutputRef.current?.({
157
+ tool: toolName,
158
+ toolCallId: toolCall.toolCallId,
159
+ state: "output-error",
160
+ errorText: err instanceof Error ? err.message : "Tool execution failed"
161
+ });
162
+ }
163
+ } else {
164
+ addToolOutputRef.current?.({
165
+ tool: toolName,
166
+ toolCallId: toolCall.toolCallId,
167
+ state: "output-error",
168
+ errorText: `No client-side handler registered for tool "${toolName}". The page context may have changed while the response was streaming.`
169
+ });
170
+ }
171
+ },
117
172
  onError: (err) => {
118
173
  console.error("useChat onError:", err);
119
174
  if (!id && !hasNavigatedRef.current) {
@@ -136,19 +191,24 @@ function ChatInterface({
136
191
  if (newConversation) {
137
192
  setCurrentConversationId(newConversation.id);
138
193
  conversationIdRef.current = newConversation.id;
139
- const newUrl = `${basePath}/chat/${newConversation.id}`;
140
- if (typeof window !== "undefined") {
141
- window.history.replaceState(
142
- { ...window.history.state },
143
- "",
144
- newUrl
145
- );
194
+ if (variant === "full") {
195
+ const newUrl = `${basePath}/chat/${newConversation.id}`;
196
+ if (typeof window !== "undefined") {
197
+ window.history.replaceState(
198
+ { ...window.history.state },
199
+ "",
200
+ newUrl
201
+ );
202
+ }
146
203
  }
147
204
  }
148
205
  }
149
206
  }
150
207
  }
151
208
  });
209
+ useEffect(() => {
210
+ addToolOutputRef.current = addToolOutput;
211
+ }, [addToolOutput]);
152
212
  useEffect(() => {
153
213
  if (isEditInProgressRef.current) {
154
214
  return;
@@ -311,17 +371,24 @@ function ChatInterface({
311
371
  ),
312
372
  children: [
313
373
  messages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full min-h-[300px]", children: [
314
- /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground", children: /* @__PURE__ */ jsx("p", { children: localization.CHAT_EMPTY_STATE }) }),
315
- chatSuggestions && chatSuggestions.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-2 pb-4 max-w-md mx-auto", children: chatSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx(
316
- "button",
317
- {
318
- type: "button",
319
- onClick: () => setInput(suggestion),
320
- className: "px-3 py-2 text-sm rounded-lg border border-border bg-background hover:bg-accent hover:text-accent-foreground transition-colors text-foreground",
321
- children: suggestion
322
- },
323
- index
324
- )) })
374
+ /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground mb-4", children: /* @__PURE__ */ jsx("p", { children: localization.CHAT_EMPTY_STATE }) }),
375
+ (() => {
376
+ const pageSuggestions = pageAIContext?.suggestions ?? [];
377
+ const allSuggestions = [
378
+ ...pageSuggestions,
379
+ ...chatSuggestions ?? []
380
+ ];
381
+ return allSuggestions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-2 pb-4 max-w-md mx-auto", children: allSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx(
382
+ "button",
383
+ {
384
+ type: "button",
385
+ onClick: () => setInput(suggestion),
386
+ className: "px-3 py-2 text-sm rounded-lg border border-border bg-background hover:bg-accent hover:text-accent-foreground transition-colors text-foreground",
387
+ children: suggestion
388
+ },
389
+ index
390
+ )) }) : null;
391
+ })()
325
392
  ] }) : messages.map((m, index) => /* @__PURE__ */ jsx(
326
393
  ChatMessage,
327
394
  {
@@ -4,26 +4,36 @@
4
4
  const jsxRuntime = require('react/jsx-runtime');
5
5
  const React = require('react');
6
6
  const button = require('../../../../../../ui/src/components/button.cjs');
7
+ const badge = require('../../../../../../ui/src/components/badge.cjs');
7
8
  const sheet = require('../../../../../../ui/src/components/sheet.cjs');
8
9
  const LucideIcons = require('lucide-react');
9
10
  const utils = require('../../../../../../ui/src/lib/utils.cjs');
10
11
  const chatSidebar = require('./chat-sidebar.cjs');
11
12
  const chatInterface = require('./chat-interface.cjs');
13
+ const plugins_aiChat_client_context_pageAiContext = require('../../../../../../../plugins/ai-chat/client/context/page-ai-context.cjs');
12
14
 
13
- function ChatLayout({
14
- apiBaseURL,
15
- apiBasePath,
16
- conversationId,
17
- layout = "full",
18
- className,
19
- showSidebar = true,
20
- widgetHeight = "600px",
21
- initialMessages,
22
- onMessagesChange
23
- }) {
15
+ function ChatLayout(props) {
16
+ const {
17
+ apiBaseURL,
18
+ apiBasePath,
19
+ conversationId,
20
+ layout = "full",
21
+ className,
22
+ showSidebar = true,
23
+ initialMessages,
24
+ onMessagesChange
25
+ } = props;
26
+ const widgetHeight = props.layout === "widget" ? props.widgetHeight ?? "600px" : "600px";
27
+ const widgetWidth = props.layout === "widget" ? props.widgetWidth ?? "380px" : "380px";
28
+ const defaultOpen = props.layout === "widget" ? props.defaultOpen ?? false : false;
29
+ const showTrigger = props.layout === "widget" ? props.showTrigger ?? true : true;
24
30
  const [sidebarOpen, setSidebarOpen] = React.useState(true);
25
31
  const [mobileSidebarOpen, setMobileSidebarOpen] = React.useState(false);
26
32
  const [chatResetKey, setChatResetKey] = React.useState(0);
33
+ const [widgetOpen, setWidgetOpen] = React.useState(defaultOpen);
34
+ const [widgetResetKey, setWidgetResetKey] = React.useState(0);
35
+ const [widgetEverOpened, setWidgetEverOpened] = React.useState(defaultOpen);
36
+ const pageAIContext = plugins_aiChat_client_context_pageAiContext.usePageAIContext();
27
37
  const apiPath = `${apiBaseURL}${apiBasePath}/chat`;
28
38
  const handleNewChat = React.useCallback(() => {
29
39
  if (!conversationId) {
@@ -31,26 +41,81 @@ function ChatLayout({
31
41
  }
32
42
  }, [conversationId]);
33
43
  if (layout === "widget") {
34
- return /* @__PURE__ */ jsxRuntime.jsx(
35
- "div",
36
- {
37
- className: utils.cn(
38
- "flex flex-col w-full border rounded-xl overflow-hidden bg-background shadow-sm",
39
- className
40
- ),
41
- style: { height: widgetHeight },
42
- children: /* @__PURE__ */ jsxRuntime.jsx(
43
- chatInterface.ChatInterface,
44
- {
45
- apiPath,
46
- id: conversationId,
47
- variant: "widget",
48
- initialMessages,
49
- onMessagesChange
50
- }
51
- )
52
- }
53
- );
44
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("flex flex-col items-end gap-3", className), children: [
45
+ /* @__PURE__ */ jsxRuntime.jsxs(
46
+ "div",
47
+ {
48
+ className: utils.cn(
49
+ "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
50
+ widgetOpen ? "flex" : "hidden"
51
+ ),
52
+ style: { height: widgetHeight, width: widgetWidth },
53
+ children: [
54
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
55
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
56
+ pageAIContext ? /* @__PURE__ */ jsxRuntime.jsx(
57
+ badge.Badge,
58
+ {
59
+ variant: "secondary",
60
+ className: "text-xs",
61
+ "data-testid": "page-context-badge",
62
+ children: pageAIContext.routeName
63
+ }
64
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground font-medium", children: "AI Chat" }),
65
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
66
+ /* @__PURE__ */ jsxRuntime.jsx(
67
+ button.Button,
68
+ {
69
+ variant: "ghost",
70
+ size: "icon",
71
+ className: "h-5 w-5",
72
+ onClick: () => setWidgetResetKey((prev) => prev + 1),
73
+ "aria-label": "Clear chat",
74
+ title: "Clear chat",
75
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Trash2, { className: "h-3.5 w-3.5" })
76
+ }
77
+ ),
78
+ /* @__PURE__ */ jsxRuntime.jsx(
79
+ button.Button,
80
+ {
81
+ variant: "ghost",
82
+ size: "icon",
83
+ className: "h-5 w-5",
84
+ onClick: () => setWidgetOpen(false),
85
+ "aria-label": "Close chat",
86
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-3.5 w-3.5" })
87
+ }
88
+ )
89
+ ] }),
90
+ widgetEverOpened && /* @__PURE__ */ jsxRuntime.jsx(
91
+ chatInterface.ChatInterface,
92
+ {
93
+ apiPath,
94
+ id: conversationId,
95
+ variant: "widget",
96
+ initialMessages,
97
+ onMessagesChange
98
+ },
99
+ `widget-${conversationId ?? "new"}-${widgetResetKey}`
100
+ )
101
+ ]
102
+ }
103
+ ),
104
+ showTrigger && /* @__PURE__ */ jsxRuntime.jsx(
105
+ button.Button,
106
+ {
107
+ size: "icon",
108
+ className: "h-12 w-12 rounded-full shadow-lg",
109
+ onClick: () => {
110
+ setWidgetOpen((prev) => !prev);
111
+ setWidgetEverOpened(true);
112
+ },
113
+ "aria-label": widgetOpen ? "Close chat" : "Open chat",
114
+ "data-testid": "widget-trigger",
115
+ children: widgetOpen ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-5 w-5" })
116
+ }
117
+ )
118
+ ] });
54
119
  }
55
120
  return /* @__PURE__ */ jsxRuntime.jsxs(
56
121
  "div",
@@ -79,7 +144,7 @@ function ChatLayout({
79
144
  }
80
145
  ),
81
146
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
82
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60", children: [
147
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 p-2 border-b bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60", children: [
83
148
  showSidebar && /* @__PURE__ */ jsxRuntime.jsxs(sheet.Sheet, { open: mobileSidebarOpen, onOpenChange: setMobileSidebarOpen, children: [
84
149
  /* @__PURE__ */ jsxRuntime.jsx(sheet.SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
85
150
  button.Button,
@@ -113,7 +178,19 @@ function ChatLayout({
113
178
  children: sidebarOpen ? /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.PanelLeftClose, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.PanelLeft, { className: "h-5 w-5" })
114
179
  }
115
180
  ),
116
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" })
181
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
182
+ pageAIContext && /* @__PURE__ */ jsxRuntime.jsxs(
183
+ badge.Badge,
184
+ {
185
+ variant: "secondary",
186
+ className: "text-xs gap-1 mr-2",
187
+ "data-testid": "page-context-badge",
188
+ children: [
189
+ /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Sparkles, { className: "h-3 w-3" }),
190
+ pageAIContext.routeName
191
+ ]
192
+ }
193
+ )
117
194
  ] }),
118
195
  /* @__PURE__ */ jsxRuntime.jsx(
119
196
  chatInterface.ChatInterface,
@@ -1,27 +1,37 @@
1
1
  "use client";
2
- import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { useState, useCallback } from 'react';
4
4
  import { Button } from '../../../../../../ui/src/components/button.mjs';
5
+ import { Badge } from '../../../../../../ui/src/components/badge.mjs';
5
6
  import { Sheet, SheetTrigger, SheetContent } from '../../../../../../ui/src/components/sheet.mjs';
6
- import { Menu, PanelLeftClose, PanelLeft } from 'lucide-react';
7
+ import { Sparkles, Trash2, X, Menu, PanelLeftClose, PanelLeft } from 'lucide-react';
7
8
  import { cn } from '../../../../../../ui/src/lib/utils.mjs';
8
9
  import { ChatSidebar } from './chat-sidebar.mjs';
9
10
  import { ChatInterface } from './chat-interface.mjs';
11
+ import { usePageAIContext } from '../../../../../../../plugins/ai-chat/client/context/page-ai-context.mjs';
10
12
 
11
- function ChatLayout({
12
- apiBaseURL,
13
- apiBasePath,
14
- conversationId,
15
- layout = "full",
16
- className,
17
- showSidebar = true,
18
- widgetHeight = "600px",
19
- initialMessages,
20
- onMessagesChange
21
- }) {
13
+ function ChatLayout(props) {
14
+ const {
15
+ apiBaseURL,
16
+ apiBasePath,
17
+ conversationId,
18
+ layout = "full",
19
+ className,
20
+ showSidebar = true,
21
+ initialMessages,
22
+ onMessagesChange
23
+ } = props;
24
+ const widgetHeight = props.layout === "widget" ? props.widgetHeight ?? "600px" : "600px";
25
+ const widgetWidth = props.layout === "widget" ? props.widgetWidth ?? "380px" : "380px";
26
+ const defaultOpen = props.layout === "widget" ? props.defaultOpen ?? false : false;
27
+ const showTrigger = props.layout === "widget" ? props.showTrigger ?? true : true;
22
28
  const [sidebarOpen, setSidebarOpen] = useState(true);
23
29
  const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
24
30
  const [chatResetKey, setChatResetKey] = useState(0);
31
+ const [widgetOpen, setWidgetOpen] = useState(defaultOpen);
32
+ const [widgetResetKey, setWidgetResetKey] = useState(0);
33
+ const [widgetEverOpened, setWidgetEverOpened] = useState(defaultOpen);
34
+ const pageAIContext = usePageAIContext();
25
35
  const apiPath = `${apiBaseURL}${apiBasePath}/chat`;
26
36
  const handleNewChat = useCallback(() => {
27
37
  if (!conversationId) {
@@ -29,26 +39,81 @@ function ChatLayout({
29
39
  }
30
40
  }, [conversationId]);
31
41
  if (layout === "widget") {
32
- return /* @__PURE__ */ jsx(
33
- "div",
34
- {
35
- className: cn(
36
- "flex flex-col w-full border rounded-xl overflow-hidden bg-background shadow-sm",
37
- className
38
- ),
39
- style: { height: widgetHeight },
40
- children: /* @__PURE__ */ jsx(
41
- ChatInterface,
42
- {
43
- apiPath,
44
- id: conversationId,
45
- variant: "widget",
46
- initialMessages,
47
- onMessagesChange
48
- }
49
- )
50
- }
51
- );
42
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col items-end gap-3", className), children: [
43
+ /* @__PURE__ */ jsxs(
44
+ "div",
45
+ {
46
+ className: cn(
47
+ "flex flex-col border rounded-xl overflow-hidden bg-background shadow-xl",
48
+ widgetOpen ? "flex" : "hidden"
49
+ ),
50
+ style: { height: widgetHeight, width: widgetWidth },
51
+ children: [
52
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-3 py-1.5 border-b bg-muted/40", children: [
53
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
54
+ pageAIContext ? /* @__PURE__ */ jsx(
55
+ Badge,
56
+ {
57
+ variant: "secondary",
58
+ className: "text-xs",
59
+ "data-testid": "page-context-badge",
60
+ children: pageAIContext.routeName
61
+ }
62
+ ) : /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-medium", children: "AI Chat" }),
63
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
64
+ /* @__PURE__ */ jsx(
65
+ Button,
66
+ {
67
+ variant: "ghost",
68
+ size: "icon",
69
+ className: "h-5 w-5",
70
+ onClick: () => setWidgetResetKey((prev) => prev + 1),
71
+ "aria-label": "Clear chat",
72
+ title: "Clear chat",
73
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
74
+ }
75
+ ),
76
+ /* @__PURE__ */ jsx(
77
+ Button,
78
+ {
79
+ variant: "ghost",
80
+ size: "icon",
81
+ className: "h-5 w-5",
82
+ onClick: () => setWidgetOpen(false),
83
+ "aria-label": "Close chat",
84
+ children: /* @__PURE__ */ jsx(X, { className: "h-3.5 w-3.5" })
85
+ }
86
+ )
87
+ ] }),
88
+ widgetEverOpened && /* @__PURE__ */ jsx(
89
+ ChatInterface,
90
+ {
91
+ apiPath,
92
+ id: conversationId,
93
+ variant: "widget",
94
+ initialMessages,
95
+ onMessagesChange
96
+ },
97
+ `widget-${conversationId ?? "new"}-${widgetResetKey}`
98
+ )
99
+ ]
100
+ }
101
+ ),
102
+ showTrigger && /* @__PURE__ */ jsx(
103
+ Button,
104
+ {
105
+ size: "icon",
106
+ className: "h-12 w-12 rounded-full shadow-lg",
107
+ onClick: () => {
108
+ setWidgetOpen((prev) => !prev);
109
+ setWidgetEverOpened(true);
110
+ },
111
+ "aria-label": widgetOpen ? "Close chat" : "Open chat",
112
+ "data-testid": "widget-trigger",
113
+ children: widgetOpen ? /* @__PURE__ */ jsx(X, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Sparkles, { className: "h-5 w-5" })
114
+ }
115
+ )
116
+ ] });
52
117
  }
53
118
  return /* @__PURE__ */ jsxs(
54
119
  "div",
@@ -77,7 +142,7 @@ function ChatLayout({
77
142
  }
78
143
  ),
79
144
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0", children: [
80
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60", children: [
145
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 p-2 border-b bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60", children: [
81
146
  showSidebar && /* @__PURE__ */ jsxs(Sheet, { open: mobileSidebarOpen, onOpenChange: setMobileSidebarOpen, children: [
82
147
  /* @__PURE__ */ jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
83
148
  Button,
@@ -111,7 +176,19 @@ function ChatLayout({
111
176
  children: sidebarOpen ? /* @__PURE__ */ jsx(PanelLeftClose, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(PanelLeft, { className: "h-5 w-5" })
112
177
  }
113
178
  ),
114
- /* @__PURE__ */ jsx("div", { className: "flex-1" })
179
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
180
+ pageAIContext && /* @__PURE__ */ jsxs(
181
+ Badge,
182
+ {
183
+ variant: "secondary",
184
+ className: "text-xs gap-1 mr-2",
185
+ "data-testid": "page-context-badge",
186
+ children: [
187
+ /* @__PURE__ */ jsx(Sparkles, { className: "h-3 w-3" }),
188
+ pageAIContext.routeName
189
+ ]
190
+ }
191
+ )
115
192
  ] }),
116
193
  /* @__PURE__ */ jsx(
117
194
  ChatInterface,
@@ -108,7 +108,7 @@ function ChatSidebar({
108
108
  ]
109
109
  }
110
110
  ) }),
111
- /* @__PURE__ */ jsxRuntime.jsx(scrollArea.ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.CHAT_LOADING }) : conversations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.SIDEBAR_NO_CONVERSATIONS }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: conversations.map((conversation) => /* @__PURE__ */ jsxRuntime.jsxs(
111
+ /* @__PURE__ */ jsxRuntime.jsx(scrollArea.ScrollArea, { className: "flex-1 [&_[data-slot=scroll-area-viewport]>div]:!block", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-2", children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.CHAT_LOADING }) : conversations.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.SIDEBAR_NO_CONVERSATIONS }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: conversations.map((conversation) => /* @__PURE__ */ jsxRuntime.jsxs(
112
112
  "div",
113
113
  {
114
114
  className: utils.cn(
@@ -106,7 +106,7 @@ function ChatSidebar({
106
106
  ]
107
107
  }
108
108
  ) }),
109
- /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsx("div", { className: "p-2", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.CHAT_LOADING }) : conversations.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.SIDEBAR_NO_CONVERSATIONS }) : /* @__PURE__ */ jsx("div", { className: "space-y-1", children: conversations.map((conversation) => /* @__PURE__ */ jsxs(
109
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1 [&_[data-slot=scroll-area-viewport]>div]:!block", children: /* @__PURE__ */ jsx("div", { className: "p-2", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.CHAT_LOADING }) : conversations.length === 0 ? /* @__PURE__ */ jsx("div", { className: "p-4 text-center text-sm text-muted-foreground", children: localization.SIDEBAR_NO_CONVERSATIONS }) : /* @__PURE__ */ jsx("div", { className: "space-y-1", children: conversations.map((conversation) => /* @__PURE__ */ jsxs(
110
110
  "div",
111
111
  {
112
112
  className: cn(
@@ -34,7 +34,23 @@ const chatRequestSchema = z.z.object({
34
34
  ])
35
35
  ),
36
36
  conversationId: z.z.string().optional(),
37
- model: z.z.string().optional()
37
+ model: z.z.string().optional(),
38
+ /**
39
+ * Description of the current page context, injected into the AI system prompt.
40
+ * Sent by ChatInterface when a page has registered context via useRegisterPageAIContext.
41
+ */
42
+ pageContext: z.z.string().max(16e3).optional(),
43
+ /**
44
+ * Names of client-side tools currently available on the page.
45
+ * The server includes matching tool schemas in the streamText call.
46
+ */
47
+ availableTools: z.z.array(z.z.string()).optional(),
48
+ /**
49
+ * The routeName registered by the page via useRegisterPageAIContext.
50
+ * Cross-validated server-side against each built-in tool's route allowlist
51
+ * to prevent a page from claiming tools intended for a different route.
52
+ */
53
+ routeName: z.z.string().optional()
38
54
  });
39
55
 
40
56
  exports.chatRequestSchema = chatRequestSchema;
@@ -32,7 +32,23 @@ const chatRequestSchema = z.object({
32
32
  ])
33
33
  ),
34
34
  conversationId: z.string().optional(),
35
- model: z.string().optional()
35
+ model: z.string().optional(),
36
+ /**
37
+ * Description of the current page context, injected into the AI system prompt.
38
+ * Sent by ChatInterface when a page has registered context via useRegisterPageAIContext.
39
+ */
40
+ pageContext: z.string().max(16e3).optional(),
41
+ /**
42
+ * Names of client-side tools currently available on the page.
43
+ * The server includes matching tool schemas in the streamText call.
44
+ */
45
+ availableTools: z.array(z.string()).optional(),
46
+ /**
47
+ * The routeName registered by the page via useRegisterPageAIContext.
48
+ * Cross-validated server-side against each built-in tool's route allowlist
49
+ * to prevent a page from claiming tools intended for a different route.
50
+ */
51
+ routeName: z.string().optional()
36
52
  });
37
53
 
38
54
  export { chatRequestSchema, createConversationSchema, updateConversationSchema };