@btst/stack 2.3.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.
- package/dist/packages/stack/src/client/components/compose.cjs +1 -2
- package/dist/packages/stack/src/client/components/compose.mjs +1 -2
- package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.cjs +71 -0
- package/dist/packages/stack/src/plugins/ai-chat/api/page-tools.mjs +68 -0
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.cjs +54 -7
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +54 -7
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.cjs +2 -2
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-input.mjs +2 -2
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.cjs +89 -22
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-interface.mjs +90 -23
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.cjs +110 -33
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-layout.mjs +112 -35
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.cjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/client/components/chat-sidebar.mjs +1 -1
- package/dist/packages/stack/src/plugins/ai-chat/schemas.cjs +17 -1
- package/dist/packages/stack/src/plugins/ai-chat/schemas.mjs +17 -1
- package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.cjs +15 -2
- package/dist/packages/stack/src/plugins/blog/client/components/forms/post-forms.mjs +16 -3
- package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.cjs +24 -1
- package/dist/packages/stack/src/plugins/blog/client/components/pages/edit-post-page.internal.mjs +24 -1
- package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.cjs +26 -0
- package/dist/packages/stack/src/plugins/blog/client/components/pages/fill-blog-form-handler.mjs +24 -0
- package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.cjs +30 -1
- package/dist/packages/stack/src/plugins/blog/client/components/pages/new-post-page.internal.mjs +30 -1
- package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.cjs +18 -0
- package/dist/packages/stack/src/plugins/blog/client/components/pages/post-page.internal.mjs +18 -0
- package/dist/packages/stack/src/plugins/cms/api/mutations.cjs +48 -0
- package/dist/packages/stack/src/plugins/cms/api/mutations.mjs +46 -0
- package/dist/packages/stack/src/plugins/cms/api/plugin.cjs +7 -1
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +7 -1
- package/dist/packages/stack/src/plugins/kanban/api/mutations.cjs +91 -0
- package/dist/packages/stack/src/plugins/kanban/api/mutations.mjs +87 -0
- package/dist/packages/stack/src/plugins/kanban/api/plugin.cjs +6 -1
- package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +6 -1
- package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.cjs +7 -3
- package/dist/packages/stack/src/plugins/kanban/client/hooks/kanban-hooks.mjs +7 -3
- package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.cjs +89 -0
- package/dist/packages/stack/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.mjs +89 -0
- package/dist/plugins/ai-chat/api/index.d.cts +1 -1
- package/dist/plugins/ai-chat/api/index.d.mts +1 -1
- package/dist/plugins/ai-chat/api/index.d.ts +1 -1
- package/dist/plugins/ai-chat/client/components/index.d.cts +1 -1
- package/dist/plugins/ai-chat/client/components/index.d.mts +1 -1
- package/dist/plugins/ai-chat/client/components/index.d.ts +1 -1
- package/dist/plugins/ai-chat/client/context/page-ai-context.cjs +92 -0
- package/dist/plugins/ai-chat/client/context/page-ai-context.d.cts +84 -0
- package/dist/plugins/ai-chat/client/context/page-ai-context.d.mts +84 -0
- package/dist/plugins/ai-chat/client/context/page-ai-context.d.ts +84 -0
- package/dist/plugins/ai-chat/client/context/page-ai-context.mjs +88 -0
- package/dist/plugins/ai-chat/client/hooks/index.d.cts +1 -1
- package/dist/plugins/ai-chat/client/hooks/index.d.mts +1 -1
- package/dist/plugins/ai-chat/client/hooks/index.d.ts +1 -1
- package/dist/plugins/ai-chat/client/index.d.cts +2 -2
- package/dist/plugins/ai-chat/client/index.d.mts +2 -2
- package/dist/plugins/ai-chat/client/index.d.ts +2 -2
- package/dist/plugins/ai-chat/query-keys.d.cts +1 -1
- package/dist/plugins/ai-chat/query-keys.d.mts +1 -1
- package/dist/plugins/ai-chat/query-keys.d.ts +1 -1
- package/dist/plugins/blog/api/index.d.cts +2 -2
- package/dist/plugins/blog/api/index.d.mts +2 -2
- package/dist/plugins/blog/api/index.d.ts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.cts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.mts +2 -2
- package/dist/plugins/blog/client/hooks/index.d.ts +2 -2
- package/dist/plugins/blog/client/index.d.cts +1 -1
- package/dist/plugins/blog/client/index.d.mts +1 -1
- package/dist/plugins/blog/client/index.d.ts +1 -1
- package/dist/plugins/blog/query-keys.d.cts +2 -2
- package/dist/plugins/blog/query-keys.d.mts +2 -2
- package/dist/plugins/blog/query-keys.d.ts +2 -2
- package/dist/plugins/cms/api/index.cjs +2 -0
- package/dist/plugins/cms/api/index.d.cts +1 -1
- package/dist/plugins/cms/api/index.d.mts +1 -1
- package/dist/plugins/cms/api/index.d.ts +1 -1
- package/dist/plugins/cms/api/index.mjs +1 -0
- package/dist/plugins/cms/query-keys.d.cts +1 -1
- package/dist/plugins/cms/query-keys.d.mts +1 -1
- package/dist/plugins/cms/query-keys.d.ts +1 -1
- package/dist/plugins/form-builder/api/index.d.cts +1 -1
- package/dist/plugins/form-builder/api/index.d.mts +1 -1
- package/dist/plugins/form-builder/api/index.d.ts +1 -1
- package/dist/plugins/form-builder/query-keys.d.cts +1 -1
- package/dist/plugins/form-builder/query-keys.d.mts +1 -1
- package/dist/plugins/form-builder/query-keys.d.ts +1 -1
- package/dist/plugins/kanban/api/index.cjs +4 -0
- package/dist/plugins/kanban/api/index.d.cts +1 -1
- package/dist/plugins/kanban/api/index.d.mts +1 -1
- package/dist/plugins/kanban/api/index.d.ts +1 -1
- package/dist/plugins/kanban/api/index.mjs +1 -0
- package/dist/plugins/kanban/query-keys.d.cts +1 -1
- package/dist/plugins/kanban/query-keys.d.mts +1 -1
- package/dist/plugins/kanban/query-keys.d.ts +1 -1
- package/dist/shared/{stack.BeSm90va.d.ts → stack.BEn34wW6.d.ts} +60 -2
- package/dist/shared/{stack.IdtKDRka.d.cts → stack.BUkC2EsZ.d.cts} +32 -2
- package/dist/shared/{stack.DaOcgmrM.d.ts → stack.BV9hnvu4.d.cts} +31 -7
- package/dist/shared/{stack.DaOcgmrM.d.cts → stack.BV9hnvu4.d.mts} +31 -7
- package/dist/shared/{stack.DaOcgmrM.d.mts → stack.BV9hnvu4.d.ts} +31 -7
- package/dist/shared/{stack.rTy7-wQU.d.mts → stack.BepFXT3w.d.mts} +70 -15
- package/dist/shared/{stack.BKfolAyK.d.ts → stack.CL8ts1Mu.d.ts} +3 -3
- package/dist/shared/{stack.CP68pFEH.d.mts → stack.CczspVn2.d.mts} +32 -2
- package/dist/shared/{stack.TIBF2AOx.d.ts → stack.CgWzG5jH.d.ts} +70 -15
- package/dist/shared/{stack.BpolpQpf.d.cts → stack.D3GB6wKv.d.cts} +70 -15
- package/dist/shared/{stack.B1EeBt1b.d.ts → stack.DASmUVjX.d.ts} +32 -2
- package/dist/shared/{stack.Dg09R0oB.d.mts → stack.DTDxgFj8.d.mts} +60 -2
- package/dist/shared/{stack.CMh_EdxW.d.cts → stack.DWoCZff7.d.cts} +60 -2
- package/dist/shared/{stack.snB1EDP7.d.cts → stack.Dk5r4W1F.d.mts} +3 -3
- package/dist/shared/{stack.BIXEI6v_.d.mts → stack.heOA9gzA.d.cts} +3 -3
- package/package.json +14 -1
- package/src/client/components/compose.tsx +7 -4
- package/src/plugins/ai-chat/api/page-tools.ts +111 -0
- package/src/plugins/ai-chat/api/plugin.ts +180 -9
- package/src/plugins/ai-chat/client/components/chat-input.tsx +2 -2
- package/src/plugins/ai-chat/client/components/chat-interface.tsx +154 -58
- package/src/plugins/ai-chat/client/components/chat-layout.tsx +166 -32
- package/src/plugins/ai-chat/client/components/chat-sidebar.tsx +1 -1
- package/src/plugins/ai-chat/client/context/page-ai-context.tsx +240 -0
- package/src/plugins/ai-chat/schemas.ts +16 -0
- package/src/plugins/blog/client/components/forms/post-forms.tsx +29 -2
- package/src/plugins/blog/client/components/pages/edit-post-page.internal.tsx +28 -0
- package/src/plugins/blog/client/components/pages/fill-blog-form-handler.ts +38 -0
- package/src/plugins/blog/client/components/pages/new-post-page.internal.tsx +33 -1
- package/src/plugins/blog/client/components/pages/post-page.internal.tsx +20 -0
- package/src/plugins/cms/api/index.ts +4 -0
- package/src/plugins/cms/api/mutations.ts +84 -0
- package/src/plugins/cms/api/plugin.ts +9 -0
- package/src/plugins/kanban/api/index.ts +6 -0
- package/src/plugins/kanban/api/mutations.ts +169 -0
- package/src/plugins/kanban/api/plugin.ts +12 -0
- package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
- package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
- package/dist/shared/{stack.C5dtIncc.d.mts → stack.B7ONvlD_.d.mts} +1 -1
- package/dist/shared/{stack.CBON0dWL.d.cts → stack.BQmuNl5p.d.cts} +2 -2
- package/dist/shared/{stack.CBON0dWL.d.mts → stack.BQmuNl5p.d.mts} +2 -2
- package/dist/shared/{stack.CBON0dWL.d.ts → stack.BQmuNl5p.d.ts} +2 -2
- package/dist/shared/{stack.CIP6QS9l.d.ts → stack.Kq2-QzOC.d.ts} +1 -1
- package/dist/shared/{stack.Dw0Ly2TM.d.cts → stack.kcdnD4gA.d.cts} +1 -1
|
@@ -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
|
|
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
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
window
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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-
|
|
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 {
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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__ */
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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-
|
|
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 };
|