@docyrus/ui-pro-ai-assistant 0.0.2 → 0.0.3
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/package.json +2 -3
- package/src/components/assistant-animations.tsx +0 -29
- package/src/components/assistant-dialogs.tsx +0 -235
- package/src/components/code-view.tsx +0 -278
- package/src/components/create-agent-task.tsx +0 -104
- package/src/components/create-new-work-version.tsx +0 -30
- package/src/components/extract-web.tsx +0 -160
- package/src/components/forward-to-agent.tsx +0 -90
- package/src/components/generate-chart.tsx +0 -101
- package/src/components/generative-action-button.tsx +0 -122
- package/src/components/generative-tool.tsx +0 -685
- package/src/components/generative-ui-object.tsx +0 -210
- package/src/components/input-area.tsx +0 -1209
- package/src/components/json-schema-layout.tsx +0 -326
- package/src/components/list-item-card.tsx +0 -92
- package/src/components/mermaid-diagram.tsx +0 -192
- package/src/components/preview-image.tsx +0 -47
- package/src/components/request-approval.tsx +0 -48
- package/src/components/request-user-input.tsx +0 -270
- package/src/components/search-web.tsx +0 -319
- package/src/components/sheet-command.tsx +0 -88
- package/src/components/shell-canvas.tsx +0 -122
- package/src/components/show-advanced-data-table.tsx +0 -352
- package/src/components/show-generated-content-options.tsx +0 -93
- package/src/components/show-people-cards.tsx +0 -180
- package/src/components/subagent-tool.tsx +0 -180
- package/src/components/text-editor-tool.tsx +0 -328
- package/src/components/work-canvas.tsx +0 -88
- package/src/components/work-card.tsx +0 -42
- package/src/declarations.d.ts +0 -1
- package/src/docy-assistant.tsx +0 -1962
- package/src/hooks/index.ts +0 -7
- package/src/hooks/use-assistant-api.ts +0 -507
- package/src/hooks/use-deployment-data.ts +0 -162
- package/src/hooks/use-project-state.ts +0 -347
- package/src/hooks/use-session-state.ts +0 -207
- package/src/hooks/use-speech-recognition.ts +0 -137
- package/src/hooks/use-ui-state.ts +0 -185
- package/src/hooks/use-works-state.ts +0 -146
- package/src/i18n/context.tsx +0 -253
- package/src/i18n/index.ts +0 -19
- package/src/i18n/locales/de.json +0 -198
- package/src/i18n/locales/el.json +0 -198
- package/src/i18n/locales/en.json +0 -226
- package/src/i18n/locales/es.json +0 -198
- package/src/i18n/locales/fr.json +0 -198
- package/src/i18n/locales/it.json +0 -198
- package/src/i18n/locales/pt.json +0 -198
- package/src/i18n/locales/sl.json +0 -198
- package/src/i18n/locales/tr.json +0 -211
- package/src/i18n/types.ts +0 -23
- package/src/i18n/use-translation.ts +0 -17
- package/src/index.ts +0 -18
- package/src/internal/plate-editor/editor/auth-context.ts +0 -11
- package/src/internal/plate-editor/editor/editor-base-kit.tsx +0 -39
- package/src/internal/plate-editor/editor/editor-kit.tsx +0 -89
- package/src/internal/plate-editor/editor/plate-editor.tsx +0 -75
- package/src/internal/plate-editor/editor/plate-types.ts +0 -126
- package/src/internal/plate-editor/editor/plugins/ai-kit.tsx +0 -172
- package/src/internal/plate-editor/editor/plugins/autoformat-kit.tsx +0 -211
- package/src/internal/plate-editor/editor/plugins/basic-blocks-base-kit.tsx +0 -26
- package/src/internal/plate-editor/editor/plugins/basic-blocks-kit.tsx +0 -51
- package/src/internal/plate-editor/editor/plugins/basic-marks-base-kit.tsx +0 -24
- package/src/internal/plate-editor/editor/plugins/basic-marks-kit.tsx +0 -38
- package/src/internal/plate-editor/editor/plugins/basic-nodes-kit.tsx +0 -6
- package/src/internal/plate-editor/editor/plugins/block-menu-kit.tsx +0 -14
- package/src/internal/plate-editor/editor/plugins/block-placeholder-kit.tsx +0 -17
- package/src/internal/plate-editor/editor/plugins/block-selection-kit.tsx +0 -31
- package/src/internal/plate-editor/editor/plugins/callout-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/callout-kit.tsx +0 -7
- package/src/internal/plate-editor/editor/plugins/code-block-base-kit.tsx +0 -23
- package/src/internal/plate-editor/editor/plugins/code-block-kit.tsx +0 -26
- package/src/internal/plate-editor/editor/plugins/column-base-kit.tsx +0 -8
- package/src/internal/plate-editor/editor/plugins/column-kit.tsx +0 -7
- package/src/internal/plate-editor/editor/plugins/comment-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/comment-kit.tsx +0 -174
- package/src/internal/plate-editor/editor/plugins/copilot-kit.tsx +0 -68
- package/src/internal/plate-editor/editor/plugins/cursor-overlay-kit.tsx +0 -13
- package/src/internal/plate-editor/editor/plugins/date-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/date-kit.tsx +0 -7
- package/src/internal/plate-editor/editor/plugins/discussion-kit.tsx +0 -36
- package/src/internal/plate-editor/editor/plugins/dnd-kit.tsx +0 -27
- package/src/internal/plate-editor/editor/plugins/docx-export-kit.tsx +0 -43
- package/src/internal/plate-editor/editor/plugins/docx-kit.tsx +0 -6
- package/src/internal/plate-editor/editor/plugins/emoji-kit.tsx +0 -15
- package/src/internal/plate-editor/editor/plugins/exit-break-kit.tsx +0 -12
- package/src/internal/plate-editor/editor/plugins/floating-toolbar-kit.tsx +0 -19
- package/src/internal/plate-editor/editor/plugins/font-base-kit.tsx +0 -36
- package/src/internal/plate-editor/editor/plugins/font-kit.tsx +0 -47
- package/src/internal/plate-editor/editor/plugins/indent-base-kit.tsx +0 -19
- package/src/internal/plate-editor/editor/plugins/indent-kit.tsx +0 -22
- package/src/internal/plate-editor/editor/plugins/link-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/link-kit.tsx +0 -35
- package/src/internal/plate-editor/editor/plugins/list-base-kit.tsx +0 -24
- package/src/internal/plate-editor/editor/plugins/list-kit.tsx +0 -27
- package/src/internal/plate-editor/editor/plugins/markdown-kit.tsx +0 -18
- package/src/internal/plate-editor/editor/plugins/math-base-kit.tsx +0 -8
- package/src/internal/plate-editor/editor/plugins/math-kit.tsx +0 -10
- package/src/internal/plate-editor/editor/plugins/media-base-kit.tsx +0 -37
- package/src/internal/plate-editor/editor/plugins/media-kit.tsx +0 -53
- package/src/internal/plate-editor/editor/plugins/mention-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/mention-kit.tsx +0 -36
- package/src/internal/plate-editor/editor/plugins/slash-kit.tsx +0 -17
- package/src/internal/plate-editor/editor/plugins/suggestion-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/suggestion-kit.tsx +0 -95
- package/src/internal/plate-editor/editor/plugins/table-base-kit.tsx +0 -20
- package/src/internal/plate-editor/editor/plugins/table-kit.tsx +0 -22
- package/src/internal/plate-editor/editor/plugins/toc-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/toc-kit.tsx +0 -14
- package/src/internal/plate-editor/editor/plugins/toggle-base-kit.tsx +0 -5
- package/src/internal/plate-editor/editor/plugins/toggle-kit.tsx +0 -9
- package/src/internal/plate-editor/editor/transforms.ts +0 -165
- package/src/internal/plate-editor/editor/use-chat.ts +0 -152
- package/src/internal/plate-editor/hooks/index.ts +0 -3
- package/src/internal/plate-editor/hooks/use-copy-to-clipboard.ts +0 -31
- package/src/internal/plate-editor/hooks/use-is-touch-device.ts +0 -26
- package/src/internal/plate-editor/hooks/use-lock-scroll.ts +0 -21
- package/src/internal/plate-editor/hooks/use-media-query.ts +0 -44
- package/src/internal/plate-editor/hooks/use-mounted.ts +0 -18
- package/src/internal/plate-editor/hooks/use-on-click-outside.ts +0 -114
- package/src/internal/plate-editor/hooks/use-upload-file.ts +0 -81
- package/src/internal/plate-editor/i18n/context.tsx +0 -58
- package/src/internal/plate-editor/i18n/index.ts +0 -3
- package/src/internal/plate-editor/i18n/locales/de.json +0 -57
- package/src/internal/plate-editor/i18n/locales/el.json +0 -57
- package/src/internal/plate-editor/i18n/locales/en.json +0 -57
- package/src/internal/plate-editor/i18n/locales/es.json +0 -57
- package/src/internal/plate-editor/i18n/locales/fr.json +0 -57
- package/src/internal/plate-editor/i18n/locales/it.json +0 -57
- package/src/internal/plate-editor/i18n/locales/pt.json +0 -57
- package/src/internal/plate-editor/i18n/locales/sl.json +0 -57
- package/src/internal/plate-editor/i18n/locales/tr.json +0 -57
- package/src/internal/plate-editor/i18n/types.ts +0 -59
- package/src/internal/plate-editor/i18n/use-translation.ts +0 -22
- package/src/internal/plate-editor/index.ts +0 -39
- package/src/internal/plate-editor/lib/ai-output-converter.ts +0 -153
- package/src/internal/plate-editor/lib/download-file.ts +0 -17
- package/src/internal/plate-editor/plate-ui/ai-chat-editor.tsx +0 -24
- package/src/internal/plate-editor/plate-ui/ai-menu.tsx +0 -828
- package/src/internal/plate-editor/plate-ui/ai-node.tsx +0 -41
- package/src/internal/plate-editor/plate-ui/ai-toolbar-button.tsx +0 -25
- package/src/internal/plate-editor/plate-ui/alert-dialog.tsx +0 -145
- package/src/internal/plate-editor/plate-ui/align-toolbar-button.tsx +0 -88
- package/src/internal/plate-editor/plate-ui/avatar.tsx +0 -3
- package/src/internal/plate-editor/plate-ui/block-context-menu.tsx +0 -104
- package/src/internal/plate-editor/plate-ui/block-discussion.tsx +0 -364
- package/src/internal/plate-editor/plate-ui/block-draggable.tsx +0 -557
- package/src/internal/plate-editor/plate-ui/block-list-static.tsx +0 -77
- package/src/internal/plate-editor/plate-ui/block-list.tsx +0 -85
- package/src/internal/plate-editor/plate-ui/block-menu.tsx +0 -555
- package/src/internal/plate-editor/plate-ui/block-selection.tsx +0 -47
- package/src/internal/plate-editor/plate-ui/block-suggestion.tsx +0 -469
- package/src/internal/plate-editor/plate-ui/blockquote-node-static.tsx +0 -10
- package/src/internal/plate-editor/plate-ui/blockquote-node.tsx +0 -11
- package/src/internal/plate-editor/plate-ui/button.tsx +0 -201
- package/src/internal/plate-editor/plate-ui/calendar.tsx +0 -3
- package/src/internal/plate-editor/plate-ui/callout-node-static.tsx +0 -76
- package/src/internal/plate-editor/plate-ui/callout-node.tsx +0 -54
- package/src/internal/plate-editor/plate-ui/caption.tsx +0 -47
- package/src/internal/plate-editor/plate-ui/checkbox.tsx +0 -3
- package/src/internal/plate-editor/plate-ui/code-block-node-static.tsx +0 -172
- package/src/internal/plate-editor/plate-ui/code-block-node.tsx +0 -226
- package/src/internal/plate-editor/plate-ui/code-node-static.tsx +0 -11
- package/src/internal/plate-editor/plate-ui/code-node.tsx +0 -12
- package/src/internal/plate-editor/plate-ui/column-node-static.tsx +0 -65
- package/src/internal/plate-editor/plate-ui/column-node.tsx +0 -24
- package/src/internal/plate-editor/plate-ui/command.tsx +0 -202
- package/src/internal/plate-editor/plate-ui/comment-node-static.tsx +0 -12
- package/src/internal/plate-editor/plate-ui/comment-node.tsx +0 -45
- package/src/internal/plate-editor/plate-ui/comment-toolbar-button.tsx +0 -24
- package/src/internal/plate-editor/plate-ui/comment.tsx +0 -619
- package/src/internal/plate-editor/plate-ui/cursor-overlay.tsx +0 -85
- package/src/internal/plate-editor/plate-ui/date-node-static.tsx +0 -43
- package/src/internal/plate-editor/plate-ui/date-node.tsx +0 -54
- package/src/internal/plate-editor/plate-ui/dialog.tsx +0 -445
- package/src/internal/plate-editor/plate-ui/dropdown-menu.tsx +0 -264
- package/src/internal/plate-editor/plate-ui/editor-static.tsx +0 -40
- package/src/internal/plate-editor/plate-ui/editor.tsx +0 -146
- package/src/internal/plate-editor/plate-ui/emoji-node.tsx +0 -48
- package/src/internal/plate-editor/plate-ui/emoji-toolbar-button.tsx +0 -626
- package/src/internal/plate-editor/plate-ui/equation-node-static.tsx +0 -155
- package/src/internal/plate-editor/plate-ui/equation-node.tsx +0 -226
- package/src/internal/plate-editor/plate-ui/equation-toolbar-button.tsx +0 -26
- package/src/internal/plate-editor/plate-ui/export-toolbar-button.tsx +0 -206
- package/src/internal/plate-editor/plate-ui/fixed-toolbar-buttons.tsx +0 -157
- package/src/internal/plate-editor/plate-ui/fixed-toolbar.tsx +0 -25
- package/src/internal/plate-editor/plate-ui/floating-discussion.tsx +0 -1129
- package/src/internal/plate-editor/plate-ui/floating-toolbar-buttons.tsx +0 -129
- package/src/internal/plate-editor/plate-ui/floating-toolbar.tsx +0 -97
- package/src/internal/plate-editor/plate-ui/font-color-toolbar-button.tsx +0 -209
- package/src/internal/plate-editor/plate-ui/font-size-toolbar-button.tsx +0 -152
- package/src/internal/plate-editor/plate-ui/ghost-text.tsx +0 -20
- package/src/internal/plate-editor/plate-ui/heading-node-static.tsx +0 -52
- package/src/internal/plate-editor/plate-ui/heading-node.tsx +0 -56
- package/src/internal/plate-editor/plate-ui/highlight-node-static.tsx +0 -9
- package/src/internal/plate-editor/plate-ui/highlight-node.tsx +0 -11
- package/src/internal/plate-editor/plate-ui/history-toolbar-button.tsx +0 -50
- package/src/internal/plate-editor/plate-ui/hover-card.tsx +0 -7
- package/src/internal/plate-editor/plate-ui/hr-node-static.tsx +0 -18
- package/src/internal/plate-editor/plate-ui/hr-node.tsx +0 -28
- package/src/internal/plate-editor/plate-ui/import-toolbar-button.tsx +0 -122
- package/src/internal/plate-editor/plate-ui/indent-toolbar-button.tsx +0 -32
- package/src/internal/plate-editor/plate-ui/inline-combobox.tsx +0 -409
- package/src/internal/plate-editor/plate-ui/input.tsx +0 -37
- package/src/internal/plate-editor/plate-ui/insert-toolbar-button.tsx +0 -258
- package/src/internal/plate-editor/plate-ui/label.tsx +0 -1
- package/src/internal/plate-editor/plate-ui/line-height-toolbar-button.tsx +0 -69
- package/src/internal/plate-editor/plate-ui/link-node-static.tsx +0 -15
- package/src/internal/plate-editor/plate-ui/link-node.tsx +0 -33
- package/src/internal/plate-editor/plate-ui/link-toolbar-button.tsx +0 -28
- package/src/internal/plate-editor/plate-ui/link-toolbar.tsx +0 -147
- package/src/internal/plate-editor/plate-ui/list-toolbar-button.tsx +0 -177
- package/src/internal/plate-editor/plate-ui/mark-toolbar-button.tsx +0 -34
- package/src/internal/plate-editor/plate-ui/media-audio-node-static.tsx +0 -21
- package/src/internal/plate-editor/plate-ui/media-audio-node.tsx +0 -32
- package/src/internal/plate-editor/plate-ui/media-embed-node.tsx +0 -103
- package/src/internal/plate-editor/plate-ui/media-file-node-static.tsx +0 -30
- package/src/internal/plate-editor/plate-ui/media-file-node.tsx +0 -52
- package/src/internal/plate-editor/plate-ui/media-image-node-static.tsx +0 -37
- package/src/internal/plate-editor/plate-ui/media-image-node.tsx +0 -183
- package/src/internal/plate-editor/plate-ui/media-placeholder-node.tsx +0 -441
- package/src/internal/plate-editor/plate-ui/media-preview-dialog.tsx +0 -127
- package/src/internal/plate-editor/plate-ui/media-toolbar-button.tsx +0 -227
- package/src/internal/plate-editor/plate-ui/media-toolbar.tsx +0 -214
- package/src/internal/plate-editor/plate-ui/media-upload-toast.tsx +0 -73
- package/src/internal/plate-editor/plate-ui/media-video-node-static.tsx +0 -35
- package/src/internal/plate-editor/plate-ui/media-video-node.tsx +0 -119
- package/src/internal/plate-editor/plate-ui/mention-node-static.tsx +0 -46
- package/src/internal/plate-editor/plate-ui/mention-node.tsx +0 -79
- package/src/internal/plate-editor/plate-ui/menu.tsx +0 -539
- package/src/internal/plate-editor/plate-ui/mode-toolbar-button.tsx +0 -124
- package/src/internal/plate-editor/plate-ui/more-toolbar-button.tsx +0 -34
- package/src/internal/plate-editor/plate-ui/paragraph-node-static.tsx +0 -15
- package/src/internal/plate-editor/plate-ui/paragraph-node.tsx +0 -16
- package/src/internal/plate-editor/plate-ui/popover.tsx +0 -75
- package/src/internal/plate-editor/plate-ui/progress.tsx +0 -1
- package/src/internal/plate-editor/plate-ui/remote-cursor-overlay.tsx +0 -79
- package/src/internal/plate-editor/plate-ui/resize-handle.tsx +0 -86
- package/src/internal/plate-editor/plate-ui/separator.tsx +0 -41
- package/src/internal/plate-editor/plate-ui/slash-node.tsx +0 -433
- package/src/internal/plate-editor/plate-ui/spinner.tsx +0 -1
- package/src/internal/plate-editor/plate-ui/suggestion-node-static.tsx +0 -35
- package/src/internal/plate-editor/plate-ui/suggestion-node.tsx +0 -166
- package/src/internal/plate-editor/plate-ui/suggestion-toolbar-button.tsx +0 -24
- package/src/internal/plate-editor/plate-ui/table-node-static.tsx +0 -84
- package/src/internal/plate-editor/plate-ui/table-node.tsx +0 -283
- package/src/internal/plate-editor/plate-ui/table-toolbar-button.tsx +0 -252
- package/src/internal/plate-editor/plate-ui/tabs.tsx +0 -3
- package/src/internal/plate-editor/plate-ui/textarea.tsx +0 -57
- package/src/internal/plate-editor/plate-ui/toc-node-static.tsx +0 -142
- package/src/internal/plate-editor/plate-ui/toc-node.tsx +0 -57
- package/src/internal/plate-editor/plate-ui/toc-sidebar.tsx +0 -48
- package/src/internal/plate-editor/plate-ui/toggle-node-static.tsx +0 -18
- package/src/internal/plate-editor/plate-ui/toggle-node.tsx +0 -33
- package/src/internal/plate-editor/plate-ui/toggle-toolbar-button.tsx +0 -24
- package/src/internal/plate-editor/plate-ui/toggle.tsx +0 -3
- package/src/internal/plate-editor/plate-ui/toolbar.tsx +0 -378
- package/src/internal/plate-editor/plate-ui/tooltip.tsx +0 -148
- package/src/internal/plate-editor/plate-ui/turn-into-toolbar-button.tsx +0 -175
- package/src/internal/plate-editor/types/index.ts +0 -22
- package/src/internal/plate-editor/vite.ts +0 -284
- package/src/internal/sheets/components/univer-sheets.tsx +0 -1104
- package/src/internal/sheets/i18n/context.tsx +0 -183
- package/src/internal/sheets/i18n/index.ts +0 -19
- package/src/internal/sheets/i18n/locales/de.json +0 -21
- package/src/internal/sheets/i18n/locales/el.json +0 -21
- package/src/internal/sheets/i18n/locales/en.json +0 -21
- package/src/internal/sheets/i18n/locales/es.json +0 -21
- package/src/internal/sheets/i18n/locales/fr.json +0 -21
- package/src/internal/sheets/i18n/locales/it.json +0 -21
- package/src/internal/sheets/i18n/locales/pt.json +0 -21
- package/src/internal/sheets/i18n/locales/sl.json +0 -21
- package/src/internal/sheets/i18n/locales/tr.json +0 -21
- package/src/internal/sheets/i18n/types.ts +0 -23
- package/src/internal/sheets/i18n/use-translation.ts +0 -17
- package/src/internal/sheets/index.ts +0 -14
- package/src/internal/sheets/types/css.d.ts +0 -11
- package/src/internal/sheets/types/index.ts +0 -260
- package/src/internal/sheets/xlsx.ts +0 -1169
- package/src/lib/api-client.ts +0 -77
- package/src/lib/assistant-api-actions.ts +0 -549
- package/src/lib/assistant-config.tsx +0 -75
- package/src/lib/class-utils.ts +0 -40
- package/src/lib/index.ts +0 -7
- package/src/lib/message-utils.ts +0 -131
- package/src/tools/tools-schema.json +0 -512
- package/src/types/index.ts +0 -235
- package/src/views/assistant-view.tsx +0 -1137
- package/src/views/canvas-app.tsx +0 -839
- package/src/views/canvas-code.tsx +0 -93
- package/src/views/canvas-deep-research.tsx +0 -44
- package/src/views/canvas-image.tsx +0 -25
- package/src/views/canvas-record-view.tsx +0 -285
- package/src/views/canvas-spreadsheet.tsx +0 -125
- package/src/views/canvas-text.tsx +0 -52
- package/src/views/canvas.tsx +0 -274
- package/src/views/chat-panel.tsx +0 -149
- package/src/views/index.ts +0 -20
- package/src/views/memories-panel.tsx +0 -365
- package/src/views/message-list.tsx +0 -370
- package/src/views/project-detail.tsx +0 -257
- package/src/views/projects-panel.tsx +0 -131
- package/src/views/sessions-list.tsx +0 -98
- package/src/views/sidebar-content.tsx +0 -256
- package/src/views/work-detail.tsx +0 -98
- package/src/vite.ts +0 -64
- package/src/worker.ts +0 -203
|
@@ -1,1209 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useCallback, useState, type ChangeEvent, type FC, type FormEvent
|
|
3
|
-
} from 'react';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
PromptInput,
|
|
7
|
-
PromptInputButton,
|
|
8
|
-
PromptInputFooter,
|
|
9
|
-
PromptInputSubmit,
|
|
10
|
-
PromptInputTextarea,
|
|
11
|
-
PromptInputTools,
|
|
12
|
-
usePromptInputAttachments
|
|
13
|
-
} from '@docyrus/ui-pro-shared/ai';
|
|
14
|
-
import { Badge } from '@docyrus/ui-pro-shared/components/badge';
|
|
15
|
-
import { Button } from '@docyrus/ui-pro-shared/components/button';
|
|
16
|
-
import {
|
|
17
|
-
Dialog,
|
|
18
|
-
DialogContent,
|
|
19
|
-
DialogFooter,
|
|
20
|
-
DialogHeader,
|
|
21
|
-
DialogTitle
|
|
22
|
-
} from '@docyrus/ui-pro-shared/components/dialog';
|
|
23
|
-
import {
|
|
24
|
-
DropdownMenu,
|
|
25
|
-
DropdownMenuContent,
|
|
26
|
-
DropdownMenuItem,
|
|
27
|
-
DropdownMenuTrigger
|
|
28
|
-
} from '@docyrus/ui-pro-shared/components/dropdown-menu';
|
|
29
|
-
import { ScrollArea } from '@docyrus/ui-pro-shared/components/scroll-area';
|
|
30
|
-
import {
|
|
31
|
-
Tooltip,
|
|
32
|
-
TooltipContent,
|
|
33
|
-
TooltipTrigger
|
|
34
|
-
} from '@docyrus/ui-pro-shared/components/tooltip';
|
|
35
|
-
import { cn } from '@docyrus/ui-pro-shared/lib/utils';
|
|
36
|
-
import {
|
|
37
|
-
AlertCircle, AudioLines, Brain, BrainCircuit, ChevronDown, File, FileSearch, Globe, Inbox, Mic, Microscope, Plug, Plus, Ruler, SlidersHorizontal, Star, X
|
|
38
|
-
} from 'lucide-react';
|
|
39
|
-
import { toast } from 'sonner';
|
|
40
|
-
|
|
41
|
-
import { useDeploymentData } from '../hooks/use-deployment-data';
|
|
42
|
-
import { useAssistantTranslation } from '../i18n';
|
|
43
|
-
import { useApiClient } from '../lib/api-client';
|
|
44
|
-
import { useAssistantConfig } from '../lib/assistant-config';
|
|
45
|
-
|
|
46
|
-
interface SubmitOptions {
|
|
47
|
-
modelId?: string;
|
|
48
|
-
supportMultipleModels?: boolean;
|
|
49
|
-
supportFiles?: boolean;
|
|
50
|
-
supportWebSearch?: boolean;
|
|
51
|
-
supportDeepResearch?: boolean;
|
|
52
|
-
supportDocumentSearch?: boolean;
|
|
53
|
-
supportThinking?: boolean;
|
|
54
|
-
supportWorkCanvas?: boolean;
|
|
55
|
-
files?: { url: string; mediaType: string; filename: string }[];
|
|
56
|
-
mcpServerIds?: string[];
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
interface McpServer {
|
|
60
|
-
id: string;
|
|
61
|
-
name: string;
|
|
62
|
-
logo?: { url?: string; signedUrl?: string };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function McpServersDropdown({
|
|
66
|
-
servers,
|
|
67
|
-
activeMcpServers,
|
|
68
|
-
onToggle,
|
|
69
|
-
disabled,
|
|
70
|
-
tooltip
|
|
71
|
-
}: {
|
|
72
|
-
servers: McpServer[];
|
|
73
|
-
activeMcpServers: Record<string, boolean>;
|
|
74
|
-
onToggle: (id: string, active: boolean) => void;
|
|
75
|
-
disabled?: boolean;
|
|
76
|
-
tooltip: string;
|
|
77
|
-
}) {
|
|
78
|
-
const activeCount = Object.values(activeMcpServers).filter(Boolean).length;
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<DropdownMenu>
|
|
82
|
-
<Tooltip>
|
|
83
|
-
<TooltipTrigger asChild>
|
|
84
|
-
<DropdownMenuTrigger asChild>
|
|
85
|
-
<PromptInputButton
|
|
86
|
-
aria-label={tooltip}
|
|
87
|
-
className="relative"
|
|
88
|
-
disabled={disabled}>
|
|
89
|
-
<Plug className="w-4 h-4" />
|
|
90
|
-
{activeCount > 0 && (
|
|
91
|
-
<span className="absolute -right-1 -top-1 flex size-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground">
|
|
92
|
-
{activeCount}
|
|
93
|
-
</span>
|
|
94
|
-
)}
|
|
95
|
-
</PromptInputButton>
|
|
96
|
-
</DropdownMenuTrigger>
|
|
97
|
-
</TooltipTrigger>
|
|
98
|
-
<TooltipContent side="top">{tooltip}</TooltipContent>
|
|
99
|
-
</Tooltip>
|
|
100
|
-
<DropdownMenuContent align="start" className="min-w-[220px] p-2 z-[10000]">
|
|
101
|
-
<div className="flex flex-col gap-2">
|
|
102
|
-
{servers.map((server) => {
|
|
103
|
-
const isActive = !!activeMcpServers[server.id];
|
|
104
|
-
const logoUrl = server.logo?.signedUrl ?? server.logo?.url;
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<div className="flex items-center justify-between gap-2" key={server.id}>
|
|
108
|
-
<div className="flex min-w-0 items-center gap-2">
|
|
109
|
-
{logoUrl ? (
|
|
110
|
-
<img alt="" className="size-4 flex-shrink-0 rounded-full" src={logoUrl} />
|
|
111
|
-
) : (
|
|
112
|
-
<Plug className="size-4 flex-shrink-0 text-muted-foreground" />
|
|
113
|
-
)}
|
|
114
|
-
<span className="truncate text-sm font-medium">{server.name}</span>
|
|
115
|
-
</div>
|
|
116
|
-
<button
|
|
117
|
-
aria-checked={isActive}
|
|
118
|
-
className={cn(
|
|
119
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2',
|
|
120
|
-
isActive ? 'bg-primary focus:ring-primary' : 'bg-muted focus:ring-muted-foreground',
|
|
121
|
-
disabled && 'cursor-not-allowed opacity-50'
|
|
122
|
-
)}
|
|
123
|
-
disabled={disabled}
|
|
124
|
-
onClick={(e) => {
|
|
125
|
-
e.preventDefault();
|
|
126
|
-
onToggle(server.id, !isActive);
|
|
127
|
-
}}
|
|
128
|
-
role="switch"
|
|
129
|
-
type="button">
|
|
130
|
-
<span className="sr-only">{isActive ? 'Disable' : 'Enable'} {server.name}</span>
|
|
131
|
-
<span className={cn(
|
|
132
|
-
'inline-block size-3 transform rounded-full bg-white shadow transition-transform',
|
|
133
|
-
isActive ? 'translate-x-5' : 'translate-x-1'
|
|
134
|
-
)} />
|
|
135
|
-
</button>
|
|
136
|
-
</div>
|
|
137
|
-
);
|
|
138
|
-
})}
|
|
139
|
-
</div>
|
|
140
|
-
</DropdownMenuContent>
|
|
141
|
-
</DropdownMenu>
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** File upload button - must be rendered inside PromptInput children */
|
|
146
|
-
function FileUploadButton({ tooltip }: { tooltip: string }) {
|
|
147
|
-
const attachments = usePromptInputAttachments();
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<Tooltip>
|
|
151
|
-
<TooltipTrigger asChild>
|
|
152
|
-
<PromptInputButton variant="ghost" onClick={() => attachments.openFileDialog()}>
|
|
153
|
-
<Plus className="w-4 h-4" />
|
|
154
|
-
</PromptInputButton>
|
|
155
|
-
</TooltipTrigger>
|
|
156
|
-
<TooltipContent side="top">{tooltip}</TooltipContent>
|
|
157
|
-
</Tooltip>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/** Attachment preview strip - must be rendered inside PromptInput children */
|
|
162
|
-
function AttachmentPreview() {
|
|
163
|
-
const attachments = usePromptInputAttachments();
|
|
164
|
-
|
|
165
|
-
if (attachments.files.length === 0) return null;
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<div className="flex items-center gap-2 px-3 pt-2 pb-1 overflow-x-auto">
|
|
169
|
-
{attachments.files.map((file) => {
|
|
170
|
-
const isImage = file.mediaType?.startsWith('image/');
|
|
171
|
-
|
|
172
|
-
return (
|
|
173
|
-
<div
|
|
174
|
-
key={file.id}
|
|
175
|
-
className="relative group flex-shrink-0 flex items-center gap-1.5 rounded-lg border bg-background px-2 py-1.5 text-xs">
|
|
176
|
-
{isImage && file.url ? (
|
|
177
|
-
<img
|
|
178
|
-
src={file.url}
|
|
179
|
-
alt={file.filename || 'attachment'}
|
|
180
|
-
className="h-8 w-8 rounded object-cover" />
|
|
181
|
-
) : (
|
|
182
|
-
<File className="h-4 w-4 text-muted-foreground" />
|
|
183
|
-
)}
|
|
184
|
-
<span className="max-w-24 truncate text-muted-foreground">
|
|
185
|
-
{file.filename || 'file'}
|
|
186
|
-
</span>
|
|
187
|
-
<Button
|
|
188
|
-
type="button"
|
|
189
|
-
variant="ghost"
|
|
190
|
-
size="icon"
|
|
191
|
-
onClick={() => attachments.remove(file.id)}
|
|
192
|
-
className="ml-0.5 h-5 w-5 rounded-full text-muted-foreground hover:bg-destructive/10 hover:text-destructive">
|
|
193
|
-
<X className="h-3 w-3" />
|
|
194
|
-
</Button>
|
|
195
|
-
</div>
|
|
196
|
-
);
|
|
197
|
-
})}
|
|
198
|
-
</div>
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/*
|
|
203
|
-
* ---------------------------------------------------------------------------
|
|
204
|
-
* Memory Extraction
|
|
205
|
-
* ---------------------------------------------------------------------------
|
|
206
|
-
*/
|
|
207
|
-
|
|
208
|
-
const MEMORY_LEVELS = [
|
|
209
|
-
{ id: 'user', name: 'User' },
|
|
210
|
-
{ id: 'user_agent', name: 'User Agent' },
|
|
211
|
-
{ id: 'project', name: 'Project' },
|
|
212
|
-
{ id: 'team', name: 'Team' },
|
|
213
|
-
{ id: 'team_agent', name: 'Team Agent' },
|
|
214
|
-
{ id: 'tenant', name: 'Tenant' },
|
|
215
|
-
{ id: 'tenant_agent', name: 'Tenant Agent' }
|
|
216
|
-
];
|
|
217
|
-
|
|
218
|
-
interface MemoryCandidate {
|
|
219
|
-
id?: string;
|
|
220
|
-
title: string;
|
|
221
|
-
content?: string;
|
|
222
|
-
suggestedLevel?: string;
|
|
223
|
-
suggestedImportance?: number;
|
|
224
|
-
tags?: string[];
|
|
225
|
-
reason?: string;
|
|
226
|
-
sourceMessageId?: string;
|
|
227
|
-
_animating?: 'save' | 'skip' | null;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
interface MemoryExtractionDialogProps {
|
|
231
|
-
open: boolean;
|
|
232
|
-
onClose: () => void;
|
|
233
|
-
candidates: MemoryCandidate[];
|
|
234
|
-
loading: boolean;
|
|
235
|
-
error: string | null;
|
|
236
|
-
saving: boolean;
|
|
237
|
-
onSave: (index: number) => void;
|
|
238
|
-
onSkip: (index: number) => void;
|
|
239
|
-
onSaveAll: () => void;
|
|
240
|
-
onSkipAll: () => void;
|
|
241
|
-
onLevelChange: (index: number, level: string) => void;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
function MemoryExtractionDialog({
|
|
245
|
-
open,
|
|
246
|
-
onClose,
|
|
247
|
-
candidates,
|
|
248
|
-
loading,
|
|
249
|
-
error,
|
|
250
|
-
saving,
|
|
251
|
-
onSave,
|
|
252
|
-
onSkip,
|
|
253
|
-
onSaveAll,
|
|
254
|
-
onSkipAll,
|
|
255
|
-
onLevelChange
|
|
256
|
-
}: MemoryExtractionDialogProps) {
|
|
257
|
-
const { t } = useAssistantTranslation();
|
|
258
|
-
|
|
259
|
-
return (
|
|
260
|
-
<Dialog open={open} onOpenChange={o => !o && onClose()}>
|
|
261
|
-
<DialogContent className="flex max-h-[80vh] max-w-xl flex-col">
|
|
262
|
-
<DialogHeader>
|
|
263
|
-
<DialogTitle className="flex items-center gap-2">
|
|
264
|
-
<Brain className="h-4 w-4" />
|
|
265
|
-
{t('memory_extraction.title')}
|
|
266
|
-
</DialogTitle>
|
|
267
|
-
</DialogHeader>
|
|
268
|
-
|
|
269
|
-
<div className="min-h-0 flex-1 overflow-hidden">
|
|
270
|
-
{loading && (
|
|
271
|
-
<div className="flex flex-col items-center justify-center py-12">
|
|
272
|
-
<div className="mb-4 h-10 w-10 animate-spin rounded-full border-b-2 border-purple-600" />
|
|
273
|
-
<p className="text-sm text-muted-foreground">{t('memory_extraction.loading')}</p>
|
|
274
|
-
</div>
|
|
275
|
-
)}
|
|
276
|
-
|
|
277
|
-
{!loading && error && (
|
|
278
|
-
<div className="flex items-start gap-2 rounded-lg border border-destructive/50 bg-destructive/10 p-4 text-destructive">
|
|
279
|
-
<AlertCircle className="mt-0.5 h-4 w-4 flex-shrink-0" />
|
|
280
|
-
<p className="text-sm">{error}</p>
|
|
281
|
-
</div>
|
|
282
|
-
)}
|
|
283
|
-
|
|
284
|
-
{!loading && !error && candidates.length === 0 && (
|
|
285
|
-
<div className="flex flex-col items-center justify-center py-12">
|
|
286
|
-
<Inbox className="mb-4 h-12 w-12 text-muted-foreground/40" />
|
|
287
|
-
<p className="text-sm text-muted-foreground">{t('memory_extraction.no_suggestions')}</p>
|
|
288
|
-
</div>
|
|
289
|
-
)}
|
|
290
|
-
|
|
291
|
-
{!loading && !error && candidates.length > 0 && (
|
|
292
|
-
<div className="space-y-3">
|
|
293
|
-
<div className="rounded-lg border border-blue-200 bg-blue-50 px-3 py-2 text-xs text-blue-700">
|
|
294
|
-
{t('memory_extraction.info')}
|
|
295
|
-
</div>
|
|
296
|
-
<p className="text-xs text-muted-foreground">
|
|
297
|
-
{t('memory_extraction.count').replace('{{count}}', String(candidates.length))}
|
|
298
|
-
</p>
|
|
299
|
-
<ScrollArea className="h-[340px] pr-2">
|
|
300
|
-
<div className="space-y-2">
|
|
301
|
-
{candidates.map((memory, index) => (
|
|
302
|
-
<div
|
|
303
|
-
key={memory.id ?? index}
|
|
304
|
-
className={cn(
|
|
305
|
-
'rounded-md border bg-background p-2.5 transition-all duration-300',
|
|
306
|
-
memory._animating === 'save' && 'translate-x-full opacity-0',
|
|
307
|
-
memory._animating === 'skip' && '-translate-x-full opacity-0'
|
|
308
|
-
)}>
|
|
309
|
-
<div className="min-w-0 flex-1">
|
|
310
|
-
<div className="flex items-center gap-1.5">
|
|
311
|
-
<p className="truncate text-sm font-medium">{memory.title}</p>
|
|
312
|
-
{memory.suggestedImportance && (
|
|
313
|
-
<span className="flex flex-shrink-0 items-center gap-0.5 text-xs text-muted-foreground">
|
|
314
|
-
<Star className="h-2.5 w-2.5" />
|
|
315
|
-
{memory.suggestedImportance}/10
|
|
316
|
-
</span>
|
|
317
|
-
)}
|
|
318
|
-
</div>
|
|
319
|
-
{memory.content && (
|
|
320
|
-
<p className="mt-0.5 line-clamp-3 text-left text-xs text-muted-foreground">
|
|
321
|
-
{memory.content}
|
|
322
|
-
</p>
|
|
323
|
-
)}
|
|
324
|
-
{memory.tags && memory.tags.length > 0 && (
|
|
325
|
-
<div className="mt-1 flex flex-wrap gap-1">
|
|
326
|
-
{memory.tags.map(tag => (
|
|
327
|
-
<Badge key={tag} variant="secondary" className="px-1.5 py-0 text-xs">
|
|
328
|
-
{tag}
|
|
329
|
-
</Badge>
|
|
330
|
-
))}
|
|
331
|
-
</div>
|
|
332
|
-
)}
|
|
333
|
-
<div className="mt-1.5 flex items-center justify-between gap-1.5">
|
|
334
|
-
<div className="flex items-center gap-1">
|
|
335
|
-
<span className="text-xs text-muted-foreground">{t('memory_extraction.level')}:</span>
|
|
336
|
-
<select
|
|
337
|
-
value={memory.suggestedLevel ?? 'user'}
|
|
338
|
-
onChange={e => onLevelChange(index, e.target.value)}
|
|
339
|
-
onClick={e => e.stopPropagation()}
|
|
340
|
-
className="rounded border bg-background px-1.5 py-0.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary">
|
|
341
|
-
{MEMORY_LEVELS.map(level => (
|
|
342
|
-
<option key={level.id} value={level.id}>{level.name}</option>
|
|
343
|
-
))}
|
|
344
|
-
</select>
|
|
345
|
-
</div>
|
|
346
|
-
<div className="flex flex-shrink-0 gap-1.5">
|
|
347
|
-
<Button
|
|
348
|
-
size="sm"
|
|
349
|
-
variant="outline"
|
|
350
|
-
className="h-6 px-2 text-xs"
|
|
351
|
-
disabled={!!memory._animating}
|
|
352
|
-
onClick={() => onSkip(index)}>
|
|
353
|
-
{t('memory_extraction.skip')}
|
|
354
|
-
</Button>
|
|
355
|
-
<Button
|
|
356
|
-
size="sm"
|
|
357
|
-
className="h-6 bg-emerald-600 px-2 text-xs text-white hover:bg-emerald-700"
|
|
358
|
-
disabled={!!memory._animating}
|
|
359
|
-
onClick={() => onSave(index)}>
|
|
360
|
-
{t('memory_extraction.save')}
|
|
361
|
-
</Button>
|
|
362
|
-
</div>
|
|
363
|
-
</div>
|
|
364
|
-
</div>
|
|
365
|
-
</div>
|
|
366
|
-
))}
|
|
367
|
-
</div>
|
|
368
|
-
</ScrollArea>
|
|
369
|
-
</div>
|
|
370
|
-
)}
|
|
371
|
-
</div>
|
|
372
|
-
|
|
373
|
-
<DialogFooter className="gap-2">
|
|
374
|
-
<Button variant="outline" size="sm" disabled={saving || loading} onClick={onSkipAll}>
|
|
375
|
-
{t('memory_extraction.skip_all')}
|
|
376
|
-
</Button>
|
|
377
|
-
<Button
|
|
378
|
-
size="sm"
|
|
379
|
-
className="bg-emerald-600 text-white hover:bg-emerald-700"
|
|
380
|
-
disabled={saving || loading || candidates.length === 0}
|
|
381
|
-
onClick={onSaveAll}>
|
|
382
|
-
{saving ? '...' : t('memory_extraction.save_all')}
|
|
383
|
-
</Button>
|
|
384
|
-
</DialogFooter>
|
|
385
|
-
</DialogContent>
|
|
386
|
-
</Dialog>
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
interface AIInputAreaProps {
|
|
391
|
-
onSubmit?: (e?: FormEvent, options?: SubmitOptions) => void;
|
|
392
|
-
onStop?: () => void;
|
|
393
|
-
value?: string;
|
|
394
|
-
onChange?: (e: ChangeEvent<HTMLTextAreaElement>) => void;
|
|
395
|
-
placeholder?: string;
|
|
396
|
-
disabled?: boolean;
|
|
397
|
-
isLoading?: boolean;
|
|
398
|
-
supportFiles?: boolean;
|
|
399
|
-
supportWebSearch?: boolean;
|
|
400
|
-
supportDocumentSearch?: boolean;
|
|
401
|
-
supportDeepResearch?: boolean;
|
|
402
|
-
supportThinking?: boolean;
|
|
403
|
-
supportWorkCanvas?: boolean;
|
|
404
|
-
supportMultiModels?: boolean;
|
|
405
|
-
deploymentId?: string;
|
|
406
|
-
tenantAiAgentId?: string;
|
|
407
|
-
enableMicrophone?: boolean;
|
|
408
|
-
enableVoice?: boolean;
|
|
409
|
-
isRecording?: boolean;
|
|
410
|
-
recognition?: any;
|
|
411
|
-
onMicrophoneClick?: () => void;
|
|
412
|
-
footerText?: string;
|
|
413
|
-
className?: string;
|
|
414
|
-
showToolbar?: boolean;
|
|
415
|
-
compactToolbar?: boolean;
|
|
416
|
-
threadId?: string;
|
|
417
|
-
hasMessages?: boolean;
|
|
418
|
-
tenantAiProjectId?: string;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
export const AIInputArea: FC<AIInputAreaProps> = ({
|
|
422
|
-
onSubmit,
|
|
423
|
-
onStop,
|
|
424
|
-
value = '',
|
|
425
|
-
onChange,
|
|
426
|
-
placeholder = 'Type a message...',
|
|
427
|
-
disabled = false,
|
|
428
|
-
isLoading = false,
|
|
429
|
-
supportFiles = false,
|
|
430
|
-
supportWebSearch = false,
|
|
431
|
-
supportDocumentSearch = false,
|
|
432
|
-
supportDeepResearch = false,
|
|
433
|
-
supportThinking = false,
|
|
434
|
-
supportMultiModels = false,
|
|
435
|
-
supportWorkCanvas = false,
|
|
436
|
-
deploymentId,
|
|
437
|
-
tenantAiAgentId,
|
|
438
|
-
enableMicrophone = false,
|
|
439
|
-
enableVoice = false,
|
|
440
|
-
isRecording = false,
|
|
441
|
-
recognition = null,
|
|
442
|
-
onMicrophoneClick,
|
|
443
|
-
footerText,
|
|
444
|
-
className,
|
|
445
|
-
showToolbar = true,
|
|
446
|
-
compactToolbar = false,
|
|
447
|
-
threadId,
|
|
448
|
-
hasMessages = false,
|
|
449
|
-
tenantAiProjectId
|
|
450
|
-
}) => {
|
|
451
|
-
const { t } = useAssistantTranslation();
|
|
452
|
-
|
|
453
|
-
// Determine if we're using a base agent (tenantAiAgentId without deploymentId)
|
|
454
|
-
const isBaseAgent = !deploymentId && !!tenantAiAgentId;
|
|
455
|
-
const idToUse = deploymentId || tenantAiAgentId;
|
|
456
|
-
|
|
457
|
-
const {
|
|
458
|
-
models,
|
|
459
|
-
selectedModel,
|
|
460
|
-
setSelectedModel,
|
|
461
|
-
showMultiModels,
|
|
462
|
-
agents,
|
|
463
|
-
selectedAgent,
|
|
464
|
-
setSelectedAgent,
|
|
465
|
-
showAgents,
|
|
466
|
-
agentAvatar,
|
|
467
|
-
mcpServers,
|
|
468
|
-
activeMcpServers,
|
|
469
|
-
toggleMcpServer,
|
|
470
|
-
capabilities
|
|
471
|
-
} = useDeploymentData(idToUse, supportMultiModels, isBaseAgent);
|
|
472
|
-
|
|
473
|
-
// When agent capabilities are loaded from the API, use them; otherwise fall back to props
|
|
474
|
-
const effectiveSupportWebSearch = capabilities ? capabilities.supportWebSearch : supportWebSearch;
|
|
475
|
-
const effectiveSupportDocumentSearch = capabilities ? capabilities.supportDocumentSearch : supportDocumentSearch;
|
|
476
|
-
const effectiveSupportThinking = capabilities ? capabilities.supportThinking : supportThinking;
|
|
477
|
-
const effectiveSupportDeepResearch = capabilities ? capabilities.supportDeepResearch : supportDeepResearch;
|
|
478
|
-
const effectiveSupportWorkCanvas = capabilities ? capabilities.supportWorkCanvas : supportWorkCanvas;
|
|
479
|
-
|
|
480
|
-
// Toggle states for toolbar features
|
|
481
|
-
const [webSearchActive, setWebSearchActive] = useState(false);
|
|
482
|
-
const [documentSearchActive, setDocumentSearchActive] = useState(false);
|
|
483
|
-
const [thinkingActive, setThinkingActive] = useState(false);
|
|
484
|
-
const [deepResearchActive, setDeepResearchActive] = useState(false);
|
|
485
|
-
const [workCanvasActive, setWorkCanvasActive] = useState(false);
|
|
486
|
-
|
|
487
|
-
const toggleActiveClass = 'bg-primary/10 text-primary hover:bg-primary/20 ring-1 ring-primary/30';
|
|
488
|
-
|
|
489
|
-
// Memory extraction state
|
|
490
|
-
const [memoryExtractionOpen, setMemoryExtractionOpen] = useState(false);
|
|
491
|
-
const [memoryExtractionLoading, setMemoryExtractionLoading] = useState(false);
|
|
492
|
-
const [memoryExtractionError, setMemoryExtractionError] = useState<string | null>(null);
|
|
493
|
-
const [memoryExtractionCandidates, setMemoryExtractionCandidates] = useState<MemoryCandidate[]>([]);
|
|
494
|
-
const [memorySaving, setMemorySaving] = useState(false);
|
|
495
|
-
const apiClient = useApiClient();
|
|
496
|
-
const assistantConfig = useAssistantConfig();
|
|
497
|
-
const tenantUserId = assistantConfig.user?.id;
|
|
498
|
-
|
|
499
|
-
const handleExtractMemories = useCallback(async () => {
|
|
500
|
-
if (!threadId) return;
|
|
501
|
-
setMemoryExtractionOpen(true);
|
|
502
|
-
setMemoryExtractionLoading(true);
|
|
503
|
-
setMemoryExtractionError(null);
|
|
504
|
-
setMemoryExtractionCandidates([]);
|
|
505
|
-
try {
|
|
506
|
-
const result = await apiClient.get('/ai/memory-candidates', { threadId });
|
|
507
|
-
|
|
508
|
-
if ((result as any)?.success === false) {
|
|
509
|
-
throw new Error((result as any)?.error_description || (result as any)?.error || t('memory_extraction.error_extract'));
|
|
510
|
-
}
|
|
511
|
-
const raw = (result as any)?.data?.candidates ?? (result as any)?.candidates ?? result ?? [];
|
|
512
|
-
|
|
513
|
-
setMemoryExtractionCandidates(Array.isArray(raw) ? raw : []);
|
|
514
|
-
} catch (err: unknown) {
|
|
515
|
-
setMemoryExtractionError(err instanceof Error ? err.message : t('memory_extraction.error_extract'));
|
|
516
|
-
} finally {
|
|
517
|
-
setMemoryExtractionLoading(false);
|
|
518
|
-
}
|
|
519
|
-
}, [threadId, apiClient, t]);
|
|
520
|
-
|
|
521
|
-
const saveMemoryCandidate = useCallback(async (index: number) => {
|
|
522
|
-
const memory = memoryExtractionCandidates[index];
|
|
523
|
-
|
|
524
|
-
if (!memory || memory._animating) return;
|
|
525
|
-
setMemoryExtractionCandidates((prev) => {
|
|
526
|
-
const next = [...prev];
|
|
527
|
-
|
|
528
|
-
next[index] = { ...next[index], _animating: 'save' };
|
|
529
|
-
|
|
530
|
-
return next;
|
|
531
|
-
});
|
|
532
|
-
try {
|
|
533
|
-
const result = await apiClient.post('/ai/memories', {
|
|
534
|
-
title: memory.title,
|
|
535
|
-
content: memory.content,
|
|
536
|
-
memoryLevel: memory.suggestedLevel ?? 'user_agent',
|
|
537
|
-
importance: memory.suggestedImportance ?? 3,
|
|
538
|
-
sourceType: 'llm_extraction',
|
|
539
|
-
sourceThreadId: threadId,
|
|
540
|
-
sourceMessageId: memory.sourceMessageId ?? null,
|
|
541
|
-
tenantUserId: tenantUserId ?? null,
|
|
542
|
-
tenantAiAgentId: tenantAiAgentId ?? null,
|
|
543
|
-
tenantAiProjectId: tenantAiProjectId ?? null,
|
|
544
|
-
tags: memory.tags ?? []
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
if ((result as any)?.success === false) {
|
|
548
|
-
throw new Error((result as any)?.error_description || (result as any)?.error || t('memory_extraction.error_save'));
|
|
549
|
-
}
|
|
550
|
-
toast.success(t('memory_extraction.success_saved'));
|
|
551
|
-
setTimeout(() => {
|
|
552
|
-
setMemoryExtractionCandidates((prev) => {
|
|
553
|
-
const next = prev.filter((_, i) => i !== index);
|
|
554
|
-
|
|
555
|
-
if (next.length === 0) {
|
|
556
|
-
setMemoryExtractionOpen(false);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
return next;
|
|
560
|
-
});
|
|
561
|
-
}, 300);
|
|
562
|
-
} catch {
|
|
563
|
-
setMemoryExtractionCandidates((prev) => {
|
|
564
|
-
const next = [...prev];
|
|
565
|
-
|
|
566
|
-
next[index] = { ...next[index], _animating: null };
|
|
567
|
-
|
|
568
|
-
return next;
|
|
569
|
-
});
|
|
570
|
-
toast.error(t('memory_extraction.error_save'));
|
|
571
|
-
}
|
|
572
|
-
}, [
|
|
573
|
-
memoryExtractionCandidates,
|
|
574
|
-
threadId,
|
|
575
|
-
apiClient,
|
|
576
|
-
tenantUserId,
|
|
577
|
-
tenantAiAgentId,
|
|
578
|
-
tenantAiProjectId,
|
|
579
|
-
t
|
|
580
|
-
]);
|
|
581
|
-
|
|
582
|
-
const skipMemoryCandidate = useCallback((index: number) => {
|
|
583
|
-
const memory = memoryExtractionCandidates[index];
|
|
584
|
-
|
|
585
|
-
if (!memory || memory._animating) return;
|
|
586
|
-
setMemoryExtractionCandidates((prev) => {
|
|
587
|
-
const next = [...prev];
|
|
588
|
-
|
|
589
|
-
next[index] = { ...next[index], _animating: 'skip' };
|
|
590
|
-
|
|
591
|
-
return next;
|
|
592
|
-
});
|
|
593
|
-
setTimeout(() => {
|
|
594
|
-
setMemoryExtractionCandidates((prev) => {
|
|
595
|
-
const next = prev.filter((_, i) => i !== index);
|
|
596
|
-
|
|
597
|
-
if (next.length === 0) {
|
|
598
|
-
toast.info(t('memory_extraction.success_all_skipped'));
|
|
599
|
-
setMemoryExtractionOpen(false);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
return next;
|
|
603
|
-
});
|
|
604
|
-
}, 300);
|
|
605
|
-
}, [memoryExtractionCandidates, t]);
|
|
606
|
-
|
|
607
|
-
const saveAllMemoryCandidates = useCallback(async () => {
|
|
608
|
-
if (memoryExtractionCandidates.length === 0) return;
|
|
609
|
-
setMemorySaving(true);
|
|
610
|
-
try {
|
|
611
|
-
const results = await Promise.all(
|
|
612
|
-
memoryExtractionCandidates.map(memory => apiClient.post('/ai/memories', {
|
|
613
|
-
title: memory.title,
|
|
614
|
-
content: memory.content,
|
|
615
|
-
memoryLevel: memory.suggestedLevel ?? 'user_agent',
|
|
616
|
-
importance: memory.suggestedImportance ?? 3,
|
|
617
|
-
sourceType: 'llm_extraction',
|
|
618
|
-
sourceThreadId: threadId,
|
|
619
|
-
tenantUserId: tenantUserId ?? null,
|
|
620
|
-
tenantAiAgentId: tenantAiAgentId ?? null,
|
|
621
|
-
tenantAiProjectId: tenantAiProjectId ?? null,
|
|
622
|
-
tags: memory.tags ?? []
|
|
623
|
-
}))
|
|
624
|
-
);
|
|
625
|
-
const failed = results.find((r: any) => r?.success === false);
|
|
626
|
-
|
|
627
|
-
if (failed) {
|
|
628
|
-
throw new Error((failed as any)?.error_description || (failed as any)?.error || t('memory_extraction.error_save'));
|
|
629
|
-
}
|
|
630
|
-
toast.success(t('memory_extraction.success_all_saved'));
|
|
631
|
-
setMemoryExtractionCandidates([]);
|
|
632
|
-
setMemoryExtractionOpen(false);
|
|
633
|
-
} catch {
|
|
634
|
-
toast.error(t('memory_extraction.error_save'));
|
|
635
|
-
} finally {
|
|
636
|
-
setMemorySaving(false);
|
|
637
|
-
}
|
|
638
|
-
}, [
|
|
639
|
-
memoryExtractionCandidates,
|
|
640
|
-
threadId,
|
|
641
|
-
apiClient,
|
|
642
|
-
tenantUserId,
|
|
643
|
-
tenantAiAgentId,
|
|
644
|
-
tenantAiProjectId,
|
|
645
|
-
t
|
|
646
|
-
]);
|
|
647
|
-
|
|
648
|
-
const skipAllMemoryCandidates = useCallback(() => {
|
|
649
|
-
setMemoryExtractionCandidates([]);
|
|
650
|
-
setMemoryExtractionOpen(false);
|
|
651
|
-
toast.info(t('memory_extraction.success_all_skipped'));
|
|
652
|
-
}, [t]);
|
|
653
|
-
|
|
654
|
-
const handleMemoryLevelChange = useCallback((index: number, level: string) => {
|
|
655
|
-
setMemoryExtractionCandidates((prev) => {
|
|
656
|
-
const next = [...prev];
|
|
657
|
-
|
|
658
|
-
next[index] = { ...next[index], suggestedLevel: level };
|
|
659
|
-
|
|
660
|
-
return next;
|
|
661
|
-
});
|
|
662
|
-
}, []);
|
|
663
|
-
|
|
664
|
-
const handlePromptSubmit = useCallback((message: { text: string; files: any[] }) => {
|
|
665
|
-
if (onSubmit) {
|
|
666
|
-
const activeMcpServerIds = Object.entries(activeMcpServers)
|
|
667
|
-
.filter(([, active]) => active)
|
|
668
|
-
.map(([id]) => id);
|
|
669
|
-
|
|
670
|
-
const options: SubmitOptions = {
|
|
671
|
-
modelId: selectedModel?.id,
|
|
672
|
-
supportMultipleModels: showMultiModels,
|
|
673
|
-
supportFiles,
|
|
674
|
-
supportWebSearch: effectiveSupportWebSearch && webSearchActive,
|
|
675
|
-
supportDeepResearch: effectiveSupportDeepResearch && deepResearchActive,
|
|
676
|
-
supportDocumentSearch: effectiveSupportDocumentSearch && documentSearchActive,
|
|
677
|
-
supportThinking: effectiveSupportThinking && thinkingActive,
|
|
678
|
-
supportWorkCanvas: effectiveSupportWorkCanvas && workCanvasActive,
|
|
679
|
-
files: message.files?.length > 0 ? message.files : undefined,
|
|
680
|
-
mcpServerIds: activeMcpServerIds.length > 0 ? activeMcpServerIds : undefined
|
|
681
|
-
};
|
|
682
|
-
|
|
683
|
-
onSubmit(undefined, options);
|
|
684
|
-
}
|
|
685
|
-
}, [
|
|
686
|
-
onSubmit,
|
|
687
|
-
selectedModel?.id,
|
|
688
|
-
showMultiModels,
|
|
689
|
-
supportFiles,
|
|
690
|
-
effectiveSupportWebSearch,
|
|
691
|
-
webSearchActive,
|
|
692
|
-
effectiveSupportDeepResearch,
|
|
693
|
-
deepResearchActive,
|
|
694
|
-
effectiveSupportDocumentSearch,
|
|
695
|
-
documentSearchActive,
|
|
696
|
-
effectiveSupportThinking,
|
|
697
|
-
thinkingActive,
|
|
698
|
-
effectiveSupportWorkCanvas,
|
|
699
|
-
workCanvasActive,
|
|
700
|
-
activeMcpServers
|
|
701
|
-
]);
|
|
702
|
-
|
|
703
|
-
const status = isLoading ? 'streaming' : 'ready';
|
|
704
|
-
const isDisabled = isLoading ? false : (disabled || !value.trim());
|
|
705
|
-
|
|
706
|
-
return (
|
|
707
|
-
<div className={className}>
|
|
708
|
-
<PromptInput
|
|
709
|
-
onSubmit={handlePromptSubmit}
|
|
710
|
-
accept={supportFiles ? 'image/*,.pdf,.docx,.csv,.xlsx,.md,.txt,.json' : undefined}
|
|
711
|
-
multiple
|
|
712
|
-
className="shadow-md bg-background rounded-2xl focus:border-none">
|
|
713
|
-
{supportFiles && <AttachmentPreview />}
|
|
714
|
-
<PromptInputTextarea
|
|
715
|
-
placeholder={placeholder}
|
|
716
|
-
className="text-sm min-h-12"
|
|
717
|
-
value={value}
|
|
718
|
-
onChange={onChange} />
|
|
719
|
-
|
|
720
|
-
{compactToolbar && (() => {
|
|
721
|
-
const hasSupport = effectiveSupportWebSearch || effectiveSupportDocumentSearch || effectiveSupportThinking || effectiveSupportDeepResearch || effectiveSupportWorkCanvas;
|
|
722
|
-
const activeCount = [
|
|
723
|
-
effectiveSupportWebSearch && webSearchActive,
|
|
724
|
-
effectiveSupportDocumentSearch && documentSearchActive,
|
|
725
|
-
effectiveSupportThinking && thinkingActive,
|
|
726
|
-
effectiveSupportDeepResearch && deepResearchActive,
|
|
727
|
-
effectiveSupportWorkCanvas && workCanvasActive
|
|
728
|
-
].filter(Boolean).length;
|
|
729
|
-
|
|
730
|
-
return (
|
|
731
|
-
<PromptInputFooter className="gap-2">
|
|
732
|
-
<PromptInputTools>
|
|
733
|
-
{supportFiles && <FileUploadButton tooltip={t('tools.file_upload')} />}
|
|
734
|
-
|
|
735
|
-
{hasSupport && (
|
|
736
|
-
<DropdownMenu>
|
|
737
|
-
<Tooltip>
|
|
738
|
-
<TooltipTrigger asChild>
|
|
739
|
-
<DropdownMenuTrigger asChild>
|
|
740
|
-
<PromptInputButton
|
|
741
|
-
variant="ghost"
|
|
742
|
-
aria-label={t('tools.options')}
|
|
743
|
-
className={cn('relative', activeCount > 0 && toggleActiveClass)}>
|
|
744
|
-
<SlidersHorizontal className="w-4 h-4" />
|
|
745
|
-
{activeCount > 0 && (
|
|
746
|
-
<span className="absolute -right-1 -top-1 flex size-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground">
|
|
747
|
-
{activeCount}
|
|
748
|
-
</span>
|
|
749
|
-
)}
|
|
750
|
-
</PromptInputButton>
|
|
751
|
-
</DropdownMenuTrigger>
|
|
752
|
-
</TooltipTrigger>
|
|
753
|
-
<TooltipContent side="top">{t('tools.options')}</TooltipContent>
|
|
754
|
-
</Tooltip>
|
|
755
|
-
<DropdownMenuContent align="start" className="min-w-[220px] p-2 z-[10000]">
|
|
756
|
-
<div className="flex flex-col gap-2">
|
|
757
|
-
{effectiveSupportWebSearch && (
|
|
758
|
-
<div className="flex items-center justify-between gap-2">
|
|
759
|
-
<div className="flex items-center gap-2">
|
|
760
|
-
<Globe className="w-4 h-4 text-muted-foreground" />
|
|
761
|
-
<span className="text-sm font-medium">{t('tools.web_search')}</span>
|
|
762
|
-
</div>
|
|
763
|
-
<button
|
|
764
|
-
role="switch"
|
|
765
|
-
type="button"
|
|
766
|
-
aria-checked={webSearchActive}
|
|
767
|
-
onClick={() => setWebSearchActive(p => !p)}
|
|
768
|
-
className={cn(
|
|
769
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none',
|
|
770
|
-
webSearchActive ? 'bg-primary' : 'bg-muted'
|
|
771
|
-
)}>
|
|
772
|
-
<span className={cn('inline-block size-3 transform rounded-full bg-white shadow transition-transform', webSearchActive ? 'translate-x-5' : 'translate-x-1')} />
|
|
773
|
-
</button>
|
|
774
|
-
</div>
|
|
775
|
-
)}
|
|
776
|
-
{effectiveSupportDocumentSearch && (
|
|
777
|
-
<div className="flex items-center justify-between gap-2">
|
|
778
|
-
<div className="flex items-center gap-2">
|
|
779
|
-
<FileSearch className="w-4 h-4 text-muted-foreground" />
|
|
780
|
-
<span className="text-sm font-medium">{t('tools.document_search')}</span>
|
|
781
|
-
</div>
|
|
782
|
-
<button
|
|
783
|
-
role="switch"
|
|
784
|
-
type="button"
|
|
785
|
-
aria-checked={documentSearchActive}
|
|
786
|
-
onClick={() => setDocumentSearchActive(p => !p)}
|
|
787
|
-
className={cn(
|
|
788
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none',
|
|
789
|
-
documentSearchActive ? 'bg-primary' : 'bg-muted'
|
|
790
|
-
)}>
|
|
791
|
-
<span className={cn('inline-block size-3 transform rounded-full bg-white shadow transition-transform', documentSearchActive ? 'translate-x-5' : 'translate-x-1')} />
|
|
792
|
-
</button>
|
|
793
|
-
</div>
|
|
794
|
-
)}
|
|
795
|
-
{effectiveSupportThinking && (
|
|
796
|
-
<div className="flex items-center justify-between gap-2">
|
|
797
|
-
<div className="flex items-center gap-2">
|
|
798
|
-
<Brain className="w-4 h-4 text-muted-foreground" />
|
|
799
|
-
<span className="text-sm font-medium">{t('tools.thinking')}</span>
|
|
800
|
-
</div>
|
|
801
|
-
<button
|
|
802
|
-
role="switch"
|
|
803
|
-
type="button"
|
|
804
|
-
aria-checked={thinkingActive}
|
|
805
|
-
onClick={() => setThinkingActive(p => !p)}
|
|
806
|
-
className={cn(
|
|
807
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none',
|
|
808
|
-
thinkingActive ? 'bg-primary' : 'bg-muted'
|
|
809
|
-
)}>
|
|
810
|
-
<span className={cn('inline-block size-3 transform rounded-full bg-white shadow transition-transform', thinkingActive ? 'translate-x-5' : 'translate-x-1')} />
|
|
811
|
-
</button>
|
|
812
|
-
</div>
|
|
813
|
-
)}
|
|
814
|
-
{effectiveSupportDeepResearch && (
|
|
815
|
-
<div className="flex items-center justify-between gap-2">
|
|
816
|
-
<div className="flex items-center gap-2">
|
|
817
|
-
<Microscope className="w-4 h-4 text-muted-foreground" />
|
|
818
|
-
<span className="text-sm font-medium">{t('tools.deep_research')}</span>
|
|
819
|
-
</div>
|
|
820
|
-
<button
|
|
821
|
-
role="switch"
|
|
822
|
-
type="button"
|
|
823
|
-
aria-checked={deepResearchActive}
|
|
824
|
-
onClick={() => setDeepResearchActive(p => !p)}
|
|
825
|
-
className={cn(
|
|
826
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none',
|
|
827
|
-
deepResearchActive ? 'bg-primary' : 'bg-muted'
|
|
828
|
-
)}>
|
|
829
|
-
<span className={cn('inline-block size-3 transform rounded-full bg-white shadow transition-transform', deepResearchActive ? 'translate-x-5' : 'translate-x-1')} />
|
|
830
|
-
</button>
|
|
831
|
-
</div>
|
|
832
|
-
)}
|
|
833
|
-
{effectiveSupportWorkCanvas && (
|
|
834
|
-
<div className="flex items-center justify-between gap-2">
|
|
835
|
-
<div className="flex items-center gap-2">
|
|
836
|
-
<Ruler className="w-4 h-4 text-muted-foreground" />
|
|
837
|
-
<span className="text-sm font-medium">{t('tools.work_canvas')}</span>
|
|
838
|
-
</div>
|
|
839
|
-
<button
|
|
840
|
-
role="switch"
|
|
841
|
-
type="button"
|
|
842
|
-
aria-checked={workCanvasActive}
|
|
843
|
-
onClick={() => setWorkCanvasActive(p => !p)}
|
|
844
|
-
className={cn(
|
|
845
|
-
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors focus:outline-none',
|
|
846
|
-
workCanvasActive ? 'bg-primary' : 'bg-muted'
|
|
847
|
-
)}>
|
|
848
|
-
<span className={cn('inline-block size-3 transform rounded-full bg-white shadow transition-transform', workCanvasActive ? 'translate-x-5' : 'translate-x-1')} />
|
|
849
|
-
</button>
|
|
850
|
-
</div>
|
|
851
|
-
)}
|
|
852
|
-
</div>
|
|
853
|
-
</DropdownMenuContent>
|
|
854
|
-
</DropdownMenu>
|
|
855
|
-
)}
|
|
856
|
-
|
|
857
|
-
{/* MCP Servers */}
|
|
858
|
-
{mcpServers.length > 0 && (
|
|
859
|
-
<McpServersDropdown
|
|
860
|
-
servers={mcpServers.map(s => ({
|
|
861
|
-
id: s.id,
|
|
862
|
-
name: s.name,
|
|
863
|
-
logo: s.logo ? { url: s.logo.url, signedUrl: s.logo.signed_url } : undefined
|
|
864
|
-
}))}
|
|
865
|
-
activeMcpServers={activeMcpServers}
|
|
866
|
-
onToggle={toggleMcpServer}
|
|
867
|
-
disabled={disabled}
|
|
868
|
-
tooltip={t('tools.mcp_servers')} />
|
|
869
|
-
)}
|
|
870
|
-
|
|
871
|
-
{/* Model selector */}
|
|
872
|
-
{showMultiModels && models.length > 0 && (
|
|
873
|
-
<DropdownMenu>
|
|
874
|
-
<DropdownMenuTrigger asChild>
|
|
875
|
-
<PromptInputButton variant="ghost" size="sm" className="h-7 px-2 gap-1">
|
|
876
|
-
{selectedModel?.providerLogoUrl && (
|
|
877
|
-
<img
|
|
878
|
-
src={selectedModel.providerLogoUrl}
|
|
879
|
-
alt={selectedModel.providerName}
|
|
880
|
-
className="w-3.5 h-3.5 rounded-sm" />
|
|
881
|
-
)}
|
|
882
|
-
<span className="text-xs font-medium max-w-16 truncate">{selectedModel?.name}</span>
|
|
883
|
-
<ChevronDown className="w-3 h-3" />
|
|
884
|
-
</PromptInputButton>
|
|
885
|
-
</DropdownMenuTrigger>
|
|
886
|
-
<DropdownMenuContent className="w-56 h-auto max-h-60 z-[10000]">
|
|
887
|
-
{models.map(model => (
|
|
888
|
-
<DropdownMenuItem
|
|
889
|
-
key={model.id}
|
|
890
|
-
onClick={() => setSelectedModel(model)}
|
|
891
|
-
className="cursor-pointer flex items-center gap-2">
|
|
892
|
-
{model.providerLogoUrl && (
|
|
893
|
-
<img
|
|
894
|
-
src={model.providerLogoUrl}
|
|
895
|
-
alt={model.providerName}
|
|
896
|
-
className="w-4 h-4 rounded-sm" />
|
|
897
|
-
)}
|
|
898
|
-
<div className="flex flex-col">
|
|
899
|
-
<span className="text-sm font-medium">{model.name}</span>
|
|
900
|
-
<span className="text-xs text-muted-foreground">{model.providerName}</span>
|
|
901
|
-
</div>
|
|
902
|
-
</DropdownMenuItem>
|
|
903
|
-
))}
|
|
904
|
-
</DropdownMenuContent>
|
|
905
|
-
</DropdownMenu>
|
|
906
|
-
)}
|
|
907
|
-
</PromptInputTools>
|
|
908
|
-
<PromptInputTools>
|
|
909
|
-
{enableMicrophone && recognition && (
|
|
910
|
-
<Tooltip>
|
|
911
|
-
<TooltipTrigger asChild>
|
|
912
|
-
<PromptInputButton
|
|
913
|
-
variant="ghost"
|
|
914
|
-
onClick={onMicrophoneClick}
|
|
915
|
-
className={cn('transition-all duration-200', isRecording && 'bg-destructive/10 text-destructive hover:bg-destructive/20 ring-1 ring-destructive/30')}>
|
|
916
|
-
<Mic className="w-4 h-4" />
|
|
917
|
-
{isRecording && <div className="absolute -top-1 -right-1 w-2 h-2 bg-destructive rounded-full animate-pulse" />}
|
|
918
|
-
</PromptInputButton>
|
|
919
|
-
</TooltipTrigger>
|
|
920
|
-
<TooltipContent side="top">{isRecording ? t('tools.stop_recording') : t('tools.microphone')}</TooltipContent>
|
|
921
|
-
</Tooltip>
|
|
922
|
-
)}
|
|
923
|
-
<PromptInputSubmit disabled={isDisabled} status={status} onStop={onStop} />
|
|
924
|
-
</PromptInputTools>
|
|
925
|
-
</PromptInputFooter>
|
|
926
|
-
);
|
|
927
|
-
})()}
|
|
928
|
-
|
|
929
|
-
{showToolbar && !compactToolbar && (
|
|
930
|
-
<PromptInputFooter className="gap-2">
|
|
931
|
-
<PromptInputTools>
|
|
932
|
-
{/* File Upload */}
|
|
933
|
-
{supportFiles && (
|
|
934
|
-
<FileUploadButton tooltip={t('tools.file_upload')} />
|
|
935
|
-
)}
|
|
936
|
-
|
|
937
|
-
{/* Web Search */}
|
|
938
|
-
{effectiveSupportWebSearch && (
|
|
939
|
-
<Tooltip>
|
|
940
|
-
<TooltipTrigger asChild>
|
|
941
|
-
<PromptInputButton
|
|
942
|
-
variant="ghost"
|
|
943
|
-
onClick={() => setWebSearchActive(prev => !prev)}
|
|
944
|
-
className={cn(
|
|
945
|
-
'transition-all duration-200',
|
|
946
|
-
webSearchActive && toggleActiveClass
|
|
947
|
-
)}>
|
|
948
|
-
<Globe className="w-4 h-4" />
|
|
949
|
-
</PromptInputButton>
|
|
950
|
-
</TooltipTrigger>
|
|
951
|
-
<TooltipContent side="top">
|
|
952
|
-
{t('tools.web_search')}{webSearchActive ? ` (${t('common.active')})` : ''}
|
|
953
|
-
</TooltipContent>
|
|
954
|
-
</Tooltip>
|
|
955
|
-
)}
|
|
956
|
-
|
|
957
|
-
{/* Document Search */}
|
|
958
|
-
{effectiveSupportDocumentSearch && (
|
|
959
|
-
<Tooltip>
|
|
960
|
-
<TooltipTrigger asChild>
|
|
961
|
-
<PromptInputButton
|
|
962
|
-
variant="ghost"
|
|
963
|
-
onClick={() => setDocumentSearchActive(prev => !prev)}
|
|
964
|
-
className={cn(
|
|
965
|
-
'transition-all duration-200',
|
|
966
|
-
documentSearchActive && toggleActiveClass
|
|
967
|
-
)}>
|
|
968
|
-
<FileSearch className="w-4 h-4" />
|
|
969
|
-
</PromptInputButton>
|
|
970
|
-
</TooltipTrigger>
|
|
971
|
-
<TooltipContent side="top">
|
|
972
|
-
{t('tools.document_search')}{documentSearchActive ? ` (${t('common.active')})` : ''}
|
|
973
|
-
</TooltipContent>
|
|
974
|
-
</Tooltip>
|
|
975
|
-
)}
|
|
976
|
-
|
|
977
|
-
{/* Thinking */}
|
|
978
|
-
{effectiveSupportThinking && (
|
|
979
|
-
<Tooltip>
|
|
980
|
-
<TooltipTrigger asChild>
|
|
981
|
-
<PromptInputButton
|
|
982
|
-
variant="ghost"
|
|
983
|
-
onClick={() => setThinkingActive(prev => !prev)}
|
|
984
|
-
className={cn(
|
|
985
|
-
'transition-all duration-200',
|
|
986
|
-
thinkingActive && toggleActiveClass
|
|
987
|
-
)}>
|
|
988
|
-
<Brain className="w-4 h-4" />
|
|
989
|
-
</PromptInputButton>
|
|
990
|
-
</TooltipTrigger>
|
|
991
|
-
<TooltipContent side="top">
|
|
992
|
-
{t('tools.thinking')}{thinkingActive ? ` (${t('common.active')})` : ''}
|
|
993
|
-
</TooltipContent>
|
|
994
|
-
</Tooltip>
|
|
995
|
-
)}
|
|
996
|
-
|
|
997
|
-
{/* Deep Research */}
|
|
998
|
-
{effectiveSupportDeepResearch && (
|
|
999
|
-
<Tooltip>
|
|
1000
|
-
<TooltipTrigger asChild>
|
|
1001
|
-
<PromptInputButton
|
|
1002
|
-
variant="ghost"
|
|
1003
|
-
onClick={() => setDeepResearchActive(prev => !prev)}
|
|
1004
|
-
className={cn(
|
|
1005
|
-
'transition-all duration-200',
|
|
1006
|
-
deepResearchActive && toggleActiveClass
|
|
1007
|
-
)}>
|
|
1008
|
-
<Microscope className="w-4 h-4" />
|
|
1009
|
-
</PromptInputButton>
|
|
1010
|
-
</TooltipTrigger>
|
|
1011
|
-
<TooltipContent side="top">
|
|
1012
|
-
{t('tools.deep_research')}{deepResearchActive ? ` (${t('common.active')})` : ''}
|
|
1013
|
-
</TooltipContent>
|
|
1014
|
-
</Tooltip>
|
|
1015
|
-
)}
|
|
1016
|
-
|
|
1017
|
-
{/* Work Canvas */}
|
|
1018
|
-
{effectiveSupportWorkCanvas && (
|
|
1019
|
-
<Tooltip>
|
|
1020
|
-
<TooltipTrigger asChild>
|
|
1021
|
-
<PromptInputButton
|
|
1022
|
-
variant="ghost"
|
|
1023
|
-
onClick={() => setWorkCanvasActive(prev => !prev)}
|
|
1024
|
-
className={cn(
|
|
1025
|
-
'transition-all duration-200',
|
|
1026
|
-
workCanvasActive && toggleActiveClass
|
|
1027
|
-
)}>
|
|
1028
|
-
<Ruler className="w-4 h-4" />
|
|
1029
|
-
</PromptInputButton>
|
|
1030
|
-
</TooltipTrigger>
|
|
1031
|
-
<TooltipContent side="top">
|
|
1032
|
-
{t('tools.work_canvas')}{workCanvasActive ? ` (${t('common.active')})` : ''}
|
|
1033
|
-
</TooltipContent>
|
|
1034
|
-
</Tooltip>
|
|
1035
|
-
)}
|
|
1036
|
-
|
|
1037
|
-
{/* MCP Servers */}
|
|
1038
|
-
{mcpServers.length > 0 && (
|
|
1039
|
-
<McpServersDropdown
|
|
1040
|
-
servers={mcpServers.map(s => ({
|
|
1041
|
-
id: s.id,
|
|
1042
|
-
name: s.name,
|
|
1043
|
-
logo: s.logo ? { url: s.logo.url, signedUrl: s.logo.signed_url } : undefined
|
|
1044
|
-
}))}
|
|
1045
|
-
activeMcpServers={activeMcpServers}
|
|
1046
|
-
onToggle={toggleMcpServer}
|
|
1047
|
-
disabled={disabled}
|
|
1048
|
-
tooltip={t('tools.mcp_servers')} />
|
|
1049
|
-
)}
|
|
1050
|
-
|
|
1051
|
-
{/* Multi Models */}
|
|
1052
|
-
{showMultiModels && models.length > 0 && (
|
|
1053
|
-
<DropdownMenu>
|
|
1054
|
-
<DropdownMenuTrigger asChild>
|
|
1055
|
-
<PromptInputButton variant="ghost" size="sm" className="h-7 px-2 gap-1">
|
|
1056
|
-
{selectedModel?.providerLogoUrl && (
|
|
1057
|
-
<img
|
|
1058
|
-
src={selectedModel.providerLogoUrl}
|
|
1059
|
-
alt={selectedModel.providerName}
|
|
1060
|
-
className="w-3.5 h-3.5 rounded-sm" />
|
|
1061
|
-
)}
|
|
1062
|
-
<span className="text-xs font-medium max-w-16 truncate">{selectedModel?.name}</span>
|
|
1063
|
-
<ChevronDown className="w-3 h-3" />
|
|
1064
|
-
</PromptInputButton>
|
|
1065
|
-
</DropdownMenuTrigger>
|
|
1066
|
-
<DropdownMenuContent className="w-56 h-auto max-h-60 z-[10000]">
|
|
1067
|
-
{models.map(model => (
|
|
1068
|
-
<DropdownMenuItem
|
|
1069
|
-
key={model.id}
|
|
1070
|
-
onClick={() => setSelectedModel(model)}
|
|
1071
|
-
className="cursor-pointer flex items-center gap-2">
|
|
1072
|
-
{model.providerLogoUrl && (
|
|
1073
|
-
<img
|
|
1074
|
-
src={model.providerLogoUrl}
|
|
1075
|
-
alt={model.providerName}
|
|
1076
|
-
className="w-4 h-4 rounded-sm" />
|
|
1077
|
-
)}
|
|
1078
|
-
<div className="flex flex-col">
|
|
1079
|
-
<span className="text-sm font-medium">{model.name}</span>
|
|
1080
|
-
<span className="text-xs text-muted-foreground">{model.providerName}</span>
|
|
1081
|
-
</div>
|
|
1082
|
-
</DropdownMenuItem>
|
|
1083
|
-
))}
|
|
1084
|
-
</DropdownMenuContent>
|
|
1085
|
-
</DropdownMenu>
|
|
1086
|
-
)}
|
|
1087
|
-
|
|
1088
|
-
{/* Agent Select */}
|
|
1089
|
-
{showAgents && agents.length > 0 && (
|
|
1090
|
-
<DropdownMenu>
|
|
1091
|
-
<DropdownMenuTrigger asChild>
|
|
1092
|
-
<PromptInputButton variant="ghost" size="sm">
|
|
1093
|
-
{agentAvatar && (
|
|
1094
|
-
<img src={agentAvatar} alt="Agent" className="w-4 h-4 rounded-full object-cover" />
|
|
1095
|
-
)}
|
|
1096
|
-
<span className="text-xs font-medium max-w-24 truncate">{selectedAgent?.skillName}</span>
|
|
1097
|
-
<ChevronDown className="w-3 h-3" />
|
|
1098
|
-
</PromptInputButton>
|
|
1099
|
-
</DropdownMenuTrigger>
|
|
1100
|
-
<DropdownMenuContent className="w-64 z-[10000]">
|
|
1101
|
-
{agents.map(agent => (
|
|
1102
|
-
<DropdownMenuItem
|
|
1103
|
-
key={agent.id}
|
|
1104
|
-
onClick={() => setSelectedAgent(agent)}
|
|
1105
|
-
className="cursor-pointer flex items-center gap-2">
|
|
1106
|
-
{agentAvatar && (
|
|
1107
|
-
<img
|
|
1108
|
-
src={agentAvatar}
|
|
1109
|
-
alt={agent.skillName}
|
|
1110
|
-
className="w-5 h-5 rounded-full object-cover" />
|
|
1111
|
-
)}
|
|
1112
|
-
<span className="text-sm font-medium">{agent.skillName}</span>
|
|
1113
|
-
</DropdownMenuItem>
|
|
1114
|
-
))}
|
|
1115
|
-
</DropdownMenuContent>
|
|
1116
|
-
</DropdownMenu>
|
|
1117
|
-
)}
|
|
1118
|
-
</PromptInputTools>
|
|
1119
|
-
|
|
1120
|
-
<PromptInputTools>
|
|
1121
|
-
|
|
1122
|
-
{/* Microphone Button */}
|
|
1123
|
-
{enableMicrophone && recognition && (
|
|
1124
|
-
<Tooltip>
|
|
1125
|
-
<TooltipTrigger asChild>
|
|
1126
|
-
<PromptInputButton
|
|
1127
|
-
variant="ghost"
|
|
1128
|
-
onClick={onMicrophoneClick}
|
|
1129
|
-
className={cn(
|
|
1130
|
-
'transition-all duration-200',
|
|
1131
|
-
isRecording && 'bg-destructive/10 text-destructive hover:bg-destructive/20 ring-1 ring-destructive/30'
|
|
1132
|
-
)}>
|
|
1133
|
-
<Mic className="w-4 h-4" />
|
|
1134
|
-
{isRecording && (
|
|
1135
|
-
<div className="absolute -top-1 -right-1 w-2 h-2 bg-destructive rounded-full animate-pulse" />
|
|
1136
|
-
)}
|
|
1137
|
-
</PromptInputButton>
|
|
1138
|
-
</TooltipTrigger>
|
|
1139
|
-
<TooltipContent side="top">
|
|
1140
|
-
{isRecording ? t('tools.stop_recording') : t('tools.microphone')}
|
|
1141
|
-
</TooltipContent>
|
|
1142
|
-
</Tooltip>
|
|
1143
|
-
)}
|
|
1144
|
-
|
|
1145
|
-
{/* Voice Button */}
|
|
1146
|
-
{enableVoice && (
|
|
1147
|
-
<Tooltip>
|
|
1148
|
-
<TooltipTrigger asChild>
|
|
1149
|
-
<PromptInputButton variant="ghost">
|
|
1150
|
-
<AudioLines className="w-4 h-4" />
|
|
1151
|
-
</PromptInputButton>
|
|
1152
|
-
</TooltipTrigger>
|
|
1153
|
-
<TooltipContent side="top">{t('tools.voice')}</TooltipContent>
|
|
1154
|
-
</Tooltip>
|
|
1155
|
-
)}
|
|
1156
|
-
|
|
1157
|
-
{/* Submit Button */}
|
|
1158
|
-
<PromptInputSubmit
|
|
1159
|
-
disabled={isDisabled}
|
|
1160
|
-
status={status}
|
|
1161
|
-
onStop={onStop} />
|
|
1162
|
-
</PromptInputTools>
|
|
1163
|
-
</PromptInputFooter>
|
|
1164
|
-
)}
|
|
1165
|
-
|
|
1166
|
-
{!showToolbar && !compactToolbar && (
|
|
1167
|
-
<PromptInputFooter className="border-t-0 pt-0 pb-1 justify-end">
|
|
1168
|
-
<PromptInputSubmit
|
|
1169
|
-
disabled={isDisabled}
|
|
1170
|
-
status={status}
|
|
1171
|
-
onStop={onStop} />
|
|
1172
|
-
</PromptInputFooter>
|
|
1173
|
-
)}
|
|
1174
|
-
</PromptInput>
|
|
1175
|
-
|
|
1176
|
-
{/* Footer */}
|
|
1177
|
-
<div className="relative mt-2 flex items-center px-1">
|
|
1178
|
-
{footerText && <span className="flex-1 text-center text-xs text-muted-foreground">{footerText}</span>}
|
|
1179
|
-
<Tooltip>
|
|
1180
|
-
<TooltipTrigger asChild>
|
|
1181
|
-
<Button
|
|
1182
|
-
type="button"
|
|
1183
|
-
variant="ghost"
|
|
1184
|
-
size="icon"
|
|
1185
|
-
className="absolute right-0 h-6 w-6 text-muted-foreground"
|
|
1186
|
-
disabled={!threadId || !hasMessages}
|
|
1187
|
-
onClick={handleExtractMemories}>
|
|
1188
|
-
<BrainCircuit className="h-3.5 w-3.5" />
|
|
1189
|
-
</Button>
|
|
1190
|
-
</TooltipTrigger>
|
|
1191
|
-
<TooltipContent side="top">{t('tools.extract_memories')}</TooltipContent>
|
|
1192
|
-
</Tooltip>
|
|
1193
|
-
</div>
|
|
1194
|
-
|
|
1195
|
-
<MemoryExtractionDialog
|
|
1196
|
-
open={memoryExtractionOpen}
|
|
1197
|
-
onClose={() => setMemoryExtractionOpen(false)}
|
|
1198
|
-
candidates={memoryExtractionCandidates}
|
|
1199
|
-
loading={memoryExtractionLoading}
|
|
1200
|
-
error={memoryExtractionError}
|
|
1201
|
-
saving={memorySaving}
|
|
1202
|
-
onSave={saveMemoryCandidate}
|
|
1203
|
-
onSkip={skipMemoryCandidate}
|
|
1204
|
-
onSaveAll={saveAllMemoryCandidates}
|
|
1205
|
-
onSkipAll={skipAllMemoryCandidates}
|
|
1206
|
-
onLevelChange={handleMemoryLevelChange} />
|
|
1207
|
-
</div>
|
|
1208
|
-
);
|
|
1209
|
-
};
|