@btst/stack 2.3.0 → 2.5.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 +87 -54
- package/dist/packages/stack/src/plugins/ai-chat/api/plugin.mjs +87 -54
- 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/client/plugin.cjs +14 -21
- package/dist/packages/stack/src/plugins/ai-chat/client/plugin.mjs +15 -22
- 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 +28 -45
- package/dist/packages/stack/src/plugins/blog/api/plugin.mjs +22 -39
- 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 +23 -27
- package/dist/packages/stack/src/plugins/blog/client/plugin.mjs +24 -28
- 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 +21 -18
- package/dist/packages/stack/src/plugins/cms/api/plugin.mjs +21 -18
- package/dist/packages/stack/src/plugins/cms/client/plugin.cjs +11 -15
- package/dist/packages/stack/src/plugins/cms/client/plugin.mjs +12 -16
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.cjs +58 -62
- package/dist/packages/stack/src/plugins/form-builder/api/plugin.mjs +58 -62
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.cjs +12 -12
- package/dist/packages/stack/src/plugins/form-builder/client/plugin.mjs +13 -13
- 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 +92 -118
- package/dist/packages/stack/src/plugins/kanban/api/plugin.mjs +89 -115
- 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 +22 -29
- package/dist/packages/stack/src/plugins/kanban/client/plugin.mjs +23 -30
- 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/ui-builder/client/plugin.cjs +8 -8
- package/dist/packages/stack/src/plugins/ui-builder/client/plugin.mjs +9 -9
- package/dist/packages/stack/src/plugins/utils.cjs +42 -0
- package/dist/packages/stack/src/plugins/utils.mjs +41 -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 +10 -10
- package/dist/plugins/ai-chat/client/index.d.mts +10 -10
- package/dist/plugins/ai-chat/client/index.d.ts +10 -10
- 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 +13 -13
- package/dist/plugins/blog/client/index.d.mts +13 -13
- package/dist/plugins/blog/client/index.d.ts +13 -13
- 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/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 +2 -0
- package/dist/plugins/cms/api/index.d.cts +2 -2
- package/dist/plugins/cms/api/index.d.mts +2 -2
- package/dist/plugins/cms/api/index.d.ts +2 -2
- package/dist/plugins/cms/api/index.mjs +1 -0
- 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/client/index.d.cts +6 -6
- package/dist/plugins/cms/client/index.d.mts +6 -6
- package/dist/plugins/cms/client/index.d.ts +6 -6
- package/dist/plugins/cms/query-keys.d.cts +2 -2
- package/dist/plugins/cms/query-keys.d.mts +2 -2
- package/dist/plugins/cms/query-keys.d.ts +2 -2
- package/dist/plugins/form-builder/api/index.d.cts +2 -2
- package/dist/plugins/form-builder/api/index.d.mts +2 -2
- package/dist/plugins/form-builder/api/index.d.ts +2 -2
- 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/client/index.d.cts +6 -6
- package/dist/plugins/form-builder/client/index.d.mts +6 -6
- package/dist/plugins/form-builder/client/index.d.ts +6 -6
- package/dist/plugins/form-builder/query-keys.d.cts +2 -2
- package/dist/plugins/form-builder/query-keys.d.mts +2 -2
- package/dist/plugins/form-builder/query-keys.d.ts +2 -2
- 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/client/index.d.cts +12 -12
- package/dist/plugins/kanban/client/index.d.mts +12 -12
- package/dist/plugins/kanban/client/index.d.ts +12 -12
- 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/plugins/ui-builder/client/hooks/index.d.cts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.mts +1 -1
- package/dist/plugins/ui-builder/client/hooks/index.d.ts +1 -1
- package/dist/plugins/ui-builder/client/index.d.cts +3 -3
- package/dist/plugins/ui-builder/client/index.d.mts +3 -3
- package/dist/plugins/ui-builder/client/index.d.ts +3 -3
- package/dist/plugins/ui-builder/index.d.cts +2 -2
- package/dist/plugins/ui-builder/index.d.mts +2 -2
- package/dist/plugins/ui-builder/index.d.ts +2 -2
- package/dist/shared/{stack.C-WUPMT6.d.cts → stack.B2xZTSiO.d.cts} +4 -4
- package/dist/shared/{stack.B1EeBt1b.d.ts → stack.B58oHdqm.d.mts} +33 -3
- package/dist/shared/{stack.CVDTkMoO.d.mts → stack.B8QD11QU.d.cts} +7 -7
- package/dist/shared/{stack.CVDTkMoO.d.cts → stack.B8QD11QU.d.mts} +7 -7
- package/dist/shared/{stack.CVDTkMoO.d.ts → stack.B8QD11QU.d.ts} +7 -7
- package/dist/shared/{stack.CIP6QS9l.d.ts → stack.BDVEpue1.d.ts} +1 -1
- package/dist/shared/{stack.C5dtIncc.d.mts → stack.BTvbxZvw.d.cts} +1 -1
- 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.DdI5W6MB.d.mts → stack.BozPgbrZ.d.cts} +19 -19
- package/dist/shared/{stack.DdI5W6MB.d.ts → stack.BozPgbrZ.d.mts} +19 -19
- package/dist/shared/{stack.DdI5W6MB.d.cts → stack.BozPgbrZ.d.ts} +19 -19
- package/dist/shared/{stack.CP68pFEH.d.mts → stack.C9Mg2Q46.d.cts} +33 -3
- package/dist/shared/{stack.BeSm90va.d.ts → stack.CTDVxbrA.d.ts} +72 -14
- package/dist/shared/{stack.C-Ptrz8s.d.ts → stack.Cj_zKww4.d.ts} +4 -4
- package/dist/shared/{stack.TIBF2AOx.d.ts → stack.CxaFNQCV.d.mts} +89 -34
- package/dist/shared/{stack.CMh_EdxW.d.cts → stack.D-b5zbPm.d.cts} +72 -14
- package/dist/shared/{stack.Dw0Ly2TM.d.cts → stack.DTtmJPQO.d.mts} +1 -1
- package/dist/shared/{stack.BKfolAyK.d.ts → stack.DXnclTG7.d.ts} +11 -11
- package/dist/shared/{stack.snB1EDP7.d.cts → stack.DaZM10cp.d.cts} +11 -11
- package/dist/shared/{stack.Dg09R0oB.d.mts → stack.FVWf2JhZ.d.mts} +72 -14
- package/dist/shared/{stack.BIXEI6v_.d.mts → stack.cfCkioTe.d.mts} +11 -11
- package/dist/shared/{stack.6fUOjLs9.d.mts → stack.dH7u-TJH.d.mts} +4 -4
- package/dist/shared/{stack.BpolpQpf.d.cts → stack.j75TpKh2.d.ts} +89 -34
- package/dist/shared/{stack.rTy7-wQU.d.mts → stack.n1_i1p2B.d.cts} +89 -34
- package/dist/shared/{stack.IdtKDRka.d.cts → stack.sO33ZDhK.d.ts} +33 -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 +228 -72
- 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/client/plugin.tsx +23 -31
- package/src/plugins/ai-chat/schemas.ts +16 -0
- package/src/plugins/blog/api/plugin.ts +31 -47
- 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 +36 -39
- package/src/plugins/client/index.ts +5 -1
- 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 +23 -17
- package/src/plugins/cms/client/plugin.tsx +18 -21
- package/src/plugins/cms/types.ts +7 -7
- package/src/plugins/form-builder/api/plugin.ts +64 -64
- package/src/plugins/form-builder/client/plugin.tsx +19 -18
- package/src/plugins/form-builder/types.ts +19 -24
- 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 +123 -136
- package/src/plugins/kanban/client/hooks/kanban-hooks.tsx +4 -0
- package/src/plugins/kanban/client/plugin.tsx +35 -41
- package/src/plugins/ui-builder/client/components/pages/page-builder-page.internal.tsx +132 -0
- package/src/plugins/ui-builder/client/plugin.tsx +11 -10
- package/src/plugins/ui-builder/types.ts +4 -4
- package/src/plugins/utils.ts +92 -1
- package/dist/shared/{stack.CBON0dWL.d.mts → stack.BQmuNl5p.d.cts} +2 -2
- package/dist/shared/{stack.CBON0dWL.d.ts → stack.BQmuNl5p.d.mts} +2 -2
- package/dist/shared/{stack.CBON0dWL.d.cts → stack.BQmuNl5p.d.ts} +2 -2
|
@@ -40,8 +40,7 @@ function ComposedRoute({
|
|
|
40
40
|
}) {
|
|
41
41
|
if (PageComponent) {
|
|
42
42
|
const content = /* @__PURE__ */ jsxRuntime.jsx(PageComponent, { ...props });
|
|
43
|
-
const
|
|
44
|
-
const suspenseFallback = isBrowser && LoadingComponent ? /* @__PURE__ */ jsxRuntime.jsx(LoadingComponent, {}) : null;
|
|
43
|
+
const suspenseFallback = LoadingComponent ? /* @__PURE__ */ jsxRuntime.jsx(LoadingComponent, {}) : null;
|
|
45
44
|
if (ErrorComponent) {
|
|
46
45
|
return /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: suspenseFallback, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
47
46
|
errorBoundary.ErrorBoundary,
|
|
@@ -38,8 +38,7 @@ function ComposedRoute({
|
|
|
38
38
|
}) {
|
|
39
39
|
if (PageComponent) {
|
|
40
40
|
const content = /* @__PURE__ */ jsx(PageComponent, { ...props });
|
|
41
|
-
const
|
|
42
|
-
const suspenseFallback = isBrowser && LoadingComponent ? /* @__PURE__ */ jsx(LoadingComponent, {}) : null;
|
|
41
|
+
const suspenseFallback = LoadingComponent ? /* @__PURE__ */ jsx(LoadingComponent, {}) : null;
|
|
43
42
|
if (ErrorComponent) {
|
|
44
43
|
return /* @__PURE__ */ jsx(Suspense, { fallback: suspenseFallback, children: /* @__PURE__ */ jsx(
|
|
45
44
|
ErrorBoundary,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ai = require('ai');
|
|
4
|
+
const z = require('zod');
|
|
5
|
+
|
|
6
|
+
const BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST = {
|
|
7
|
+
/** Blog new-post and edit-post pages */
|
|
8
|
+
fillBlogForm: ["blog-new-post", "blog-edit-post", "newPost", "editPost"],
|
|
9
|
+
/** UI builder edit page */
|
|
10
|
+
updatePageLayers: ["ui-builder-edit-page"]
|
|
11
|
+
};
|
|
12
|
+
const BUILT_IN_PAGE_TOOL_SCHEMAS = {
|
|
13
|
+
/**
|
|
14
|
+
* Fill in the blog post editor form fields.
|
|
15
|
+
* Registered by blog new/edit page via useRegisterPageAIContext.
|
|
16
|
+
*/
|
|
17
|
+
fillBlogForm: ai.tool({
|
|
18
|
+
description: "Fill in the blog post editor form fields. Call this when the user asks to write, draft, or populate a blog post. You can fill any combination of title, content, excerpt, and tags.",
|
|
19
|
+
inputSchema: z.z.object({
|
|
20
|
+
title: z.z.string().optional().describe("The post title"),
|
|
21
|
+
content: z.z.string().optional().describe(
|
|
22
|
+
"Full markdown content for the post body. Use proper markdown formatting with headings, lists, etc."
|
|
23
|
+
),
|
|
24
|
+
excerpt: z.z.string().optional().describe("A short summary/excerpt of the post (1-2 sentences)"),
|
|
25
|
+
tags: z.z.array(z.z.string()).optional().describe("Array of tag names to apply to the post")
|
|
26
|
+
})
|
|
27
|
+
}),
|
|
28
|
+
/**
|
|
29
|
+
* Replace the UI builder page layers with new ones.
|
|
30
|
+
* Registered by the UI builder edit page via useRegisterPageAIContext.
|
|
31
|
+
*/
|
|
32
|
+
updatePageLayers: ai.tool({
|
|
33
|
+
description: `Replace the UI builder page component layers. Call this when the user asks to change, add, redesign, or update the page layout and components.
|
|
34
|
+
|
|
35
|
+
Rules:
|
|
36
|
+
- Provide the COMPLETE layer tree, not a partial diff. The entire tree will replace the current layers.
|
|
37
|
+
- Only use component types that appear in the "Available Component Types" list in the page context.
|
|
38
|
+
- Every layer must have a unique \`id\` string (e.g. "hero-section", "card-title-1").
|
|
39
|
+
- The \`type\` field must exactly match a name from the component registry (e.g. "div", "Button", "Card", "Flexbox").
|
|
40
|
+
- The \`name\` field is the human-readable label shown in the layers panel.
|
|
41
|
+
- \`props\` contains component-specific props (className uses Tailwind classes).
|
|
42
|
+
- \`children\` is either an array of child ComponentLayer objects, or a plain string for text content.
|
|
43
|
+
- Use \`Flexbox\` or \`Grid\` for layout instead of raw div flex/grid when possible.
|
|
44
|
+
- Preserve any layers the user has not asked to change \u2014 read the current layers from the page context first.
|
|
45
|
+
- ALWAYS use shadcn/ui semantic color tokens in className (e.g. bg-background, bg-card, bg-primary, text-foreground, text-muted-foreground, text-primary-foreground, border-border) instead of hardcoded Tailwind colors like bg-white, bg-gray-*, text-black, etc. This ensures the UI automatically adapts to light and dark themes.`,
|
|
46
|
+
inputSchema: z.z.object({
|
|
47
|
+
layers: z.z.array(
|
|
48
|
+
z.z.object({
|
|
49
|
+
id: z.z.string().describe("Unique identifier for this layer"),
|
|
50
|
+
type: z.z.string().describe(
|
|
51
|
+
"Component type \u2014 must match a key in the component registry (e.g. 'div', 'Button', 'Card', 'Flexbox')"
|
|
52
|
+
),
|
|
53
|
+
name: z.z.string().describe(
|
|
54
|
+
"Human-readable display name shown in the layers panel"
|
|
55
|
+
),
|
|
56
|
+
props: z.z.record(z.z.string(), z.z.any()).describe(
|
|
57
|
+
"Component props object. Use Tailwind classes for className. See the component registry for valid props per type."
|
|
58
|
+
),
|
|
59
|
+
children: z.z.any().optional().describe(
|
|
60
|
+
"Child layers (array of ComponentLayer) or plain text string"
|
|
61
|
+
)
|
|
62
|
+
})
|
|
63
|
+
).describe(
|
|
64
|
+
"Complete replacement layer tree. Must include ALL layers for the page, not just changed ones."
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
exports.BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST = BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST;
|
|
71
|
+
exports.BUILT_IN_PAGE_TOOL_SCHEMAS = BUILT_IN_PAGE_TOOL_SCHEMAS;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { tool } from 'ai';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST = {
|
|
5
|
+
/** Blog new-post and edit-post pages */
|
|
6
|
+
fillBlogForm: ["blog-new-post", "blog-edit-post", "newPost", "editPost"],
|
|
7
|
+
/** UI builder edit page */
|
|
8
|
+
updatePageLayers: ["ui-builder-edit-page"]
|
|
9
|
+
};
|
|
10
|
+
const BUILT_IN_PAGE_TOOL_SCHEMAS = {
|
|
11
|
+
/**
|
|
12
|
+
* Fill in the blog post editor form fields.
|
|
13
|
+
* Registered by blog new/edit page via useRegisterPageAIContext.
|
|
14
|
+
*/
|
|
15
|
+
fillBlogForm: tool({
|
|
16
|
+
description: "Fill in the blog post editor form fields. Call this when the user asks to write, draft, or populate a blog post. You can fill any combination of title, content, excerpt, and tags.",
|
|
17
|
+
inputSchema: z.object({
|
|
18
|
+
title: z.string().optional().describe("The post title"),
|
|
19
|
+
content: z.string().optional().describe(
|
|
20
|
+
"Full markdown content for the post body. Use proper markdown formatting with headings, lists, etc."
|
|
21
|
+
),
|
|
22
|
+
excerpt: z.string().optional().describe("A short summary/excerpt of the post (1-2 sentences)"),
|
|
23
|
+
tags: z.array(z.string()).optional().describe("Array of tag names to apply to the post")
|
|
24
|
+
})
|
|
25
|
+
}),
|
|
26
|
+
/**
|
|
27
|
+
* Replace the UI builder page layers with new ones.
|
|
28
|
+
* Registered by the UI builder edit page via useRegisterPageAIContext.
|
|
29
|
+
*/
|
|
30
|
+
updatePageLayers: tool({
|
|
31
|
+
description: `Replace the UI builder page component layers. Call this when the user asks to change, add, redesign, or update the page layout and components.
|
|
32
|
+
|
|
33
|
+
Rules:
|
|
34
|
+
- Provide the COMPLETE layer tree, not a partial diff. The entire tree will replace the current layers.
|
|
35
|
+
- Only use component types that appear in the "Available Component Types" list in the page context.
|
|
36
|
+
- Every layer must have a unique \`id\` string (e.g. "hero-section", "card-title-1").
|
|
37
|
+
- The \`type\` field must exactly match a name from the component registry (e.g. "div", "Button", "Card", "Flexbox").
|
|
38
|
+
- The \`name\` field is the human-readable label shown in the layers panel.
|
|
39
|
+
- \`props\` contains component-specific props (className uses Tailwind classes).
|
|
40
|
+
- \`children\` is either an array of child ComponentLayer objects, or a plain string for text content.
|
|
41
|
+
- Use \`Flexbox\` or \`Grid\` for layout instead of raw div flex/grid when possible.
|
|
42
|
+
- Preserve any layers the user has not asked to change \u2014 read the current layers from the page context first.
|
|
43
|
+
- ALWAYS use shadcn/ui semantic color tokens in className (e.g. bg-background, bg-card, bg-primary, text-foreground, text-muted-foreground, text-primary-foreground, border-border) instead of hardcoded Tailwind colors like bg-white, bg-gray-*, text-black, etc. This ensures the UI automatically adapts to light and dark themes.`,
|
|
44
|
+
inputSchema: z.object({
|
|
45
|
+
layers: z.array(
|
|
46
|
+
z.object({
|
|
47
|
+
id: z.string().describe("Unique identifier for this layer"),
|
|
48
|
+
type: z.string().describe(
|
|
49
|
+
"Component type \u2014 must match a key in the component registry (e.g. 'div', 'Button', 'Card', 'Flexbox')"
|
|
50
|
+
),
|
|
51
|
+
name: z.string().describe(
|
|
52
|
+
"Human-readable display name shown in the layers panel"
|
|
53
|
+
),
|
|
54
|
+
props: z.record(z.string(), z.any()).describe(
|
|
55
|
+
"Component props object. Use Tailwind classes for className. See the component registry for valid props per type."
|
|
56
|
+
),
|
|
57
|
+
children: z.any().optional().describe(
|
|
58
|
+
"Child layers (array of ComponentLayer) or plain text string"
|
|
59
|
+
)
|
|
60
|
+
})
|
|
61
|
+
).describe(
|
|
62
|
+
"Complete replacement layer tree. Must include ALL layers for the page, not just changed ones."
|
|
63
|
+
)
|
|
64
|
+
})
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export { BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST, BUILT_IN_PAGE_TOOL_SCHEMAS };
|
|
@@ -5,6 +5,8 @@ const ai = require('ai');
|
|
|
5
5
|
const db = require('../db.cjs');
|
|
6
6
|
const schemas = require('../schemas.cjs');
|
|
7
7
|
const getters = require('./getters.cjs');
|
|
8
|
+
const pageTools = require('./page-tools.cjs');
|
|
9
|
+
const utils = require('../../utils.cjs');
|
|
8
10
|
|
|
9
11
|
const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
10
12
|
name: "ai-chat",
|
|
@@ -52,7 +54,13 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
52
54
|
body: schemas.chatRequestSchema
|
|
53
55
|
},
|
|
54
56
|
async (ctx) => {
|
|
55
|
-
const {
|
|
57
|
+
const {
|
|
58
|
+
messages: rawMessages,
|
|
59
|
+
conversationId,
|
|
60
|
+
pageContext,
|
|
61
|
+
availableTools,
|
|
62
|
+
routeName
|
|
63
|
+
} = ctx.body;
|
|
56
64
|
const uiMessages = rawMessages;
|
|
57
65
|
const context = {
|
|
58
66
|
body: ctx.body,
|
|
@@ -65,15 +73,11 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
65
73
|
role: msg.role,
|
|
66
74
|
content: getMessageTextContent(msg)
|
|
67
75
|
}));
|
|
68
|
-
|
|
69
|
-
messagesForHook,
|
|
70
|
-
|
|
76
|
+
await utils.runHookWithShim(
|
|
77
|
+
() => config.hooks.onBeforeChat(messagesForHook, context),
|
|
78
|
+
ctx.error,
|
|
79
|
+
"Unauthorized: Cannot start chat"
|
|
71
80
|
);
|
|
72
|
-
if (!canChat) {
|
|
73
|
-
throw ctx.error(403, {
|
|
74
|
-
message: "Unauthorized: Cannot start chat"
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
81
|
}
|
|
78
82
|
const firstMessage = uiMessages[0];
|
|
79
83
|
if (!firstMessage) {
|
|
@@ -83,17 +87,57 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
83
87
|
}
|
|
84
88
|
const firstMessageContent = getMessageTextContent(firstMessage);
|
|
85
89
|
const modelMessages = ai.convertToModelMessages(uiMessages);
|
|
86
|
-
const
|
|
87
|
-
|
|
90
|
+
const pageContextContent = pageContext && pageContext.trim() ? `
|
|
91
|
+
|
|
92
|
+
Current page context:
|
|
93
|
+
${pageContext}` : "";
|
|
94
|
+
const systemContent = config.systemPrompt ? `${config.systemPrompt}${pageContextContent}` : pageContextContent || void 0;
|
|
95
|
+
const messagesWithSystem = systemContent ? [
|
|
96
|
+
{ role: "system", content: systemContent },
|
|
88
97
|
...modelMessages
|
|
89
98
|
] : modelMessages;
|
|
99
|
+
const activePageTools = config.enablePageTools && availableTools && availableTools.length > 0 ? (() => {
|
|
100
|
+
const consumerSchemas = config.clientToolSchemas ?? {};
|
|
101
|
+
return Object.fromEntries(
|
|
102
|
+
availableTools.filter((name) => {
|
|
103
|
+
if (name in pageTools.BUILT_IN_PAGE_TOOL_SCHEMAS) {
|
|
104
|
+
const allowed = pageTools.BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST[name];
|
|
105
|
+
return allowed && routeName && allowed.includes(routeName);
|
|
106
|
+
}
|
|
107
|
+
return name in consumerSchemas;
|
|
108
|
+
}).map((name) => {
|
|
109
|
+
const schema = pageTools.BUILT_IN_PAGE_TOOL_SCHEMAS[name] ?? consumerSchemas[name];
|
|
110
|
+
return [name, schema];
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
})() : {};
|
|
114
|
+
if (config.hooks?.onBeforeToolsActivated && Object.keys(activePageTools).length > 0) {
|
|
115
|
+
try {
|
|
116
|
+
const allowed = await config.hooks.onBeforeToolsActivated(
|
|
117
|
+
Object.keys(activePageTools),
|
|
118
|
+
routeName,
|
|
119
|
+
context
|
|
120
|
+
);
|
|
121
|
+
const allowedSet = new Set(allowed);
|
|
122
|
+
for (const key of Object.keys(activePageTools)) {
|
|
123
|
+
if (!allowedSet.has(key)) {
|
|
124
|
+
delete activePageTools[key];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (hookError) {
|
|
128
|
+
throw ctx.error(403, {
|
|
129
|
+
message: hookError instanceof Error ? hookError.message : "Unauthorized: Tool activation denied"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const mergedTools = Object.keys(activePageTools).length > 0 ? { ...activePageTools, ...config.tools } : config.tools;
|
|
90
134
|
if (isPublicMode) {
|
|
91
135
|
const result2 = ai.streamText({
|
|
92
136
|
model: config.model,
|
|
93
137
|
messages: messagesWithSystem,
|
|
94
|
-
tools:
|
|
138
|
+
tools: mergedTools,
|
|
95
139
|
// Enable multi-step tool calls if tools are configured
|
|
96
|
-
...
|
|
140
|
+
...mergedTools ? { stopWhen: ai.stepCountIs(5) } : {}
|
|
97
141
|
});
|
|
98
142
|
return result2.toUIMessageStreamResponse({
|
|
99
143
|
originalMessages: uiMessages
|
|
@@ -201,9 +245,9 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
201
245
|
const result = ai.streamText({
|
|
202
246
|
model: config.model,
|
|
203
247
|
messages: messagesWithSystem,
|
|
204
|
-
tools:
|
|
248
|
+
tools: mergedTools,
|
|
205
249
|
// Enable multi-step tool calls if tools are configured
|
|
206
|
-
...
|
|
250
|
+
...mergedTools ? { stopWhen: ai.stepCountIs(5) } : {},
|
|
207
251
|
onFinish: async (completion) => {
|
|
208
252
|
try {
|
|
209
253
|
const assistantParts = completion.text ? [{ type: "text", text: completion.text }] : [];
|
|
@@ -296,15 +340,14 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
296
340
|
});
|
|
297
341
|
});
|
|
298
342
|
if (config.hooks?.onBeforeCreateConversation) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
343
|
+
await utils.runHookWithShim(
|
|
344
|
+
() => config.hooks.onBeforeCreateConversation(
|
|
345
|
+
{ id, title },
|
|
346
|
+
context
|
|
347
|
+
),
|
|
348
|
+
ctx.error,
|
|
349
|
+
"Unauthorized: Cannot create conversation"
|
|
302
350
|
);
|
|
303
|
-
if (!canCreate) {
|
|
304
|
-
throw ctx.error(403, {
|
|
305
|
-
message: "Unauthorized: Cannot create conversation"
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
351
|
}
|
|
309
352
|
const newConv = await adapter.create({
|
|
310
353
|
model: "conversation",
|
|
@@ -350,12 +393,11 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
350
393
|
});
|
|
351
394
|
});
|
|
352
395
|
if (config.hooks?.onBeforeListConversations) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
396
|
+
await utils.runHookWithShim(
|
|
397
|
+
() => config.hooks.onBeforeListConversations(context),
|
|
398
|
+
ctx.error,
|
|
399
|
+
"Unauthorized: Cannot list conversations"
|
|
400
|
+
);
|
|
359
401
|
}
|
|
360
402
|
const whereConditions = [];
|
|
361
403
|
if (userId) {
|
|
@@ -408,15 +450,11 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
408
450
|
});
|
|
409
451
|
});
|
|
410
452
|
if (config.hooks?.onBeforeGetConversation) {
|
|
411
|
-
|
|
412
|
-
id,
|
|
413
|
-
|
|
453
|
+
await utils.runHookWithShim(
|
|
454
|
+
() => config.hooks.onBeforeGetConversation(id, context),
|
|
455
|
+
ctx.error,
|
|
456
|
+
"Unauthorized: Cannot get conversation"
|
|
414
457
|
);
|
|
415
|
-
if (!canGet) {
|
|
416
|
-
throw ctx.error(403, {
|
|
417
|
-
message: "Unauthorized: Cannot get conversation"
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
458
|
}
|
|
421
459
|
const conversations = await adapter.findMany({
|
|
422
460
|
model: "conversation",
|
|
@@ -498,16 +536,15 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
498
536
|
});
|
|
499
537
|
}
|
|
500
538
|
if (config.hooks?.onBeforeUpdateConversation) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
539
|
+
await utils.runHookWithShim(
|
|
540
|
+
() => config.hooks.onBeforeUpdateConversation(
|
|
541
|
+
id,
|
|
542
|
+
{ title },
|
|
543
|
+
context
|
|
544
|
+
),
|
|
545
|
+
ctx.error,
|
|
546
|
+
"Unauthorized: Cannot update conversation"
|
|
505
547
|
);
|
|
506
|
-
if (!canUpdate) {
|
|
507
|
-
throw ctx.error(403, {
|
|
508
|
-
message: "Unauthorized: Cannot update conversation"
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
548
|
}
|
|
512
549
|
const updated = await adapter.update({
|
|
513
550
|
model: "conversation",
|
|
@@ -572,15 +609,11 @@ const aiChatBackendPlugin = (config) => api.defineBackendPlugin({
|
|
|
572
609
|
});
|
|
573
610
|
}
|
|
574
611
|
if (config.hooks?.onBeforeDeleteConversation) {
|
|
575
|
-
|
|
576
|
-
id,
|
|
577
|
-
|
|
612
|
+
await utils.runHookWithShim(
|
|
613
|
+
() => config.hooks.onBeforeDeleteConversation(id, context),
|
|
614
|
+
ctx.error,
|
|
615
|
+
"Unauthorized: Cannot delete conversation"
|
|
578
616
|
);
|
|
579
|
-
if (!canDelete) {
|
|
580
|
-
throw ctx.error(403, {
|
|
581
|
-
message: "Unauthorized: Cannot delete conversation"
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
617
|
}
|
|
585
618
|
await adapter.delete({
|
|
586
619
|
model: "conversation",
|
|
@@ -3,6 +3,8 @@ import { convertToModelMessages, streamText, stepCountIs } from 'ai';
|
|
|
3
3
|
import { aiChatSchema } from '../db.mjs';
|
|
4
4
|
import { chatRequestSchema, createConversationSchema, updateConversationSchema } from '../schemas.mjs';
|
|
5
5
|
import { getConversationById, getAllConversations } from './getters.mjs';
|
|
6
|
+
import { BUILT_IN_PAGE_TOOL_SCHEMAS, BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST } from './page-tools.mjs';
|
|
7
|
+
import { runHookWithShim } from '../../utils.mjs';
|
|
6
8
|
|
|
7
9
|
const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
8
10
|
name: "ai-chat",
|
|
@@ -50,7 +52,13 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
50
52
|
body: chatRequestSchema
|
|
51
53
|
},
|
|
52
54
|
async (ctx) => {
|
|
53
|
-
const {
|
|
55
|
+
const {
|
|
56
|
+
messages: rawMessages,
|
|
57
|
+
conversationId,
|
|
58
|
+
pageContext,
|
|
59
|
+
availableTools,
|
|
60
|
+
routeName
|
|
61
|
+
} = ctx.body;
|
|
54
62
|
const uiMessages = rawMessages;
|
|
55
63
|
const context = {
|
|
56
64
|
body: ctx.body,
|
|
@@ -63,15 +71,11 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
63
71
|
role: msg.role,
|
|
64
72
|
content: getMessageTextContent(msg)
|
|
65
73
|
}));
|
|
66
|
-
|
|
67
|
-
messagesForHook,
|
|
68
|
-
|
|
74
|
+
await runHookWithShim(
|
|
75
|
+
() => config.hooks.onBeforeChat(messagesForHook, context),
|
|
76
|
+
ctx.error,
|
|
77
|
+
"Unauthorized: Cannot start chat"
|
|
69
78
|
);
|
|
70
|
-
if (!canChat) {
|
|
71
|
-
throw ctx.error(403, {
|
|
72
|
-
message: "Unauthorized: Cannot start chat"
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
79
|
}
|
|
76
80
|
const firstMessage = uiMessages[0];
|
|
77
81
|
if (!firstMessage) {
|
|
@@ -81,17 +85,57 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
81
85
|
}
|
|
82
86
|
const firstMessageContent = getMessageTextContent(firstMessage);
|
|
83
87
|
const modelMessages = convertToModelMessages(uiMessages);
|
|
84
|
-
const
|
|
85
|
-
|
|
88
|
+
const pageContextContent = pageContext && pageContext.trim() ? `
|
|
89
|
+
|
|
90
|
+
Current page context:
|
|
91
|
+
${pageContext}` : "";
|
|
92
|
+
const systemContent = config.systemPrompt ? `${config.systemPrompt}${pageContextContent}` : pageContextContent || void 0;
|
|
93
|
+
const messagesWithSystem = systemContent ? [
|
|
94
|
+
{ role: "system", content: systemContent },
|
|
86
95
|
...modelMessages
|
|
87
96
|
] : modelMessages;
|
|
97
|
+
const activePageTools = config.enablePageTools && availableTools && availableTools.length > 0 ? (() => {
|
|
98
|
+
const consumerSchemas = config.clientToolSchemas ?? {};
|
|
99
|
+
return Object.fromEntries(
|
|
100
|
+
availableTools.filter((name) => {
|
|
101
|
+
if (name in BUILT_IN_PAGE_TOOL_SCHEMAS) {
|
|
102
|
+
const allowed = BUILT_IN_PAGE_TOOL_ROUTE_ALLOWLIST[name];
|
|
103
|
+
return allowed && routeName && allowed.includes(routeName);
|
|
104
|
+
}
|
|
105
|
+
return name in consumerSchemas;
|
|
106
|
+
}).map((name) => {
|
|
107
|
+
const schema = BUILT_IN_PAGE_TOOL_SCHEMAS[name] ?? consumerSchemas[name];
|
|
108
|
+
return [name, schema];
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
})() : {};
|
|
112
|
+
if (config.hooks?.onBeforeToolsActivated && Object.keys(activePageTools).length > 0) {
|
|
113
|
+
try {
|
|
114
|
+
const allowed = await config.hooks.onBeforeToolsActivated(
|
|
115
|
+
Object.keys(activePageTools),
|
|
116
|
+
routeName,
|
|
117
|
+
context
|
|
118
|
+
);
|
|
119
|
+
const allowedSet = new Set(allowed);
|
|
120
|
+
for (const key of Object.keys(activePageTools)) {
|
|
121
|
+
if (!allowedSet.has(key)) {
|
|
122
|
+
delete activePageTools[key];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
} catch (hookError) {
|
|
126
|
+
throw ctx.error(403, {
|
|
127
|
+
message: hookError instanceof Error ? hookError.message : "Unauthorized: Tool activation denied"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const mergedTools = Object.keys(activePageTools).length > 0 ? { ...activePageTools, ...config.tools } : config.tools;
|
|
88
132
|
if (isPublicMode) {
|
|
89
133
|
const result2 = streamText({
|
|
90
134
|
model: config.model,
|
|
91
135
|
messages: messagesWithSystem,
|
|
92
|
-
tools:
|
|
136
|
+
tools: mergedTools,
|
|
93
137
|
// Enable multi-step tool calls if tools are configured
|
|
94
|
-
...
|
|
138
|
+
...mergedTools ? { stopWhen: stepCountIs(5) } : {}
|
|
95
139
|
});
|
|
96
140
|
return result2.toUIMessageStreamResponse({
|
|
97
141
|
originalMessages: uiMessages
|
|
@@ -199,9 +243,9 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
199
243
|
const result = streamText({
|
|
200
244
|
model: config.model,
|
|
201
245
|
messages: messagesWithSystem,
|
|
202
|
-
tools:
|
|
246
|
+
tools: mergedTools,
|
|
203
247
|
// Enable multi-step tool calls if tools are configured
|
|
204
|
-
...
|
|
248
|
+
...mergedTools ? { stopWhen: stepCountIs(5) } : {},
|
|
205
249
|
onFinish: async (completion) => {
|
|
206
250
|
try {
|
|
207
251
|
const assistantParts = completion.text ? [{ type: "text", text: completion.text }] : [];
|
|
@@ -294,15 +338,14 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
294
338
|
});
|
|
295
339
|
});
|
|
296
340
|
if (config.hooks?.onBeforeCreateConversation) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
341
|
+
await runHookWithShim(
|
|
342
|
+
() => config.hooks.onBeforeCreateConversation(
|
|
343
|
+
{ id, title },
|
|
344
|
+
context
|
|
345
|
+
),
|
|
346
|
+
ctx.error,
|
|
347
|
+
"Unauthorized: Cannot create conversation"
|
|
300
348
|
);
|
|
301
|
-
if (!canCreate) {
|
|
302
|
-
throw ctx.error(403, {
|
|
303
|
-
message: "Unauthorized: Cannot create conversation"
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
349
|
}
|
|
307
350
|
const newConv = await adapter.create({
|
|
308
351
|
model: "conversation",
|
|
@@ -348,12 +391,11 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
348
391
|
});
|
|
349
392
|
});
|
|
350
393
|
if (config.hooks?.onBeforeListConversations) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
394
|
+
await runHookWithShim(
|
|
395
|
+
() => config.hooks.onBeforeListConversations(context),
|
|
396
|
+
ctx.error,
|
|
397
|
+
"Unauthorized: Cannot list conversations"
|
|
398
|
+
);
|
|
357
399
|
}
|
|
358
400
|
const whereConditions = [];
|
|
359
401
|
if (userId) {
|
|
@@ -406,15 +448,11 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
406
448
|
});
|
|
407
449
|
});
|
|
408
450
|
if (config.hooks?.onBeforeGetConversation) {
|
|
409
|
-
|
|
410
|
-
id,
|
|
411
|
-
|
|
451
|
+
await runHookWithShim(
|
|
452
|
+
() => config.hooks.onBeforeGetConversation(id, context),
|
|
453
|
+
ctx.error,
|
|
454
|
+
"Unauthorized: Cannot get conversation"
|
|
412
455
|
);
|
|
413
|
-
if (!canGet) {
|
|
414
|
-
throw ctx.error(403, {
|
|
415
|
-
message: "Unauthorized: Cannot get conversation"
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
456
|
}
|
|
419
457
|
const conversations = await adapter.findMany({
|
|
420
458
|
model: "conversation",
|
|
@@ -496,16 +534,15 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
496
534
|
});
|
|
497
535
|
}
|
|
498
536
|
if (config.hooks?.onBeforeUpdateConversation) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
537
|
+
await runHookWithShim(
|
|
538
|
+
() => config.hooks.onBeforeUpdateConversation(
|
|
539
|
+
id,
|
|
540
|
+
{ title },
|
|
541
|
+
context
|
|
542
|
+
),
|
|
543
|
+
ctx.error,
|
|
544
|
+
"Unauthorized: Cannot update conversation"
|
|
503
545
|
);
|
|
504
|
-
if (!canUpdate) {
|
|
505
|
-
throw ctx.error(403, {
|
|
506
|
-
message: "Unauthorized: Cannot update conversation"
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
546
|
}
|
|
510
547
|
const updated = await adapter.update({
|
|
511
548
|
model: "conversation",
|
|
@@ -570,15 +607,11 @@ const aiChatBackendPlugin = (config) => defineBackendPlugin({
|
|
|
570
607
|
});
|
|
571
608
|
}
|
|
572
609
|
if (config.hooks?.onBeforeDeleteConversation) {
|
|
573
|
-
|
|
574
|
-
id,
|
|
575
|
-
|
|
610
|
+
await runHookWithShim(
|
|
611
|
+
() => config.hooks.onBeforeDeleteConversation(id, context),
|
|
612
|
+
ctx.error,
|
|
613
|
+
"Unauthorized: Cannot delete conversation"
|
|
576
614
|
);
|
|
577
|
-
if (!canDelete) {
|
|
578
|
-
throw ctx.error(403, {
|
|
579
|
-
message: "Unauthorized: Cannot delete conversation"
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
615
|
}
|
|
583
616
|
await adapter.delete({
|
|
584
617
|
model: "conversation",
|
|
@@ -184,7 +184,7 @@ function ChatInput({
|
|
|
184
184
|
}
|
|
185
185
|
)
|
|
186
186
|
] }),
|
|
187
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1", children: [
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-1 min-w-0", children: [
|
|
188
188
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
189
189
|
textarea.Textarea,
|
|
190
190
|
{
|
|
@@ -193,7 +193,7 @@ function ChatInput({
|
|
|
193
193
|
onKeyDown: handleKeyDown,
|
|
194
194
|
placeholder: placeholder || localization.CHAT_PLACEHOLDER,
|
|
195
195
|
className: utils.cn(
|
|
196
|
-
"resize-none pr-12",
|
|
196
|
+
"resize-none pr-12 max-w-full",
|
|
197
197
|
isCompact ? "min-h-[40px] max-h-[120px] py-2" : "min-h-[50px] max-h-[200px] py-3"
|
|
198
198
|
),
|
|
199
199
|
rows: 1
|
|
@@ -182,7 +182,7 @@ function ChatInput({
|
|
|
182
182
|
}
|
|
183
183
|
)
|
|
184
184
|
] }),
|
|
185
|
-
/* @__PURE__ */ jsxs("div", { className: "relative flex-1", children: [
|
|
185
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex-1 min-w-0", children: [
|
|
186
186
|
/* @__PURE__ */ jsx(
|
|
187
187
|
Textarea,
|
|
188
188
|
{
|
|
@@ -191,7 +191,7 @@ function ChatInput({
|
|
|
191
191
|
onKeyDown: handleKeyDown,
|
|
192
192
|
placeholder: placeholder || localization.CHAT_PLACEHOLDER,
|
|
193
193
|
className: cn(
|
|
194
|
-
"resize-none pr-12",
|
|
194
|
+
"resize-none pr-12 max-w-full",
|
|
195
195
|
isCompact ? "min-h-[40px] max-h-[120px] py-2" : "min-h-[50px] max-h-[200px] py-3"
|
|
196
196
|
),
|
|
197
197
|
rows: 1
|