@datalayer/agent-runtimes 0.0.9 → 0.0.10
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/README.md +2 -1
- package/lib/{examples/components → components}/AgentConfiguration.d.ts +27 -12
- package/lib/{examples/components → components}/AgentConfiguration.js +170 -22
- package/lib/{examples/components → components}/FooterMetrics.d.ts +1 -2
- package/lib/{examples/components → components}/Header.d.ts +1 -6
- package/lib/{examples/components → components}/Header.js +5 -39
- package/lib/{examples/components → components}/HeaderControls.d.ts +1 -2
- package/lib/{examples/components → components}/HeaderControls.js +1 -1
- package/lib/{examples/components → components}/LexicalEditor.d.ts +2 -3
- package/lib/{examples/components → components}/LexicalEditor.js +2 -2
- package/lib/components/MainContent.d.ts +34 -0
- package/lib/{examples/components → components}/MainContent.js +18 -9
- package/lib/components/McpServerManager.d.ts +30 -0
- package/lib/components/McpServerManager.js +331 -0
- package/lib/{examples/components → components}/MockFileBrowser.d.ts +1 -2
- package/lib/{examples/components → components}/SessionTabs.d.ts +2 -3
- package/lib/{examples/components → components}/TimeTravel.d.ts +1 -2
- package/lib/components/chat/components/AgentDetails.d.ts +3 -1
- package/lib/components/chat/components/AgentDetails.js +323 -31
- package/lib/components/chat/components/Chat.d.ts +37 -3
- package/lib/components/chat/components/Chat.js +29 -10
- package/lib/components/chat/components/ChatFloating.d.ts +27 -2
- package/lib/components/chat/components/ChatFloating.js +17 -10
- package/lib/components/chat/components/ChatPopupStandalone.js +1 -1
- package/lib/components/chat/components/ChatSidebar.d.ts +1 -1
- package/lib/components/chat/components/ChatStandalone.d.ts +1 -1
- package/lib/components/chat/components/ChatStandalone.js +1 -1
- package/lib/components/chat/components/ContextDistribution.d.ts +70 -6
- package/lib/components/chat/components/ContextDistribution.js +11 -4
- package/lib/components/chat/components/ContextInspector.d.ts +81 -0
- package/lib/components/chat/components/ContextInspector.js +261 -0
- package/lib/components/chat/components/ContextPanel.d.ts +112 -0
- package/lib/components/chat/components/ContextPanel.js +373 -0
- package/lib/components/chat/components/base/ChatBase.d.ts +74 -19
- package/lib/components/chat/components/base/ChatBase.js +296 -37
- package/lib/components/chat/components/index.d.ts +3 -1
- package/lib/components/chat/components/index.js +2 -0
- package/lib/components/chat/extensions/ExtensionRegistry.d.ts +1 -1
- package/lib/components/chat/extensions/index.d.ts +1 -0
- package/lib/components/chat/index.d.ts +3 -3
- package/lib/components/chat/protocols/AGUIAdapter.js +24 -4
- package/lib/components/chat/protocols/VercelAIAdapter.js +35 -1
- package/lib/components/chat/store/chatStore.d.ts +2 -3
- package/lib/components/chat/store/conversationStore.d.ts +83 -0
- package/lib/components/chat/store/conversationStore.js +174 -0
- package/lib/components/chat/store/index.d.ts +2 -1
- package/lib/components/chat/store/index.js +1 -0
- package/lib/components/chat/types/inference.d.ts +17 -0
- package/lib/components/chat/types/protocol.d.ts +10 -0
- package/lib/components/index.d.ts +23 -0
- package/lib/components/index.js +11 -0
- package/lib/config/agents.d.ts +33 -0
- package/lib/config/agents.js +424 -0
- package/lib/config/index.d.ts +4 -0
- package/lib/config/index.js +8 -0
- package/lib/config/mcpServers.d.ts +18 -0
- package/lib/config/mcpServers.js +129 -0
- package/lib/config/skills.d.ts +25 -0
- package/lib/config/skills.js +54 -0
- package/lib/{lib → config}/utils.d.ts +1 -1
- package/lib/{lib → config}/utils.js +2 -2
- package/lib/examples/AgentRuntimeLexical2Example.d.ts +1 -0
- package/lib/examples/AgentRuntimeLexical2Example.js +3 -2
- package/lib/examples/AgentRuntimeLexicalExample.d.ts +1 -0
- package/lib/examples/AgentRuntimeLexicalExample.js +5 -3
- package/lib/examples/AgentRuntimeLexicalSidebarExample.d.ts +1 -0
- package/lib/examples/AgentRuntimeLexicalSidebarExample.js +3 -3
- package/lib/examples/AgentRuntimeNotebookExample.js +1 -1
- package/lib/examples/AgentSpaceFormExample.d.ts +2 -2
- package/lib/examples/AgentSpaceFormExample.js +167 -29
- package/lib/examples/CopilotKitLexicalExample.d.ts +1 -0
- package/lib/examples/CopilotKitLexicalExample.js +3 -2
- package/lib/examples/index.d.ts +1 -0
- package/lib/examples/stores/notebooks/NotebookExample2.ipynb.json +43 -43
- package/lib/hooks/useAGUI.d.ts +1 -1
- package/lib/hooks/useAGUI.js +1 -1
- package/lib/identity/types.d.ts +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.js +1 -0
- package/lib/runtime/index.d.ts +3 -0
- package/lib/runtime/runtimeStore.d.ts +3 -4
- package/lib/runtime/useAgentConnection.d.ts +2 -3
- package/lib/runtime/useAgentRuntime.d.ts +2 -3
- package/lib/stories/Cell.stories.js +1 -1
- package/lib/tools/adapters/agent-runtimes/notebookHooks.js +1 -0
- package/lib/tools/adapters/copilotkit/notebookHooks.js +1 -0
- package/lib/types.d.ts +150 -0
- package/package.json +4 -5
- package/scripts/apply-patches.sh +1 -1
- package/scripts/codegen/generate_agents.py +452 -0
- package/scripts/codegen/generate_mcp_servers.py +424 -0
- package/scripts/codegen/generate_skills.py +321 -0
- package/scripts/download-ai-elements.py +35 -20
- package/scripts/sync-jupyter.sh +6 -0
- package/lib/components/ui/accordion.d.ts +0 -7
- package/lib/components/ui/accordion.js +0 -22
- package/lib/components/ui/alert-dialog.d.ts +0 -14
- package/lib/components/ui/alert-dialog.js +0 -43
- package/lib/components/ui/alert.d.ts +0 -9
- package/lib/components/ui/alert.js +0 -24
- package/lib/components/ui/aspect-ratio.d.ts +0 -3
- package/lib/components/ui/aspect-ratio.js +0 -11
- package/lib/components/ui/avatar.d.ts +0 -6
- package/lib/components/ui/avatar.js +0 -18
- package/lib/components/ui/badge.d.ts +0 -9
- package/lib/components/ui/badge.js +0 -22
- package/lib/components/ui/breadcrumb.d.ts +0 -11
- package/lib/components/ui/breadcrumb.js +0 -27
- package/lib/components/ui/button-group.d.ts +0 -11
- package/lib/components/ui/button-group.js +0 -31
- package/lib/components/ui/button.d.ts +0 -13
- package/lib/components/ui/button.js +0 -39
- package/lib/components/ui/calendar.d.ts +0 -8
- package/lib/components/ui/calendar.js +0 -80
- package/lib/components/ui/card.d.ts +0 -9
- package/lib/components/ui/card.js +0 -24
- package/lib/components/ui/carousel.d.ts +0 -19
- package/lib/components/ui/carousel.js +0 -95
- package/lib/components/ui/chart.d.ts +0 -53
- package/lib/components/ui/chart.js +0 -136
- package/lib/components/ui/checkbox.d.ts +0 -4
- package/lib/components/ui/checkbox.js +0 -13
- package/lib/components/ui/collapsible.d.ts +0 -5
- package/lib/components/ui/collapsible.js +0 -17
- package/lib/components/ui/command.d.ts +0 -18
- package/lib/components/ui/command.js +0 -38
- package/lib/components/ui/context-menu.d.ts +0 -25
- package/lib/components/ui/context-menu.js +0 -55
- package/lib/components/ui/dialog.d.ts +0 -15
- package/lib/components/ui/dialog.js +0 -40
- package/lib/components/ui/drawer.d.ts +0 -13
- package/lib/components/ui/drawer.js +0 -39
- package/lib/components/ui/dropdown-menu.d.ts +0 -25
- package/lib/components/ui/dropdown-menu.js +0 -55
- package/lib/components/ui/empty.d.ts +0 -11
- package/lib/components/ui/empty.js +0 -37
- package/lib/components/ui/field.d.ts +0 -24
- package/lib/components/ui/field.js +0 -80
- package/lib/components/ui/form.d.ts +0 -24
- package/lib/components/ui/form.js +0 -63
- package/lib/components/ui/hover-card.d.ts +0 -6
- package/lib/components/ui/hover-card.js +0 -18
- package/lib/components/ui/input-group.d.ts +0 -19
- package/lib/components/ui/input-group.js +0 -69
- package/lib/components/ui/input-otp.d.ts +0 -11
- package/lib/components/ui/input-otp.js +0 -25
- package/lib/components/ui/input.d.ts +0 -3
- package/lib/components/ui/input.js +0 -6
- package/lib/components/ui/item.d.ts +0 -23
- package/lib/components/ui/item.js +0 -66
- package/lib/components/ui/kbd.d.ts +0 -3
- package/lib/components/ui/kbd.js +0 -13
- package/lib/components/ui/label.d.ts +0 -4
- package/lib/components/ui/label.js +0 -12
- package/lib/components/ui/menubar.d.ts +0 -26
- package/lib/components/ui/menubar.js +0 -58
- package/lib/components/ui/navigation-menu.d.ts +0 -14
- package/lib/components/ui/navigation-menu.js +0 -31
- package/lib/components/ui/pagination.d.ts +0 -13
- package/lib/components/ui/pagination.js +0 -29
- package/lib/components/ui/popover.d.ts +0 -7
- package/lib/components/ui/popover.js +0 -21
- package/lib/components/ui/progress.d.ts +0 -4
- package/lib/components/ui/progress.js +0 -12
- package/lib/components/ui/radio-group.d.ts +0 -5
- package/lib/components/ui/radio-group.js +0 -16
- package/lib/components/ui/resizable.d.ts +0 -8
- package/lib/components/ui/resizable.js +0 -19
- package/lib/components/ui/scroll-area.d.ts +0 -5
- package/lib/components/ui/scroll-area.js +0 -17
- package/lib/components/ui/select.d.ts +0 -15
- package/lib/components/ui/select.js +0 -42
- package/lib/components/ui/separator.d.ts +0 -4
- package/lib/components/ui/separator.js +0 -12
- package/lib/components/ui/sheet.d.ts +0 -13
- package/lib/components/ui/sheet.js +0 -44
- package/lib/components/ui/sidebar.d.ts +0 -69
- package/lib/components/ui/sidebar.js +0 -216
- package/lib/components/ui/skeleton.d.ts +0 -2
- package/lib/components/ui/skeleton.js +0 -10
- package/lib/components/ui/slider.d.ts +0 -4
- package/lib/components/ui/slider.js +0 -18
- package/lib/components/ui/sonner.d.ts +0 -3
- package/lib/components/ui/sonner.js +0 -25
- package/lib/components/ui/spinner.d.ts +0 -2
- package/lib/components/ui/spinner.js +0 -11
- package/lib/components/ui/switch.d.ts +0 -4
- package/lib/components/ui/switch.js +0 -12
- package/lib/components/ui/table.d.ts +0 -10
- package/lib/components/ui/table.js +0 -32
- package/lib/components/ui/tabs.d.ts +0 -7
- package/lib/components/ui/tabs.js +0 -21
- package/lib/components/ui/textarea.d.ts +0 -3
- package/lib/components/ui/textarea.js +0 -6
- package/lib/components/ui/toast.d.ts +0 -15
- package/lib/components/ui/toast.js +0 -38
- package/lib/components/ui/toaster.d.ts +0 -1
- package/lib/components/ui/toaster.js +0 -14
- package/lib/components/ui/toggle-group.d.ts +0 -9
- package/lib/components/ui/toggle-group.js +0 -26
- package/lib/components/ui/toggle.d.ts +0 -9
- package/lib/components/ui/toggle.js +0 -30
- package/lib/components/ui/tooltip.d.ts +0 -7
- package/lib/components/ui/tooltip.js +0 -21
- package/lib/components/vercel-ai-elements/artifact.d.ts +0 -23
- package/lib/components/vercel-ai-elements/artifact.js +0 -24
- package/lib/components/vercel-ai-elements/code-block.d.ts +0 -17
- package/lib/components/vercel-ai-elements/code-block.js +0 -94
- package/lib/components/vercel-ai-elements/conversation.d.ts +0 -15
- package/lib/components/vercel-ai-elements/conversation.js +0 -21
- package/lib/components/vercel-ai-elements/loader.d.ts +0 -5
- package/lib/components/vercel-ai-elements/loader.js +0 -8
- package/lib/components/vercel-ai-elements/message.d.ts +0 -46
- package/lib/components/vercel-ai-elements/message.js +0 -109
- package/lib/components/vercel-ai-elements/model-selector.d.ts +0 -35
- package/lib/components/vercel-ai-elements/model-selector.js +0 -22
- package/lib/components/vercel-ai-elements/prompt-input.d.ts +0 -195
- package/lib/components/vercel-ai-elements/prompt-input.js +0 -589
- package/lib/components/vercel-ai-elements/reasoning.d.ts +0 -26
- package/lib/components/vercel-ai-elements/reasoning.js +0 -80
- package/lib/components/vercel-ai-elements/shimmer.d.ts +0 -9
- package/lib/components/vercel-ai-elements/shimmer.js +0 -22
- package/lib/components/vercel-ai-elements/sources.d.ts +0 -12
- package/lib/components/vercel-ai-elements/sources.js +0 -13
- package/lib/components/vercel-ai-elements/suggestion.d.ts +0 -10
- package/lib/components/vercel-ai-elements/suggestion.js +0 -16
- package/lib/components/vercel-ai-elements/tool.d.ts +0 -23
- package/lib/components/vercel-ai-elements/tool.js +0 -52
- package/lib/examples/components/MainContent.d.ts +0 -19
- package/lib/examples/components/index.d.ts +0 -10
- package/lib/examples/components/index.js +0 -13
- package/lib/examples/vercel-ai-elements/VercelAiElementsShowcase.d.ts +0 -12
- package/lib/examples/vercel-ai-elements/VercelAiElementsShowcase.js +0 -69
- package/lib/examples/vercel-ai-elements/components/ArtifactShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ArtifactShowcase.js +0 -85
- package/lib/examples/vercel-ai-elements/components/CodeBlockShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/CodeBlockShowcase.js +0 -62
- package/lib/examples/vercel-ai-elements/components/ConversationShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ConversationShowcase.js +0 -51
- package/lib/examples/vercel-ai-elements/components/LoaderShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/LoaderShowcase.js +0 -9
- package/lib/examples/vercel-ai-elements/components/MessageShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/MessageShowcase.js +0 -56
- package/lib/examples/vercel-ai-elements/components/ModelSelectorShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ModelSelectorShowcase.js +0 -50
- package/lib/examples/vercel-ai-elements/components/PromptInputShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/PromptInputShowcase.js +0 -16
- package/lib/examples/vercel-ai-elements/components/ReasoningShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ReasoningShowcase.js +0 -72
- package/lib/examples/vercel-ai-elements/components/ShimmerShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ShimmerShowcase.js +0 -9
- package/lib/examples/vercel-ai-elements/components/SourcesShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/SourcesShowcase.js +0 -43
- package/lib/examples/vercel-ai-elements/components/SuggestionShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/SuggestionShowcase.js +0 -31
- package/lib/examples/vercel-ai-elements/components/ToolShowcase.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/components/ToolShowcase.js +0 -54
- package/lib/examples/vercel-ai-elements/index.d.ts +0 -13
- package/lib/examples/vercel-ai-elements/index.js +0 -17
- package/lib/examples/vercel-ai-elements/main.d.ts +0 -1
- package/lib/examples/vercel-ai-elements/main.js +0 -9
- package/lib/examples/vercel-ai-elements/showcase.css +0 -128
- package/lib/hooks/useToast.d.ts +0 -44
- package/lib/hooks/useToast.js +0 -128
- package/patches/@datalayer+jupyter-lexical+1.0.8.patch +0 -11628
- package/patches/@datalayer+jupyter-react+2.0.2.patch +0 -5338
- package/style/showcase-vercel-ai.css +0 -137
- /package/lib/{examples/components → components}/FooterMetrics.js +0 -0
- /package/lib/{examples/components → components}/MockFileBrowser.js +0 -0
- /package/lib/{examples/components → components}/SessionTabs.js +0 -0
- /package/lib/{examples/components → components}/TimeTravel.js +0 -0
- /package/lib/{models → types}/AIAgent.d.ts +0 -0
- /package/lib/{models → types}/AIAgent.js +0 -0
- /package/lib/{models → types}/index.d.ts +0 -0
- /package/lib/{models → types}/index.js +0 -0
|
@@ -1,589 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
3
|
-
* Distributed under the terms of the Modified BSD License.
|
|
4
|
-
*/
|
|
5
|
-
'use client';
|
|
6
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
7
|
-
import * as React from 'react';
|
|
8
|
-
import { Button } from '@/components/ui/button';
|
|
9
|
-
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from '@/components/ui/command';
|
|
10
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu';
|
|
11
|
-
import { HoverCard, HoverCardContent, HoverCardTrigger, } from '@/components/ui/hover-card';
|
|
12
|
-
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea, } from '@/components/ui/input-group';
|
|
13
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select';
|
|
14
|
-
import { cn } from '@/lib/utils';
|
|
15
|
-
import { CornerDownLeftIcon, Loader2Icon, MicIcon, PaperclipIcon, PlusIcon, SquareIcon, XIcon, } from 'lucide-react';
|
|
16
|
-
import { nanoid } from 'nanoid';
|
|
17
|
-
import { Children, createContext, Fragment, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
18
|
-
const PromptInputController = createContext(null);
|
|
19
|
-
const ProviderAttachmentsContext = createContext(null);
|
|
20
|
-
export const usePromptInputController = () => {
|
|
21
|
-
const ctx = useContext(PromptInputController);
|
|
22
|
-
if (!ctx) {
|
|
23
|
-
throw new Error('Wrap your component inside <PromptInputProvider> to use usePromptInputController().');
|
|
24
|
-
}
|
|
25
|
-
return ctx;
|
|
26
|
-
};
|
|
27
|
-
// Optional variants (do NOT throw). Useful for dual-mode components.
|
|
28
|
-
const useOptionalPromptInputController = () => useContext(PromptInputController);
|
|
29
|
-
export const useProviderAttachments = () => {
|
|
30
|
-
const ctx = useContext(ProviderAttachmentsContext);
|
|
31
|
-
if (!ctx) {
|
|
32
|
-
throw new Error('Wrap your component inside <PromptInputProvider> to use useProviderAttachments().');
|
|
33
|
-
}
|
|
34
|
-
return ctx;
|
|
35
|
-
};
|
|
36
|
-
const useOptionalProviderAttachments = () => useContext(ProviderAttachmentsContext);
|
|
37
|
-
/**
|
|
38
|
-
* Optional global provider that lifts PromptInput state outside of PromptInput.
|
|
39
|
-
* If you don't use it, PromptInput stays fully self-managed.
|
|
40
|
-
*/
|
|
41
|
-
export function PromptInputProvider({ initialInput: initialTextInput = '', children, }) {
|
|
42
|
-
// ----- textInput state
|
|
43
|
-
const [textInput, setTextInput] = useState(initialTextInput);
|
|
44
|
-
const clearInput = useCallback(() => setTextInput(''), []);
|
|
45
|
-
// ----- attachments state (global when wrapped)
|
|
46
|
-
const [attachmentFiles, setAttachmentFiles] = useState([]);
|
|
47
|
-
const fileInputRef = useRef(null);
|
|
48
|
-
const openRef = useRef(() => { });
|
|
49
|
-
const add = useCallback((files) => {
|
|
50
|
-
const incoming = Array.from(files);
|
|
51
|
-
if (incoming.length === 0) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
setAttachmentFiles(prev => prev.concat(incoming.map(file => ({
|
|
55
|
-
id: nanoid(),
|
|
56
|
-
type: 'file',
|
|
57
|
-
url: URL.createObjectURL(file),
|
|
58
|
-
mediaType: file.type,
|
|
59
|
-
filename: file.name,
|
|
60
|
-
}))));
|
|
61
|
-
}, []);
|
|
62
|
-
const remove = useCallback((id) => {
|
|
63
|
-
setAttachmentFiles(prev => {
|
|
64
|
-
const found = prev.find(f => f.id === id);
|
|
65
|
-
if (found?.url) {
|
|
66
|
-
URL.revokeObjectURL(found.url);
|
|
67
|
-
}
|
|
68
|
-
return prev.filter(f => f.id !== id);
|
|
69
|
-
});
|
|
70
|
-
}, []);
|
|
71
|
-
const clear = useCallback(() => {
|
|
72
|
-
setAttachmentFiles(prev => {
|
|
73
|
-
for (const f of prev) {
|
|
74
|
-
if (f.url) {
|
|
75
|
-
URL.revokeObjectURL(f.url);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return [];
|
|
79
|
-
});
|
|
80
|
-
}, []);
|
|
81
|
-
// Keep a ref to attachments for cleanup on unmount (avoids stale closure)
|
|
82
|
-
const attachmentsRef = useRef(attachmentFiles);
|
|
83
|
-
attachmentsRef.current = attachmentFiles;
|
|
84
|
-
// Cleanup blob URLs on unmount to prevent memory leaks
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
return () => {
|
|
87
|
-
for (const f of attachmentsRef.current) {
|
|
88
|
-
if (f.url) {
|
|
89
|
-
URL.revokeObjectURL(f.url);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
}, []);
|
|
94
|
-
const openFileDialog = useCallback(() => {
|
|
95
|
-
openRef.current?.();
|
|
96
|
-
}, []);
|
|
97
|
-
const attachments = useMemo(() => ({
|
|
98
|
-
files: attachmentFiles,
|
|
99
|
-
add,
|
|
100
|
-
remove,
|
|
101
|
-
clear,
|
|
102
|
-
openFileDialog,
|
|
103
|
-
fileInputRef,
|
|
104
|
-
}), [attachmentFiles, add, remove, clear, openFileDialog]);
|
|
105
|
-
const __registerFileInput = useCallback((ref, open) => {
|
|
106
|
-
fileInputRef.current = ref.current;
|
|
107
|
-
openRef.current = open;
|
|
108
|
-
}, []);
|
|
109
|
-
const controller = useMemo(() => ({
|
|
110
|
-
textInput: {
|
|
111
|
-
value: textInput,
|
|
112
|
-
setInput: setTextInput,
|
|
113
|
-
clear: clearInput,
|
|
114
|
-
},
|
|
115
|
-
attachments,
|
|
116
|
-
__registerFileInput,
|
|
117
|
-
}), [textInput, clearInput, attachments, __registerFileInput]);
|
|
118
|
-
return (_jsx(PromptInputController.Provider, { value: controller, children: _jsx(ProviderAttachmentsContext.Provider, { value: attachments, children: children }) }));
|
|
119
|
-
}
|
|
120
|
-
// ============================================================================
|
|
121
|
-
// Component Context & Hooks
|
|
122
|
-
// ============================================================================
|
|
123
|
-
const LocalAttachmentsContext = createContext(null);
|
|
124
|
-
export const usePromptInputAttachments = () => {
|
|
125
|
-
// Dual-mode: prefer provider if present, otherwise use local
|
|
126
|
-
const provider = useOptionalProviderAttachments();
|
|
127
|
-
const local = useContext(LocalAttachmentsContext);
|
|
128
|
-
const context = provider ?? local;
|
|
129
|
-
if (!context) {
|
|
130
|
-
throw new Error('usePromptInputAttachments must be used within a PromptInput or PromptInputProvider');
|
|
131
|
-
}
|
|
132
|
-
return context;
|
|
133
|
-
};
|
|
134
|
-
export function PromptInputAttachment({ data, className, ...props }) {
|
|
135
|
-
const attachments = usePromptInputAttachments();
|
|
136
|
-
const filename = data.filename || '';
|
|
137
|
-
const mediaType = data.mediaType?.startsWith('image/') && data.url ? 'image' : 'file';
|
|
138
|
-
const isImage = mediaType === 'image';
|
|
139
|
-
const attachmentLabel = filename || (isImage ? 'Image' : 'Attachment');
|
|
140
|
-
return (_jsxs(PromptInputHoverCard, { children: [_jsx(HoverCardTrigger, { asChild: true, children: _jsxs("div", { className: cn('group relative flex h-8 cursor-pointer select-none items-center gap-1.5 rounded-md border border-border px-1.5 font-medium text-sm transition-all hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50', className), ...props, children: [_jsxs("div", { className: "relative size-5 shrink-0", children: [_jsx("div", { className: "absolute inset-0 flex size-5 items-center justify-center overflow-hidden rounded bg-background transition-opacity group-hover:opacity-0", children: isImage ? (_jsx("img", { alt: filename || 'attachment', className: "size-5 object-cover", height: 20, src: data.url, width: 20 })) : (_jsx("div", { className: "flex size-5 items-center justify-center text-muted-foreground", children: _jsx(PaperclipIcon, { className: "size-3" }) })) }), _jsxs(Button, { "aria-label": "Remove attachment", className: "absolute inset-0 size-5 cursor-pointer rounded p-0 opacity-0 transition-opacity group-hover:pointer-events-auto group-hover:opacity-100 [&>svg]:size-2.5", onClick: e => {
|
|
141
|
-
e.stopPropagation();
|
|
142
|
-
attachments.remove(data.id);
|
|
143
|
-
}, type: "button", variant: "ghost", children: [_jsx(XIcon, {}), _jsx("span", { className: "sr-only", children: "Remove" })] })] }), _jsx("span", { className: "flex-1 truncate", children: attachmentLabel })] }, data.id) }), _jsx(PromptInputHoverCardContent, { className: "w-auto p-2", children: _jsxs("div", { className: "w-auto space-y-3", children: [isImage && (_jsx("div", { className: "flex max-h-96 w-96 items-center justify-center overflow-hidden rounded-md border", children: _jsx("img", { alt: filename || 'attachment preview', className: "max-h-full max-w-full object-contain", height: 384, src: data.url, width: 448 }) })), _jsx("div", { className: "flex items-center gap-2.5", children: _jsxs("div", { className: "min-w-0 flex-1 space-y-1 px-0.5", children: [_jsx("h4", { className: "truncate font-semibold text-sm leading-none", children: filename || (isImage ? 'Image' : 'Attachment') }), data.mediaType && (_jsx("p", { className: "truncate font-mono text-muted-foreground text-xs", children: data.mediaType }))] }) })] }) })] }));
|
|
144
|
-
}
|
|
145
|
-
export function PromptInputAttachments({ children, className, ...props }) {
|
|
146
|
-
const attachments = usePromptInputAttachments();
|
|
147
|
-
if (!attachments.files.length) {
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
return (_jsx("div", { className: cn('flex flex-wrap items-center gap-2 p-3 w-full', className), ...props, children: attachments.files.map(file => (_jsx(Fragment, { children: children(file) }, file.id))) }));
|
|
151
|
-
}
|
|
152
|
-
export const PromptInputActionAddAttachments = ({ label, children, ...props }) => {
|
|
153
|
-
const attachments = usePromptInputAttachments();
|
|
154
|
-
return (_jsx(InputGroupButton, { type: "button", variant: "ghost", size: "icon-sm", ...props, onClick: e => {
|
|
155
|
-
e.preventDefault();
|
|
156
|
-
attachments.openFileDialog();
|
|
157
|
-
props.onClick?.(e);
|
|
158
|
-
}, children: children ?? _jsx(PaperclipIcon, { className: "size-4" }) }));
|
|
159
|
-
};
|
|
160
|
-
export const PromptInput = ({ className, accept, multiple, globalDrop, syncHiddenInput, maxFiles, maxFileSize, onError, onSubmit, children, ...props }) => {
|
|
161
|
-
// Try to use a provider controller if present
|
|
162
|
-
const controller = useOptionalPromptInputController();
|
|
163
|
-
const usingProvider = !!controller;
|
|
164
|
-
// Refs
|
|
165
|
-
const inputRef = useRef(null);
|
|
166
|
-
const formRef = useRef(null);
|
|
167
|
-
// ----- Local attachments (only used when no provider)
|
|
168
|
-
const [items, setItems] = useState([]);
|
|
169
|
-
const files = usingProvider ? controller.attachments.files : items;
|
|
170
|
-
// Keep a ref to files for cleanup on unmount (avoids stale closure)
|
|
171
|
-
const filesRef = useRef(files);
|
|
172
|
-
filesRef.current = files;
|
|
173
|
-
const openFileDialogLocal = useCallback(() => {
|
|
174
|
-
inputRef.current?.click();
|
|
175
|
-
}, []);
|
|
176
|
-
const matchesAccept = useCallback((f) => {
|
|
177
|
-
if (!accept || accept.trim() === '') {
|
|
178
|
-
return true;
|
|
179
|
-
}
|
|
180
|
-
const patterns = accept
|
|
181
|
-
.split(',')
|
|
182
|
-
.map(s => s.trim())
|
|
183
|
-
.filter(Boolean);
|
|
184
|
-
return patterns.some(pattern => {
|
|
185
|
-
if (pattern.endsWith('/*')) {
|
|
186
|
-
const prefix = pattern.slice(0, -1); // e.g: image/* -> image/
|
|
187
|
-
return f.type.startsWith(prefix);
|
|
188
|
-
}
|
|
189
|
-
return f.type === pattern;
|
|
190
|
-
});
|
|
191
|
-
}, [accept]);
|
|
192
|
-
const addLocal = useCallback((fileList) => {
|
|
193
|
-
const incoming = Array.from(fileList);
|
|
194
|
-
const accepted = incoming.filter(f => matchesAccept(f));
|
|
195
|
-
if (incoming.length && accepted.length === 0) {
|
|
196
|
-
onError?.({
|
|
197
|
-
code: 'accept',
|
|
198
|
-
message: 'No files match the accepted types.',
|
|
199
|
-
});
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const withinSize = (f) => maxFileSize ? f.size <= maxFileSize : true;
|
|
203
|
-
const sized = accepted.filter(withinSize);
|
|
204
|
-
if (accepted.length > 0 && sized.length === 0) {
|
|
205
|
-
onError?.({
|
|
206
|
-
code: 'max_file_size',
|
|
207
|
-
message: 'All files exceed the maximum size.',
|
|
208
|
-
});
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
setItems(prev => {
|
|
212
|
-
const capacity = typeof maxFiles === 'number'
|
|
213
|
-
? Math.max(0, maxFiles - prev.length)
|
|
214
|
-
: undefined;
|
|
215
|
-
const capped = typeof capacity === 'number' ? sized.slice(0, capacity) : sized;
|
|
216
|
-
if (typeof capacity === 'number' && sized.length > capacity) {
|
|
217
|
-
onError?.({
|
|
218
|
-
code: 'max_files',
|
|
219
|
-
message: 'Too many files. Some were not added.',
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
const next = [];
|
|
223
|
-
for (const file of capped) {
|
|
224
|
-
next.push({
|
|
225
|
-
id: nanoid(),
|
|
226
|
-
type: 'file',
|
|
227
|
-
url: URL.createObjectURL(file),
|
|
228
|
-
mediaType: file.type,
|
|
229
|
-
filename: file.name,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
return prev.concat(next);
|
|
233
|
-
});
|
|
234
|
-
}, [matchesAccept, maxFiles, maxFileSize, onError]);
|
|
235
|
-
const removeLocal = useCallback((id) => setItems(prev => {
|
|
236
|
-
const found = prev.find(file => file.id === id);
|
|
237
|
-
if (found?.url) {
|
|
238
|
-
URL.revokeObjectURL(found.url);
|
|
239
|
-
}
|
|
240
|
-
return prev.filter(file => file.id !== id);
|
|
241
|
-
}), []);
|
|
242
|
-
const clearLocal = useCallback(() => setItems(prev => {
|
|
243
|
-
for (const file of prev) {
|
|
244
|
-
if (file.url) {
|
|
245
|
-
URL.revokeObjectURL(file.url);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return [];
|
|
249
|
-
}), []);
|
|
250
|
-
const add = usingProvider ? controller.attachments.add : addLocal;
|
|
251
|
-
const remove = usingProvider ? controller.attachments.remove : removeLocal;
|
|
252
|
-
const clear = usingProvider ? controller.attachments.clear : clearLocal;
|
|
253
|
-
const openFileDialog = usingProvider
|
|
254
|
-
? controller.attachments.openFileDialog
|
|
255
|
-
: openFileDialogLocal;
|
|
256
|
-
// Let provider know about our hidden file input so external menus can call openFileDialog()
|
|
257
|
-
useEffect(() => {
|
|
258
|
-
if (!usingProvider)
|
|
259
|
-
return;
|
|
260
|
-
controller.__registerFileInput(inputRef, () => inputRef.current?.click());
|
|
261
|
-
}, [usingProvider, controller]);
|
|
262
|
-
// Note: File input cannot be programmatically set for security reasons
|
|
263
|
-
// The syncHiddenInput prop is no longer functional
|
|
264
|
-
useEffect(() => {
|
|
265
|
-
if (syncHiddenInput && inputRef.current && files.length === 0) {
|
|
266
|
-
inputRef.current.value = '';
|
|
267
|
-
}
|
|
268
|
-
}, [files, syncHiddenInput]);
|
|
269
|
-
// Attach drop handlers on nearest form and document (opt-in)
|
|
270
|
-
useEffect(() => {
|
|
271
|
-
const form = formRef.current;
|
|
272
|
-
if (!form)
|
|
273
|
-
return;
|
|
274
|
-
if (globalDrop)
|
|
275
|
-
return; // when global drop is on, let the document-level handler own drops
|
|
276
|
-
const onDragOver = (e) => {
|
|
277
|
-
if (e.dataTransfer?.types?.includes('Files')) {
|
|
278
|
-
e.preventDefault();
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
const onDrop = (e) => {
|
|
282
|
-
if (e.dataTransfer?.types?.includes('Files')) {
|
|
283
|
-
e.preventDefault();
|
|
284
|
-
}
|
|
285
|
-
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
|
|
286
|
-
add(e.dataTransfer.files);
|
|
287
|
-
}
|
|
288
|
-
};
|
|
289
|
-
form.addEventListener('dragover', onDragOver);
|
|
290
|
-
form.addEventListener('drop', onDrop);
|
|
291
|
-
return () => {
|
|
292
|
-
form.removeEventListener('dragover', onDragOver);
|
|
293
|
-
form.removeEventListener('drop', onDrop);
|
|
294
|
-
};
|
|
295
|
-
}, [add, globalDrop]);
|
|
296
|
-
useEffect(() => {
|
|
297
|
-
if (!globalDrop)
|
|
298
|
-
return;
|
|
299
|
-
const onDragOver = (e) => {
|
|
300
|
-
if (e.dataTransfer?.types?.includes('Files')) {
|
|
301
|
-
e.preventDefault();
|
|
302
|
-
}
|
|
303
|
-
};
|
|
304
|
-
const onDrop = (e) => {
|
|
305
|
-
if (e.dataTransfer?.types?.includes('Files')) {
|
|
306
|
-
e.preventDefault();
|
|
307
|
-
}
|
|
308
|
-
if (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
|
|
309
|
-
add(e.dataTransfer.files);
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
document.addEventListener('dragover', onDragOver);
|
|
313
|
-
document.addEventListener('drop', onDrop);
|
|
314
|
-
return () => {
|
|
315
|
-
document.removeEventListener('dragover', onDragOver);
|
|
316
|
-
document.removeEventListener('drop', onDrop);
|
|
317
|
-
};
|
|
318
|
-
}, [add, globalDrop]);
|
|
319
|
-
useEffect(() => () => {
|
|
320
|
-
if (!usingProvider) {
|
|
321
|
-
for (const f of filesRef.current) {
|
|
322
|
-
if (f.url)
|
|
323
|
-
URL.revokeObjectURL(f.url);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
}, [usingProvider]);
|
|
327
|
-
const handleChange = event => {
|
|
328
|
-
if (event.currentTarget.files) {
|
|
329
|
-
add(event.currentTarget.files);
|
|
330
|
-
}
|
|
331
|
-
// Reset input value to allow selecting files that were previously removed
|
|
332
|
-
event.currentTarget.value = '';
|
|
333
|
-
};
|
|
334
|
-
const convertBlobUrlToDataUrl = async (url) => {
|
|
335
|
-
try {
|
|
336
|
-
const response = await fetch(url);
|
|
337
|
-
const blob = await response.blob();
|
|
338
|
-
return new Promise(resolve => {
|
|
339
|
-
const reader = new FileReader();
|
|
340
|
-
reader.onloadend = () => resolve(reader.result);
|
|
341
|
-
reader.onerror = () => resolve(null);
|
|
342
|
-
reader.readAsDataURL(blob);
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
catch {
|
|
346
|
-
return null;
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
const ctx = useMemo(() => ({
|
|
350
|
-
files: files.map(item => ({ ...item, id: item.id })),
|
|
351
|
-
add,
|
|
352
|
-
remove,
|
|
353
|
-
clear,
|
|
354
|
-
openFileDialog,
|
|
355
|
-
fileInputRef: inputRef,
|
|
356
|
-
}), [files, add, remove, clear, openFileDialog]);
|
|
357
|
-
const handleSubmit = event => {
|
|
358
|
-
event.preventDefault();
|
|
359
|
-
const form = event.currentTarget;
|
|
360
|
-
const text = usingProvider
|
|
361
|
-
? controller.textInput.value
|
|
362
|
-
: (() => {
|
|
363
|
-
const formData = new FormData(form);
|
|
364
|
-
return formData.get('message') || '';
|
|
365
|
-
})();
|
|
366
|
-
// Reset form immediately after capturing text to avoid race condition
|
|
367
|
-
// where user input during async blob conversion would be lost
|
|
368
|
-
if (!usingProvider) {
|
|
369
|
-
form.reset();
|
|
370
|
-
}
|
|
371
|
-
// Convert blob URLs to data URLs asynchronously
|
|
372
|
-
Promise.all(files.map(async ({ id, ...item }) => {
|
|
373
|
-
if (item.url && item.url.startsWith('blob:')) {
|
|
374
|
-
const dataUrl = await convertBlobUrlToDataUrl(item.url);
|
|
375
|
-
// If conversion failed, keep the original blob URL
|
|
376
|
-
return {
|
|
377
|
-
...item,
|
|
378
|
-
url: dataUrl ?? item.url,
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
return item;
|
|
382
|
-
}))
|
|
383
|
-
.then((convertedFiles) => {
|
|
384
|
-
try {
|
|
385
|
-
const result = onSubmit({ text, files: convertedFiles }, event);
|
|
386
|
-
// Handle both sync and async onSubmit
|
|
387
|
-
if (result instanceof Promise) {
|
|
388
|
-
result
|
|
389
|
-
.then(() => {
|
|
390
|
-
clear();
|
|
391
|
-
if (usingProvider) {
|
|
392
|
-
controller.textInput.clear();
|
|
393
|
-
}
|
|
394
|
-
})
|
|
395
|
-
.catch(() => {
|
|
396
|
-
// Don't clear on error - user may want to retry
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
else {
|
|
400
|
-
// Sync function completed without throwing, clear attachments
|
|
401
|
-
clear();
|
|
402
|
-
if (usingProvider) {
|
|
403
|
-
controller.textInput.clear();
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
catch {
|
|
408
|
-
// Don't clear on error - user may want to retry
|
|
409
|
-
}
|
|
410
|
-
})
|
|
411
|
-
.catch(() => {
|
|
412
|
-
// Don't clear on error - user may want to retry
|
|
413
|
-
});
|
|
414
|
-
};
|
|
415
|
-
// Render with or without local provider
|
|
416
|
-
const inner = (_jsxs(_Fragment, { children: [_jsx("input", { accept: accept, "aria-label": "Upload files", className: "hidden", multiple: multiple, onChange: handleChange, ref: inputRef, title: "Upload files", type: "file" }), _jsx("form", { className: cn('w-full', className), onSubmit: handleSubmit, ref: formRef, ...props, children: _jsx(InputGroup, { className: "overflow-hidden", children: children }) })] }));
|
|
417
|
-
return usingProvider ? (inner) : (_jsx(LocalAttachmentsContext.Provider, { value: ctx, children: inner }));
|
|
418
|
-
};
|
|
419
|
-
export const PromptInputBody = ({ className, ...props }) => (_jsx("div", { className: cn('contents', className), ...props }));
|
|
420
|
-
export const PromptInputTextarea = ({ onChange, className, placeholder = 'What would you like to know?', ...props }) => {
|
|
421
|
-
const controller = useOptionalPromptInputController();
|
|
422
|
-
const attachments = usePromptInputAttachments();
|
|
423
|
-
const [isComposing, setIsComposing] = useState(false);
|
|
424
|
-
const handleKeyDown = e => {
|
|
425
|
-
if (e.key === 'Enter') {
|
|
426
|
-
if (isComposing || e.nativeEvent.isComposing) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
if (e.shiftKey) {
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
e.preventDefault();
|
|
433
|
-
// Check if the submit button is disabled before submitting
|
|
434
|
-
const form = e.currentTarget.form;
|
|
435
|
-
const submitButton = form?.querySelector('button[type="submit"]');
|
|
436
|
-
if (submitButton?.disabled) {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
form?.requestSubmit();
|
|
440
|
-
}
|
|
441
|
-
// Remove last attachment when Backspace is pressed and textarea is empty
|
|
442
|
-
if (e.key === 'Backspace' &&
|
|
443
|
-
e.currentTarget.value === '' &&
|
|
444
|
-
attachments.files.length > 0) {
|
|
445
|
-
e.preventDefault();
|
|
446
|
-
const lastAttachment = attachments.files.at(-1);
|
|
447
|
-
if (lastAttachment) {
|
|
448
|
-
attachments.remove(lastAttachment.id);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
};
|
|
452
|
-
const handlePaste = event => {
|
|
453
|
-
const items = event.clipboardData?.items;
|
|
454
|
-
if (!items) {
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
const files = [];
|
|
458
|
-
for (const item of items) {
|
|
459
|
-
if (item.kind === 'file') {
|
|
460
|
-
const file = item.getAsFile();
|
|
461
|
-
if (file) {
|
|
462
|
-
files.push(file);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
if (files.length > 0) {
|
|
467
|
-
event.preventDefault();
|
|
468
|
-
attachments.add(files);
|
|
469
|
-
}
|
|
470
|
-
};
|
|
471
|
-
const controlledProps = controller
|
|
472
|
-
? {
|
|
473
|
-
value: controller.textInput.value,
|
|
474
|
-
onChange: (e) => {
|
|
475
|
-
controller.textInput.setInput(e.currentTarget.value);
|
|
476
|
-
onChange?.(e);
|
|
477
|
-
},
|
|
478
|
-
}
|
|
479
|
-
: {
|
|
480
|
-
onChange,
|
|
481
|
-
};
|
|
482
|
-
return (_jsx(InputGroupTextarea, { className: cn('field-sizing-content max-h-48 min-h-16', className), name: "message", onCompositionEnd: () => setIsComposing(false), onCompositionStart: () => setIsComposing(true), onKeyDown: handleKeyDown, onPaste: handlePaste, placeholder: placeholder, ...props, ...controlledProps }));
|
|
483
|
-
};
|
|
484
|
-
export const PromptInputHeader = ({ className, ...props }) => (_jsx(InputGroupAddon, { align: "block-end", className: cn('order-first flex-wrap gap-1', className), ...props }));
|
|
485
|
-
export const PromptInputFooter = ({ className, ...props }) => (_jsx(InputGroupAddon, { align: "block-end", className: cn('justify-between gap-1', className), ...props }));
|
|
486
|
-
export const PromptInputTools = ({ className, ...props }) => (_jsx("div", { className: cn('flex items-center gap-1', className), ...props }));
|
|
487
|
-
export const PromptInputButton = React.forwardRef(({ variant = 'ghost', className, size, ...props }, ref) => {
|
|
488
|
-
const newSize = size ?? (Children.count(props.children) > 1 ? 'sm' : 'icon-sm');
|
|
489
|
-
return (_jsx(InputGroupButton, { ref: ref, className: cn(className), size: newSize, type: "button", variant: variant, ...props }));
|
|
490
|
-
});
|
|
491
|
-
PromptInputButton.displayName = 'PromptInputButton';
|
|
492
|
-
export const PromptInputActionMenu = (props) => (_jsx(DropdownMenu, { ...props }));
|
|
493
|
-
export const PromptInputActionMenuTrigger = ({ className, children, ...props }) => (_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(PromptInputButton, { className: className, ...props, children: children ?? _jsx(PlusIcon, { className: "size-4" }) }) }));
|
|
494
|
-
export const PromptInputActionMenuContent = ({ className, ...props }) => (_jsx(DropdownMenuContent, { align: "start", className: cn(className), ...props }));
|
|
495
|
-
export const PromptInputActionMenuItem = ({ className, ...props }) => (_jsx(DropdownMenuItem, { className: cn(className), ...props }));
|
|
496
|
-
export const PromptInputSubmit = ({ className, variant = 'default', size = 'icon-sm', status, children, ...props }) => {
|
|
497
|
-
let Icon = _jsx(CornerDownLeftIcon, { className: "size-4" });
|
|
498
|
-
if (status === 'submitted') {
|
|
499
|
-
Icon = _jsx(Loader2Icon, { className: "size-4 animate-spin" });
|
|
500
|
-
}
|
|
501
|
-
else if (status === 'streaming') {
|
|
502
|
-
Icon = _jsx(SquareIcon, { className: "size-4" });
|
|
503
|
-
}
|
|
504
|
-
else if (status === 'error') {
|
|
505
|
-
Icon = _jsx(XIcon, { className: "size-4" });
|
|
506
|
-
}
|
|
507
|
-
return (_jsx(InputGroupButton, { "aria-label": "Submit", className: cn(className), size: size, type: "submit", variant: variant, ...props, children: children ?? Icon }));
|
|
508
|
-
};
|
|
509
|
-
export const PromptInputSpeechButton = ({ className, textareaRef, onTranscriptionChange, ...props }) => {
|
|
510
|
-
const [isListening, setIsListening] = useState(false);
|
|
511
|
-
const [recognition, setRecognition] = useState(null);
|
|
512
|
-
const recognitionRef = useRef(null);
|
|
513
|
-
useEffect(() => {
|
|
514
|
-
if (typeof window !== 'undefined' &&
|
|
515
|
-
('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)) {
|
|
516
|
-
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
517
|
-
const speechRecognition = new SpeechRecognition();
|
|
518
|
-
speechRecognition.continuous = true;
|
|
519
|
-
speechRecognition.interimResults = true;
|
|
520
|
-
speechRecognition.lang = 'en-US';
|
|
521
|
-
speechRecognition.onstart = () => {
|
|
522
|
-
setIsListening(true);
|
|
523
|
-
};
|
|
524
|
-
speechRecognition.onend = () => {
|
|
525
|
-
setIsListening(false);
|
|
526
|
-
};
|
|
527
|
-
speechRecognition.onresult = event => {
|
|
528
|
-
let finalTranscript = '';
|
|
529
|
-
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
530
|
-
const result = event.results[i];
|
|
531
|
-
if (result.isFinal) {
|
|
532
|
-
finalTranscript += result[0]?.transcript ?? '';
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
if (finalTranscript && textareaRef?.current) {
|
|
536
|
-
const textarea = textareaRef.current;
|
|
537
|
-
const currentValue = textarea.value;
|
|
538
|
-
const newValue = currentValue + (currentValue ? ' ' : '') + finalTranscript;
|
|
539
|
-
textarea.value = newValue;
|
|
540
|
-
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
|
541
|
-
onTranscriptionChange?.(newValue);
|
|
542
|
-
}
|
|
543
|
-
};
|
|
544
|
-
speechRecognition.onerror = event => {
|
|
545
|
-
console.error('Speech recognition error:', event.error);
|
|
546
|
-
setIsListening(false);
|
|
547
|
-
};
|
|
548
|
-
recognitionRef.current = speechRecognition;
|
|
549
|
-
setRecognition(speechRecognition);
|
|
550
|
-
}
|
|
551
|
-
return () => {
|
|
552
|
-
if (recognitionRef.current) {
|
|
553
|
-
recognitionRef.current.stop();
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
}, [textareaRef, onTranscriptionChange]);
|
|
557
|
-
const toggleListening = useCallback(() => {
|
|
558
|
-
if (!recognition) {
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
if (isListening) {
|
|
562
|
-
recognition.stop();
|
|
563
|
-
}
|
|
564
|
-
else {
|
|
565
|
-
recognition.start();
|
|
566
|
-
}
|
|
567
|
-
}, [recognition, isListening]);
|
|
568
|
-
return (_jsx(PromptInputButton, { className: cn('relative transition-all duration-200', isListening && 'animate-pulse bg-accent text-accent-foreground', className), disabled: !recognition, onClick: toggleListening, ...props, children: _jsx(MicIcon, { className: "size-4" }) }));
|
|
569
|
-
};
|
|
570
|
-
export const PromptInputSelect = (props) => (_jsx(Select, { ...props }));
|
|
571
|
-
export const PromptInputSelectTrigger = ({ className, ...props }) => (_jsx(SelectTrigger, { className: cn('border-none bg-transparent font-medium text-muted-foreground shadow-none transition-colors', 'hover:bg-accent hover:text-foreground aria-expanded:bg-accent aria-expanded:text-foreground', className), ...props }));
|
|
572
|
-
export const PromptInputSelectContent = ({ className, ...props }) => (_jsx(SelectContent, { className: cn(className), ...props }));
|
|
573
|
-
export const PromptInputSelectItem = ({ className, ...props }) => (_jsx(SelectItem, { className: cn(className), ...props }));
|
|
574
|
-
export const PromptInputSelectValue = ({ className, ...props }) => (_jsx(SelectValue, { className: cn(className), ...props }));
|
|
575
|
-
export const PromptInputHoverCard = ({ openDelay = 0, closeDelay = 0, ...props }) => (_jsx(HoverCard, { closeDelay: closeDelay, openDelay: openDelay, ...props }));
|
|
576
|
-
export const PromptInputHoverCardTrigger = (props) => _jsx(HoverCardTrigger, { ...props });
|
|
577
|
-
export const PromptInputHoverCardContent = ({ align = 'start', ...props }) => (_jsx(HoverCardContent, { align: align, ...props }));
|
|
578
|
-
export const PromptInputTabsList = ({ className, ...props }) => _jsx("div", { className: cn(className), ...props });
|
|
579
|
-
export const PromptInputTab = ({ className, ...props }) => _jsx("div", { className: cn(className), ...props });
|
|
580
|
-
export const PromptInputTabLabel = ({ className, ...props }) => (_jsx("h3", { className: cn('mb-2 px-3 font-medium text-muted-foreground text-xs', className), ...props }));
|
|
581
|
-
export const PromptInputTabBody = ({ className, ...props }) => (_jsx("div", { className: cn('space-y-1', className), ...props }));
|
|
582
|
-
export const PromptInputTabItem = ({ className, ...props }) => (_jsx("div", { className: cn('flex items-center gap-2 px-3 py-2 text-xs hover:bg-accent', className), ...props }));
|
|
583
|
-
export const PromptInputCommand = ({ className, ...props }) => _jsx(Command, { className: cn(className), ...props });
|
|
584
|
-
export const PromptInputCommandInput = ({ className, ...props }) => (_jsx(CommandInput, { className: cn(className), ...props }));
|
|
585
|
-
export const PromptInputCommandList = ({ className, ...props }) => (_jsx(CommandList, { className: cn(className), ...props }));
|
|
586
|
-
export const PromptInputCommandEmpty = ({ className, ...props }) => (_jsx(CommandEmpty, { className: cn(className), ...props }));
|
|
587
|
-
export const PromptInputCommandGroup = ({ className, ...props }) => (_jsx(CommandGroup, { className: cn(className), ...props }));
|
|
588
|
-
export const PromptInputCommandItem = ({ className, ...props }) => (_jsx(CommandItem, { className: cn(className), ...props }));
|
|
589
|
-
export const PromptInputCommandSeparator = ({ className, ...props }) => (_jsx(CommandSeparator, { className: cn(className), ...props }));
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
|
|
2
|
-
import type { ComponentProps, ReactNode } from 'react';
|
|
3
|
-
type ReasoningContextValue = {
|
|
4
|
-
isStreaming: boolean;
|
|
5
|
-
isOpen: boolean;
|
|
6
|
-
setIsOpen: (open: boolean) => void;
|
|
7
|
-
duration: number | undefined;
|
|
8
|
-
};
|
|
9
|
-
export declare const useReasoning: () => ReasoningContextValue;
|
|
10
|
-
export type ReasoningProps = ComponentProps<typeof Collapsible> & {
|
|
11
|
-
isStreaming?: boolean;
|
|
12
|
-
open?: boolean;
|
|
13
|
-
defaultOpen?: boolean;
|
|
14
|
-
onOpenChange?: (open: boolean) => void;
|
|
15
|
-
duration?: number;
|
|
16
|
-
};
|
|
17
|
-
export declare const Reasoning: import("react").MemoExoticComponent<({ className, isStreaming, open, defaultOpen, onOpenChange, duration: durationProp, children, ...props }: ReasoningProps) => import("react/jsx-runtime").JSX.Element>;
|
|
18
|
-
export type ReasoningTriggerProps = ComponentProps<typeof CollapsibleTrigger> & {
|
|
19
|
-
getThinkingMessage?: (isStreaming: boolean, duration?: number) => ReactNode;
|
|
20
|
-
};
|
|
21
|
-
export declare const ReasoningTrigger: import("react").MemoExoticComponent<({ className, children, getThinkingMessage, ...props }: ReasoningTriggerProps) => import("react/jsx-runtime").JSX.Element>;
|
|
22
|
-
export type ReasoningContentProps = ComponentProps<typeof CollapsibleContent> & {
|
|
23
|
-
children: string;
|
|
24
|
-
};
|
|
25
|
-
export declare const ReasoningContent: import("react").MemoExoticComponent<({ className, children, ...props }: ReasoningContentProps) => import("react/jsx-runtime").JSX.Element>;
|
|
26
|
-
export {};
|