@eventcatalog/core 5.6.1 → 5.7.1
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/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-LVOGLB6C.js → chunk-36XVRD36.js} +1 -1
- package/dist/{chunk-N7LDFUEB.js → chunk-AXWTR2FV.js} +1 -1
- package/dist/{chunk-QJXVAM76.js → chunk-CPF5WE3R.js} +1 -1
- package/dist/{chunk-2NALBBWH.js → chunk-GRC67WHC.js} +1 -1
- package/dist/{chunk-L63ED43X.js → chunk-HZ3XZKUT.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +596 -122
- package/eventcatalog/src/components/ChatPanel/ChatPanelButton.tsx +3 -2
- package/eventcatalog/src/components/ChatPanel/assistant-events.ts +37 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +21 -1
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +2 -1
- package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +2 -34
- package/eventcatalog/src/features/ai/chat-api.ts +24 -5
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +75 -74
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +73 -73
- package/eventcatalog/src/features/studio/agent-choreography.ts +84 -16
- package/eventcatalog/src/features/studio/api/canvases-api.ts +3 -0
- package/eventcatalog/src/features/studio/canvas-actions.ts +330 -15
- package/eventcatalog/src/features/studio/catalog.ts +5 -3
- package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +14 -0
- package/eventcatalog/src/features/studio/components/NodeDetails.tsx +4 -0
- package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +165 -18
- package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +9 -4
- package/eventcatalog/src/features/studio/pages/[id].astro +2 -0
- package/eventcatalog/src/features/studio/server/assistant-tools.ts +207 -0
- package/eventcatalog/src/features/studio/server/canvas-agent.ts +27 -0
- package/eventcatalog/src/features/studio/server/canvas-mcp.ts +2 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +4 -0
- package/eventcatalog/src/utils/node-graphs/compact-visualiser-graph.ts +14 -0
- package/eventcatalog/src/utils/node-graphs/node-resource.ts +26 -0
- package/eventcatalog/src/utils/resource-reference-icons.ts +37 -0
- package/package.json +7 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
2
|
import { Sparkles } from 'lucide-react';
|
|
3
3
|
import ChatPanel from './ChatPanel';
|
|
4
|
+
import { OPEN_CHAT_EVENT } from './assistant-events';
|
|
4
5
|
|
|
5
6
|
const ChatPanelButton = ({ configured = false }: { configured?: boolean }) => {
|
|
6
7
|
const [isOpen, setIsOpen] = useState(false);
|
|
@@ -25,10 +26,10 @@ const ChatPanelButton = ({ configured = false }: { configured?: boolean }) => {
|
|
|
25
26
|
}
|
|
26
27
|
};
|
|
27
28
|
window.addEventListener('keydown', handleShortcut);
|
|
28
|
-
window.addEventListener(
|
|
29
|
+
window.addEventListener(OPEN_CHAT_EVENT, handleOpenChat);
|
|
29
30
|
return () => {
|
|
30
31
|
window.removeEventListener('keydown', handleShortcut);
|
|
31
|
-
window.removeEventListener(
|
|
32
|
+
window.removeEventListener(OPEN_CHAT_EVENT, handleOpenChat);
|
|
32
33
|
};
|
|
33
34
|
}, []);
|
|
34
35
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Window events between the assistant (Ask AI) and the page it's on, e.g. a Studio canvas */
|
|
2
|
+
|
|
3
|
+
/** Opens the assistant's panel */
|
|
4
|
+
export const OPEN_CHAT_EVENT = 'eventcatalog:open-chat';
|
|
5
|
+
|
|
6
|
+
/** The assistant was asked something on a Studio canvas (detail: { canvasId }), which it may draw on */
|
|
7
|
+
export const ASSISTANT_DRAWING_EVENT = 'eventcatalog:assistant-drawing';
|
|
8
|
+
|
|
9
|
+
/** Takes the person to nodes on the Studio canvas they have open (detail: { canvasId, nodeIds }): zoomed to, and selected */
|
|
10
|
+
export const CANVAS_FOCUS_EVENT = 'eventcatalog:canvas-focus';
|
|
11
|
+
|
|
12
|
+
/** Links the assistant writes that take the person to nodes on the canvas: `#canvas-focus=<node id>,<node id>` */
|
|
13
|
+
const FOCUS_LINK = '#canvas-focus=';
|
|
14
|
+
export const nodesInFocusLink = (href: string | undefined) =>
|
|
15
|
+
href?.startsWith(FOCUS_LINK)
|
|
16
|
+
? href
|
|
17
|
+
.slice(FOCUS_LINK.length)
|
|
18
|
+
.split(',')
|
|
19
|
+
.map((id) => decodeURIComponent(id.trim()))
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
: undefined;
|
|
22
|
+
|
|
23
|
+
/** Takes the person to a hotspot on the Studio canvas they have open, and opens it (detail: { canvasId, hotspotId }) */
|
|
24
|
+
export const CANVAS_HOTSPOT_EVENT = 'eventcatalog:canvas-hotspot';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* References the assistant writes to something on the canvas, drawn like the docs' resource references and taking
|
|
28
|
+
* the person to it: `#canvas-ref=<type>:<node id>` (the type, e.g. service or event, gives its icon and colour)
|
|
29
|
+
*/
|
|
30
|
+
const REF_LINK = '#canvas-ref=';
|
|
31
|
+
export const canvasRefIn = (href: string | undefined) => {
|
|
32
|
+
if (!href?.startsWith(REF_LINK)) return undefined;
|
|
33
|
+
const value = decodeURIComponent(href.slice(REF_LINK.length)).trim();
|
|
34
|
+
const split = value.indexOf(':');
|
|
35
|
+
const [type, nodeId] = split === -1 ? ['', value] : [value.slice(0, split).trim(), value.slice(split + 1).trim()];
|
|
36
|
+
return nodeId ? { type: type.toLowerCase(), nodeId } : undefined;
|
|
37
|
+
};
|
|
@@ -17,6 +17,7 @@ import { createPortal } from 'react-dom';
|
|
|
17
17
|
import type { Node, Edge } from '@xyflow/react';
|
|
18
18
|
import type { FlowGroupBy, OpenInStudioRequest } from '@eventcatalog/visualiser';
|
|
19
19
|
import { buildUrl } from '@utils/url-builder';
|
|
20
|
+
import { getNodeDiagramPath } from '@utils/node-graphs/node-resource';
|
|
20
21
|
import { createCanvasThroughApi } from '@features/studio/api/client';
|
|
21
22
|
import { getStoredName } from '@features/studio/identity';
|
|
22
23
|
|
|
@@ -84,9 +85,27 @@ interface AstroNodeGraphProps {
|
|
|
84
85
|
swimlanes?: FlowGroupBy;
|
|
85
86
|
// The Studio API's address, when Studio is on: the menu can then start a canvas from the diagram
|
|
86
87
|
studioApiUrl?: string;
|
|
88
|
+
// Clicking a node opens its diagram (when the catalog has the visualiser's pages)
|
|
89
|
+
opensDiagrams?: boolean;
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
const
|
|
92
|
+
const withoutTrailingSlash = (path: string) => path.replace(/\/+$/, '');
|
|
93
|
+
|
|
94
|
+
/** The diagram page a node opens, unless it's the page this is (e.g. the service on its own diagram) */
|
|
95
|
+
const getNodeDiagramUrl = (node: Node) => {
|
|
96
|
+
const path = getNodeDiagramPath(node);
|
|
97
|
+
if (!path) return undefined;
|
|
98
|
+
const url = buildUrl(path);
|
|
99
|
+
return withoutTrailingSlash(url) === withoutTrailingSlash(window.location.pathname) ? undefined : url;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const AstroNodeGraph = ({
|
|
103
|
+
isDevMode = false,
|
|
104
|
+
resourceKey,
|
|
105
|
+
studioApiUrl,
|
|
106
|
+
opensDiagrams = false,
|
|
107
|
+
...otherProps
|
|
108
|
+
}: AstroNodeGraphProps) => {
|
|
90
109
|
// Astro-specific navigation handler
|
|
91
110
|
const handleNavigate = useCallback((url: string) => {
|
|
92
111
|
// Use window.location for navigation since we can't import astro:transitions/client in a React component
|
|
@@ -167,6 +186,7 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, studioApiUrl, ...other
|
|
|
167
186
|
isDevMode={isDevMode}
|
|
168
187
|
onNavigate={handleNavigate}
|
|
169
188
|
onBuildUrl={handleBuildUrl}
|
|
189
|
+
getNodeDiagramUrl={opensDiagrams ? getNodeDiagramUrl : undefined}
|
|
170
190
|
onSaveLayout={handleSaveLayout}
|
|
171
191
|
onResetLayout={handleResetLayout}
|
|
172
192
|
onOpenInStudio={studioApiUrl ? setToOpen : undefined}
|
|
@@ -31,7 +31,7 @@ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
|
|
|
31
31
|
import { getNodesAndEdges as getNodesAndEdgesForContainer } from '@utils/node-graphs/container-node-graph';
|
|
32
32
|
import { getNodesAndEdges as getNodesAndEdgesForChannel } from '@utils/node-graphs/channel-node-graph';
|
|
33
33
|
import config from '@config';
|
|
34
|
-
import { isEventCatalogChatVisible, isDevMode, isCanvasEnabled } from '@utils/feature';
|
|
34
|
+
import { isEventCatalogChatVisible, isDevMode, isCanvasEnabled, isVisualiserEnabled } from '@utils/feature';
|
|
35
35
|
import { CANVASES_API_PATH } from '@features/studio/api/canvases-api';
|
|
36
36
|
import { loadSavedLayout, applyLayoutToNodes, buildResourceKey } from '@utils/node-graphs/layout-persistence';
|
|
37
37
|
import { compactVisualiserGraph } from '@utils/node-graphs/compact-visualiser-graph';
|
|
@@ -268,6 +268,7 @@ if (overview && levelsOverview) {
|
|
|
268
268
|
swimlanes={lanes}
|
|
269
269
|
studioApiUrl={studioApiUrl}
|
|
270
270
|
syncRenderModeWithUrl={syncRenderModeWithUrl}
|
|
271
|
+
opensDiagrams={isVisualiserEnabled()}
|
|
271
272
|
/>
|
|
272
273
|
</div>
|
|
273
274
|
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import { getCollection } from 'astro:content';
|
|
16
16
|
import { getServiceSpecifications, getSpecUrl, getSpecLabel } from '@components/Grids/specification-utils';
|
|
17
17
|
import { getResourceReferenceStyle } from '@utils/resource-reference-colors';
|
|
18
|
+
import { getResourceReferenceIcon } from '@utils/resource-reference-icons';
|
|
18
19
|
import { isIconPath, resolveIconUrl } from '@utils/icon';
|
|
19
20
|
import {
|
|
20
21
|
getResourceReferenceUrl,
|
|
@@ -88,41 +89,8 @@ const typeLabels: Record<string, string> = {
|
|
|
88
89
|
'data-product': 'Data Product',
|
|
89
90
|
};
|
|
90
91
|
|
|
91
|
-
// SVG icons for each type (from heroicons outline)
|
|
92
|
-
const typeIcons: Record<string, string> = {
|
|
93
|
-
agent:
|
|
94
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M12 6V3m-4.5 7.5h9m-9 3h9M7.5 18h9A2.5 2.5 0 0019 15.5v-5A2.5 2.5 0 0016.5 8h-9A2.5 2.5 0 005 10.5v5A2.5 2.5 0 007.5 18zM9 21h6" />',
|
|
95
|
-
entity:
|
|
96
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M4 7v10l8 4" />', // Box/cube
|
|
97
|
-
service:
|
|
98
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01" />', // Server
|
|
99
|
-
event:
|
|
100
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 13.5l10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75z" />', // Bolt
|
|
101
|
-
command:
|
|
102
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z" />', // ChatBubble
|
|
103
|
-
query:
|
|
104
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />', // MagnifyingGlass
|
|
105
|
-
domain:
|
|
106
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 7.125C2.25 6.504 2.754 6 3.375 6h6c.621 0 1.125.504 1.125 1.125v3.75c0 .621-.504 1.125-1.125 1.125h-6a1.125 1.125 0 01-1.125-1.125v-3.75zM14.25 8.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v8.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-8.25zM3.75 16.125c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v2.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-2.25z" />', // RectangleGroup
|
|
107
|
-
flow: '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.625 4.5h12.75a1.875 1.875 0 010 3.75H5.625a1.875 1.875 0 010-3.75z" />', // QueueList
|
|
108
|
-
channel:
|
|
109
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M7.5 21L3 16.5m0 0L7.5 12M3 16.5h13.5m0-13.5L21 7.5m0 0L16.5 12M21 7.5H7.5" />', // ArrowsRightLeft
|
|
110
|
-
diagram:
|
|
111
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M9 6.75V15m6-6v8.25m.503 3.498l4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 00-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0z" />', // Map
|
|
112
|
-
container:
|
|
113
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" />', // Database
|
|
114
|
-
user: '<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0zM4.501 20.118a7.5 7.5 0 0114.998 0A17.933 17.933 0 0112 21.75c-2.676 0-5.216-.584-7.499-1.632z" />', // User
|
|
115
|
-
team: '<path stroke-linecap="round" stroke-linejoin="round" d="M18 18.72a9.094 9.094 0 003.741-.479 3 3 0 00-4.682-2.72m.94 3.198l.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0112 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 016 18.719m12 0a5.971 5.971 0 00-.941-3.197m0 0A5.995 5.995 0 0012 12.75a5.995 5.995 0 00-5.058 2.772m0 0a3 3 0 00-4.681 2.72 8.986 8.986 0 003.74.477m.94-3.197a5.971 5.971 0 00-.94 3.197M15 6.75a3 3 0 11-6 0 3 3 0 016 0zm6 3a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0zm-13.5 0a2.25 2.25 0 11-4.5 0 2.25 2.25 0 014.5 0z" />', // UserGroup
|
|
116
|
-
doc: '<path stroke-linecap="round" stroke-linejoin="round" d="M14 2v4a2 2 0 002 2h4" /><path stroke-linecap="round" stroke-linejoin="round" d="M15 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V7z" /><path stroke-linecap="round" stroke-linejoin="round" d="M10 9H8" /><path stroke-linecap="round" stroke-linejoin="round" d="M16 13H8" /><path stroke-linecap="round" stroke-linejoin="round" d="M16 17H8" />', // FileText
|
|
117
|
-
'data-product':
|
|
118
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M21 7.5l-9-5.25L3 7.5m18 0l-9 5.25M21 7.5v9l-9 5.25M3 7.5l9 5.25M3 7.5v9l9 5.25m0-9v9" />', // Cube
|
|
119
|
-
system:
|
|
120
|
-
'<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 7.125C2.25 6.504 2.754 6 3.375 6h6c.621 0 1.125.504 1.125 1.125v3.75c0 .621-.504 1.125-1.125 1.125h-6a1.125 1.125 0 01-1.125-1.125v-3.75zM14.25 8.625c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v8.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-8.25zM3.75 16.125c0-.621.504-1.125 1.125-1.125h5.25c.621 0 1.125.504 1.125 1.125v2.25c0 .621-.504 1.125-1.125 1.125h-5.25a1.125 1.125 0 01-1.125-1.125v-2.25z" />', // Group (systems)
|
|
121
|
-
adr: '<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" /><path stroke-linecap="round" stroke-linejoin="round" d="M9 7h2" />', // ClipboardList-ish (ADR)
|
|
122
|
-
};
|
|
123
|
-
|
|
124
92
|
const label = typeLabels[type] || typeLabels.entity;
|
|
125
|
-
const iconPath =
|
|
93
|
+
const iconPath = getResourceReferenceIcon(type);
|
|
126
94
|
const resourceReferenceStyle = getResourceReferenceStyle(type);
|
|
127
95
|
|
|
128
96
|
let resource: any = null;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
type UIMessage,
|
|
11
11
|
} from 'ai';
|
|
12
12
|
import { join } from 'node:path';
|
|
13
|
-
import { isDevMode } from '@utils/feature';
|
|
13
|
+
import { isCanvasEnabled, isDevMode } from '@utils/feature';
|
|
14
14
|
import { getCollection, getEntry } from 'astro:content';
|
|
15
15
|
import { z } from 'astro/zod';
|
|
16
16
|
import { getConsumersOfMessage, getProducersOfMessage } from '@utils/collections/services';
|
|
@@ -38,6 +38,8 @@ const catalogDirectory = process.env.PROJECT_DIR || process.cwd();
|
|
|
38
38
|
// How many model calls one answer may take. Questions across several domains need many tool calls, so the last
|
|
39
39
|
// step has tools turned off: the model has to answer with what it found, rather than stop without a reply.
|
|
40
40
|
const MAX_STEPS = 10;
|
|
41
|
+
// Drawing a diagram on a Studio canvas takes more: finding the resources, adding them, connecting and tidying
|
|
42
|
+
const MAX_CANVAS_STEPS = 20;
|
|
41
43
|
|
|
42
44
|
export const defaultConfiguration = {
|
|
43
45
|
temperature: 0.4,
|
|
@@ -204,7 +206,8 @@ export const GET = async ({ request }: APIContext<{ question: string; messages:
|
|
|
204
206
|
};
|
|
205
207
|
|
|
206
208
|
export const POST = async ({ request }: APIContext<{ question: string; messages: Message[]; additionalContext?: string }>) => {
|
|
207
|
-
|
|
209
|
+
// canvasId: the Studio canvas the assistant was opened on, which it can draw on
|
|
210
|
+
const { messages, canvasId }: { messages: UIMessage[]; canvasId?: string } = await request.json();
|
|
208
211
|
|
|
209
212
|
if (!hasChatConfiguration) {
|
|
210
213
|
return chatConfigurationErrorResponse();
|
|
@@ -214,6 +217,12 @@ export const POST = async ({ request }: APIContext<{ question: string; messages:
|
|
|
214
217
|
const referrer = request.headers.get('referer');
|
|
215
218
|
|
|
216
219
|
try {
|
|
220
|
+
const canvas =
|
|
221
|
+
canvasId && isCanvasEnabled()
|
|
222
|
+
? (await import('@features/studio/server/assistant-tools')).getCanvasAssistant(canvasId)
|
|
223
|
+
: undefined;
|
|
224
|
+
const maxSteps = canvas ? MAX_CANVAS_STEPS : MAX_STEPS;
|
|
225
|
+
|
|
217
226
|
const tools = {
|
|
218
227
|
getResources: tool({
|
|
219
228
|
description: toolDescriptions.getResources,
|
|
@@ -390,19 +399,29 @@ export const POST = async ({ request }: APIContext<{ question: string; messages:
|
|
|
390
399
|
return { suggestions: questions };
|
|
391
400
|
},
|
|
392
401
|
}),
|
|
402
|
+
...canvas?.tools,
|
|
393
403
|
...extendedTools,
|
|
394
404
|
};
|
|
395
405
|
|
|
396
406
|
const result = streamText({
|
|
397
407
|
model,
|
|
398
|
-
instructions: getBaseSystemPrompt(referrer ?? ''),
|
|
408
|
+
instructions: getBaseSystemPrompt(referrer ?? '') + (canvas?.instructions ?? ''),
|
|
399
409
|
messages: await convertToModelMessages(messages),
|
|
400
410
|
temperature: modelConfiguration?.temperature ?? 0.7,
|
|
401
|
-
|
|
402
|
-
|
|
411
|
+
// The provider's own options (e.g. { anthropic: { effort: 'low' } }), from eventcatalog.chat.js's configuration
|
|
412
|
+
providerOptions: modelConfiguration?.providerOptions,
|
|
413
|
+
stopWhen: isStepCount(maxSteps),
|
|
414
|
+
prepareStep: ({ stepNumber }) => (stepNumber === maxSteps - 1 ? { toolChoice: 'none' } : undefined),
|
|
403
415
|
onError: (error) => {
|
|
404
416
|
console.error('[Chat] On error', error);
|
|
405
417
|
},
|
|
418
|
+
// On a canvas: shown planning while it writes what to add, and what it drew tidied once it's finished
|
|
419
|
+
...(canvas && {
|
|
420
|
+
onChunk: ({ chunk }) => {
|
|
421
|
+
if (chunk.type === 'tool-input-start') canvas.startedWriting(chunk.toolName);
|
|
422
|
+
},
|
|
423
|
+
onEnd: () => canvas.finished().catch((error) => console.error('[Chat] Could not tidy the canvas', error)),
|
|
424
|
+
}),
|
|
406
425
|
tools,
|
|
407
426
|
});
|
|
408
427
|
|