@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.
- 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/api/plugin.cjs +52 -1
- package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +52 -1
- package/dist/packages/stack/src/plugins/blog/api/query-key-defs.cjs +18 -0
- package/dist/packages/stack/src/plugins/blog/api/query-key-defs.mjs +15 -0
- package/dist/packages/stack/src/plugins/blog/api/serializers.cjs +21 -0
- package/dist/packages/stack/src/plugins/blog/api/serializers.mjs +18 -0
- 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/blog/client/plugin.cjs +15 -0
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +16 -1
- package/dist/packages/stack/src/plugins/cms/api/getters.cjs +10 -0
- package/dist/packages/stack/src/plugins/cms/api/getters.mjs +10 -1
- 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 +75 -0
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +76 -1
- package/dist/packages/stack/src/plugins/cms/api/query-key-defs.cjs +29 -0
- package/dist/packages/stack/src/plugins/cms/api/query-key-defs.mjs +26 -0
- package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +15 -0
- package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +16 -1
- package/dist/packages/stack/src/plugins/form-builder/api/getters.cjs +9 -0
- package/dist/packages/stack/src/plugins/form-builder/api/getters.mjs +9 -1
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +62 -1
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +63 -2
- package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.cjs +37 -0
- package/dist/packages/stack/src/plugins/form-builder/api/query-key-defs.mjs +33 -0
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +15 -0
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +16 -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 +34 -1
- package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +34 -1
- package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.cjs +26 -0
- package/dist/packages/stack/src/plugins/kanban/api/query-key-defs.mjs +23 -0
- package/dist/packages/stack/src/plugins/kanban/api/serializers.cjs +30 -0
- package/dist/packages/stack/src/plugins/kanban/api/serializers.mjs +26 -0
- 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/kanban/client/plugin.cjs +10 -0
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +11 -1
- 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/packages/stack/src/plugins/utils.cjs +6 -0
- package/dist/packages/stack/src/plugins/utils.mjs +6 -1
- 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.cjs +5 -0
- package/dist/plugins/blog/api/index.d.cts +19 -4
- package/dist/plugins/blog/api/index.d.mts +19 -4
- package/dist/plugins/blog/api/index.d.ts +19 -4
- package/dist/plugins/blog/api/index.mjs +2 -0
- package/dist/plugins/blog/client/hooks/index.d.cts +3 -3
- package/dist/plugins/blog/client/hooks/index.d.mts +3 -3
- package/dist/plugins/blog/client/hooks/index.d.ts +3 -3
- 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.cjs +6 -5
- package/dist/plugins/blog/query-keys.d.cts +8 -387
- package/dist/plugins/blog/query-keys.d.mts +8 -387
- package/dist/plugins/blog/query-keys.d.ts +8 -387
- package/dist/plugins/blog/query-keys.mjs +6 -5
- package/dist/plugins/client/index.cjs +1 -0
- package/dist/plugins/client/index.d.cts +8 -1
- package/dist/plugins/client/index.d.mts +8 -1
- package/dist/plugins/client/index.d.ts +8 -1
- package/dist/plugins/client/index.mjs +1 -1
- package/dist/plugins/cms/api/index.cjs +8 -0
- package/dist/plugins/cms/api/index.d.cts +7 -219
- package/dist/plugins/cms/api/index.d.mts +7 -219
- package/dist/plugins/cms/api/index.d.ts +7 -219
- package/dist/plugins/cms/api/index.mjs +3 -1
- package/dist/plugins/cms/client/hooks/index.d.cts +1 -1
- package/dist/plugins/cms/client/hooks/index.d.mts +1 -1
- package/dist/plugins/cms/client/hooks/index.d.ts +1 -1
- package/dist/plugins/cms/query-keys.cjs +2 -1
- package/dist/plugins/cms/query-keys.d.cts +5 -9
- package/dist/plugins/cms/query-keys.d.mts +5 -9
- package/dist/plugins/cms/query-keys.d.ts +5 -9
- package/dist/plugins/cms/query-keys.mjs +2 -1
- package/dist/plugins/form-builder/api/index.cjs +6 -0
- package/dist/plugins/form-builder/api/index.d.cts +7 -211
- package/dist/plugins/form-builder/api/index.d.mts +7 -211
- package/dist/plugins/form-builder/api/index.d.ts +7 -211
- package/dist/plugins/form-builder/api/index.mjs +2 -1
- package/dist/plugins/form-builder/client/components/index.d.cts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.mts +1 -1
- package/dist/plugins/form-builder/client/components/index.d.ts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.cts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.mts +1 -1
- package/dist/plugins/form-builder/client/hooks/index.d.ts +1 -1
- package/dist/plugins/form-builder/query-keys.cjs +3 -2
- package/dist/plugins/form-builder/query-keys.d.cts +6 -6
- package/dist/plugins/form-builder/query-keys.d.mts +6 -6
- package/dist/plugins/form-builder/query-keys.d.ts +6 -6
- package/dist/plugins/form-builder/query-keys.mjs +3 -2
- package/dist/plugins/kanban/api/index.cjs +10 -0
- package/dist/plugins/kanban/api/index.d.cts +17 -392
- package/dist/plugins/kanban/api/index.d.mts +17 -392
- package/dist/plugins/kanban/api/index.d.ts +17 -392
- package/dist/plugins/kanban/api/index.mjs +3 -0
- package/dist/plugins/kanban/client/components/index.d.cts +1 -1
- package/dist/plugins/kanban/client/components/index.d.mts +1 -1
- package/dist/plugins/kanban/client/components/index.d.ts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.cts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.mts +1 -1
- package/dist/plugins/kanban/client/hooks/index.d.ts +1 -1
- package/dist/plugins/kanban/client/index.d.cts +1 -1
- package/dist/plugins/kanban/client/index.d.mts +1 -1
- package/dist/plugins/kanban/client/index.d.ts +1 -1
- package/dist/plugins/kanban/query-keys.cjs +2 -9
- package/dist/plugins/kanban/query-keys.d.cts +4 -16
- package/dist/plugins/kanban/query-keys.d.mts +4 -16
- package/dist/plugins/kanban/query-keys.d.ts +4 -16
- package/dist/plugins/kanban/query-keys.mjs +2 -9
- package/dist/plugins/ui-builder/index.d.cts +1 -1
- package/dist/plugins/ui-builder/index.d.mts +1 -1
- package/dist/plugins/ui-builder/index.d.ts +1 -1
- package/dist/shared/stack.B7ONvlD_.d.mts +293 -0
- package/dist/shared/{stack.BeSm90va.d.ts → stack.BEn34wW6.d.ts} +60 -2
- package/dist/shared/stack.BUkC2EsZ.d.cts +327 -0
- 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.BepFXT3w.d.mts +500 -0
- package/dist/shared/stack.CL8ts1Mu.d.ts +419 -0
- package/dist/shared/{stack.CXjzTMsb.d.cts → stack.CVDTkMoO.d.cts} +7 -1
- package/dist/shared/{stack.CXjzTMsb.d.mts → stack.CVDTkMoO.d.mts} +7 -1
- package/dist/shared/{stack.CXjzTMsb.d.ts → stack.CVDTkMoO.d.ts} +7 -1
- package/dist/shared/stack.CczspVn2.d.mts +327 -0
- package/dist/shared/stack.CgWzG5jH.d.ts +500 -0
- package/dist/shared/stack.D3GB6wKv.d.cts +500 -0
- package/dist/shared/stack.DASmUVjX.d.ts +327 -0
- package/dist/shared/{stack.QD1y_7NY.d.cts → stack.DJaKVY7v.d.cts} +1 -1
- package/dist/shared/{stack.QD1y_7NY.d.mts → stack.DJaKVY7v.d.mts} +1 -1
- package/dist/shared/{stack.QD1y_7NY.d.ts → stack.DJaKVY7v.d.ts} +1 -1
- 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.CIrIsc-A.d.cts → stack.DdI5W6MB.d.cts} +7 -1
- package/dist/shared/{stack.CIrIsc-A.d.mts → stack.DdI5W6MB.d.mts} +7 -1
- package/dist/shared/{stack.CIrIsc-A.d.ts → stack.DdI5W6MB.d.ts} +7 -1
- package/dist/shared/stack.Dk5r4W1F.d.mts +419 -0
- package/dist/shared/stack.Kq2-QzOC.d.ts +293 -0
- package/dist/shared/stack.heOA9gzA.d.cts +419 -0
- package/dist/shared/stack.kcdnD4gA.d.cts +293 -0
- package/package.json +16 -3
- 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/api/index.ts +2 -0
- package/src/plugins/blog/api/plugin.ts +85 -0
- package/src/plugins/blog/api/query-key-defs.ts +46 -0
- package/src/plugins/blog/api/serializers.ts +27 -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/blog/client/plugin.tsx +19 -0
- package/src/plugins/blog/query-keys.ts +5 -7
- package/src/plugins/client/index.ts +1 -1
- package/src/plugins/cms/api/getters.ts +24 -0
- package/src/plugins/cms/api/index.ts +14 -1
- package/src/plugins/cms/api/mutations.ts +84 -0
- package/src/plugins/cms/api/plugin.ts +114 -0
- package/src/plugins/cms/api/query-key-defs.ts +53 -0
- package/src/plugins/cms/api/serializers.ts +12 -0
- package/src/plugins/cms/client/plugin.tsx +19 -0
- package/src/plugins/cms/query-keys.ts +2 -1
- package/src/plugins/form-builder/api/getters.ts +23 -0
- package/src/plugins/form-builder/api/index.ts +15 -2
- package/src/plugins/form-builder/api/plugin.ts +91 -0
- package/src/plugins/form-builder/api/query-key-defs.ts +79 -0
- package/src/plugins/form-builder/api/serializers.ts +12 -0
- package/src/plugins/form-builder/client/plugin.tsx +19 -0
- package/src/plugins/form-builder/query-keys.ts +6 -2
- package/src/plugins/kanban/api/index.ts +9 -0
- package/src/plugins/kanban/api/mutations.ts +169 -0
- package/src/plugins/kanban/api/plugin.ts +61 -0
- package/src/plugins/kanban/api/query-key-defs.ts +54 -0
- package/src/plugins/kanban/api/serializers.ts +49 -0
- package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
- package/src/plugins/kanban/client/plugin.tsx +13 -0
- package/src/plugins/kanban/query-keys.ts +2 -9
- package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
- package/src/plugins/utils.ts +19 -0
- package/dist/shared/{stack.BkYlUT_8.d.cts → stack.BQmuNl5p.d.cts} +6 -6
- package/dist/shared/{stack.BkYlUT_8.d.mts → stack.BQmuNl5p.d.mts} +6 -6
- 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
|
|
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 };
|