@open-mercato/ai-assistant 0.4.11-develop.1918.e117165f7f → 0.4.11-develop.1923.169bef99c6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frontend/components/DockableChat/DockableChat.js +5 -0
- package/dist/frontend/components/DockableChat/DockableChat.js.map +2 -2
- package/dist/frontend/hooks/useCommandPalette.js +16 -12
- package/dist/frontend/hooks/useCommandPalette.js.map +2 -2
- package/dist/frontend/hooks/useMcpTools.js +22 -21
- package/dist/frontend/hooks/useMcpTools.js.map +2 -2
- package/dist/modules/ai_assistant/api/chat/route.js +9 -1
- package/dist/modules/ai_assistant/api/chat/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/health/route.js +9 -1
- package/dist/modules/ai_assistant/api/health/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/route/route.js +9 -1
- package/dist/modules/ai_assistant/api/route/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/settings/route.js +9 -1
- package/dist/modules/ai_assistant/api/settings/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/tools/execute/route.js +9 -1
- package/dist/modules/ai_assistant/api/tools/execute/route.js.map +2 -2
- package/dist/modules/ai_assistant/api/tools/route.js +9 -1
- package/dist/modules/ai_assistant/api/tools/route.js.map +2 -2
- package/dist/modules/ai_assistant/lib/opencode-client.js +24 -8
- package/dist/modules/ai_assistant/lib/opencode-client.js.map +2 -2
- package/package.json +4 -4
- package/src/frontend/components/DockableChat/DockableChat.tsx +5 -0
- package/src/frontend/hooks/useCommandPalette.ts +17 -12
- package/src/frontend/hooks/useMcpTools.ts +22 -22
- package/src/modules/ai_assistant/api/chat/route.ts +9 -0
- package/src/modules/ai_assistant/api/health/route.ts +9 -0
- package/src/modules/ai_assistant/api/route/route.ts +9 -0
- package/src/modules/ai_assistant/api/settings/route.ts +9 -0
- package/src/modules/ai_assistant/api/tools/execute/route.ts +9 -0
- package/src/modules/ai_assistant/api/tools/route.ts +9 -0
- package/src/modules/ai_assistant/lib/opencode-client.ts +24 -8
|
@@ -186,6 +186,11 @@ function DockableChat() {
|
|
|
186
186
|
const handleChatKeyDown = (e) => {
|
|
187
187
|
if (e.key === "Escape") {
|
|
188
188
|
e.stopPropagation();
|
|
189
|
+
if (phase !== "idle") {
|
|
190
|
+
reset();
|
|
191
|
+
} else {
|
|
192
|
+
close();
|
|
193
|
+
}
|
|
189
194
|
}
|
|
190
195
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
191
196
|
e.preventDefault();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/frontend/components/DockableChat/DockableChat.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Command } from 'cmdk'\nimport {\n Loader2,\n Send,\n Square,\n X,\n Minimize2,\n PanelRight,\n PanelLeft,\n PanelBottom,\n MessageCircle,\n} from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useCommandPaletteContext } from '../CommandPalette/CommandPaletteProvider'\nimport { CommandInput } from '../CommandPalette/CommandInput'\nimport { CommandHeader } from '../CommandPalette/CommandHeader'\nimport { CommandFooter } from '../CommandPalette/CommandFooter'\nimport { ToolChatPage } from '../CommandPalette/ToolChatPage'\nimport { DebugPanel } from '../CommandPalette/DebugPanel'\nimport { AiDot } from '../AiDot'\nimport type { DockPosition } from '../../types'\nimport { useDockPosition } from '../../hooks/useDockPosition'\n\n// Idle state - shown when palette is open but no query submitted\nfunction IdleState() {\n const t = useT()\n return (\n <div className=\"py-8 px-4 text-center text-muted-foreground\">\n <p className=\"mb-2\">{t('ai_assistant.chat.idleTitle')}</p>\n <p className=\"text-sm\">{t('ai_assistant.chat.idleExamples')}</p>\n <ul className=\"text-sm mt-2 space-y-1\">\n <li>"{t('ai_assistant.chat.example.search')}"</li>\n <li>"{t('ai_assistant.chat.example.create')}"</li>\n <li>"{t('ai_assistant.chat.example.show')}"</li>\n </ul>\n </div>\n )\n}\n\n// Routing indicator - shown while fast model analyzes intent\nfunction RoutingIndicator() {\n const t = useT()\n return (\n <div className=\"py-8 flex items-center justify-center gap-2\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n <span className=\"text-sm text-muted-foreground\">{t('ai_assistant.status.analyzing')}</span>\n </div>\n )\n}\n\ninterface DockControlsProps {\n position: DockPosition\n onPositionChange: (position: DockPosition) => void\n onMinimize: () => void\n onClose: () => void\n}\n\nfunction DockControls({\n position,\n onPositionChange,\n onMinimize,\n onClose,\n}: DockControlsProps) {\n const t = useT()\n const positions: { value: DockPosition; icon: React.ReactNode; labelKey: string }[] = [\n { value: 'floating', icon: <MessageCircle className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.floating' },\n { value: 'left', icon: <PanelLeft className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.left' },\n { value: 'bottom', icon: <PanelBottom className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.bottom' },\n { value: 'right', icon: <PanelRight className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.right' },\n ]\n\n return (\n <div className=\"flex items-center gap-1\">\n {positions.map((pos) => (\n <Button\n key={pos.value}\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-6 w-6', position === pos.value && 'bg-accent')}\n onClick={() => onPositionChange(pos.value)}\n title={t(pos.labelKey)}\n >\n {pos.icon}\n </Button>\n ))}\n <div className=\"w-px h-4 bg-border mx-1\" />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onMinimize}\n title={t('ai_assistant.dock.minimize')}\n >\n <Minimize2 className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onClose}\n title={t('ai_assistant.dock.close')}\n >\n <X className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n )\n}\n\nconst FLOATING_POSITION_STYLE: React.CSSProperties = {\n bottom: 24,\n right: 24,\n}\n\nexport function DockableChat() {\n const t = useT()\n const {\n state,\n isThinking,\n agentStatus,\n isSessionAuthorized,\n messages,\n pendingToolCalls,\n selectedTool,\n close,\n reset,\n handleSubmit,\n sendAgenticMessage,\n stopExecution,\n approveToolCall,\n rejectToolCall,\n debugEvents,\n showDebug,\n setShowDebug,\n clearDebugEvents,\n pendingQuestion,\n answerQuestion,\n } = useCommandPaletteContext()\n\n const {\n dockState,\n setPosition,\n toggleMinimized,\n setMinimized,\n isFloating,\n isHydrated,\n } = useDockPosition()\n\n const {\n isOpen,\n phase,\n isLoading,\n isStreaming,\n connectionStatus,\n } = state\n\n const [localInput, setLocalInput] = React.useState('')\n const [chatInput, setChatInput] = React.useState('')\n const chatInputRef = React.useRef<HTMLInputElement>(null)\n\n // Reset local input when phase changes to idle\n React.useEffect(() => {\n if (phase === 'idle') {\n setLocalInput('')\n setChatInput('')\n }\n }, [phase])\n\n // Focus chat input when entering chatting phase\n React.useEffect(() => {\n if (phase === 'chatting' || phase === 'confirming' || phase === 'executing') {\n setTimeout(() => chatInputRef.current?.focus(), 50)\n }\n }, [phase])\n\n const handleInputSubmit = async () => {\n const query = localInput.trim()\n if (!query) return\n setLocalInput('')\n await handleSubmit(query)\n }\n\n const handleInputKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && phase === 'idle' && localInput.trim()) {\n e.preventDefault()\n handleInputSubmit()\n }\n }\n\n const handleChatSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!chatInput.trim() || isStreaming) return\n\n const content = chatInput\n setChatInput('')\n await sendAgenticMessage(content)\n }\n\n const handleChatKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (chatInput.trim() && !isStreaming) {\n const content = chatInput\n setChatInput('')\n sendAgenticMessage(content)\n }\n }\n }\n\n // Don't render until hydrated to avoid SSR mismatch\n if (!isHydrated) return null\n\n // When minimized in any mode, show the AiDot in bottom-right corner\n if (isOpen && dockState.isMinimized) {\n return typeof document !== 'undefined' ? createPortal(\n <AiDot\n onClick={() => setMinimized(false)}\n isActive={isStreaming || isThinking}\n hasMessages={messages.length > 0}\n position=\"bottom-right\"\n />,\n document.body\n ) : null\n }\n\n // Render as floating panel when in floating mode\n if (isFloating) {\n if (!isOpen) return null\n\n return typeof document !== 'undefined' ? createPortal(\n <>\n <div\n className={cn(\n 'fixed z-50',\n 'rounded-xl border bg-background shadow-2xl',\n 'flex flex-col',\n 'transition-all duration-200 ease-out'\n )}\n style={{\n ...FLOATING_POSITION_STYLE,\n width: dockState.width,\n height: dockState.height,\n maxHeight: 'calc(100vh - 48px)',\n }}\n onKeyDown={handleInputKeyDown}\n >\n <Command className=\"flex flex-col flex-1 min-h-0 rounded-xl overflow-hidden\" shouldFilter={false}>\n {/* Dock controls header */}\n <div className=\"flex items-center justify-end px-2 py-1.5 border-b shrink-0\">\n <DockControls\n position={dockState.position}\n onPositionChange={setPosition}\n onMinimize={toggleMinimized}\n onClose={close}\n />\n </div>\n\n <CommandHeader\n phase={phase}\n selectedTool={selectedTool}\n onBack={reset}\n />\n\n {phase === 'idle' && (\n <CommandInput\n value={localInput}\n onValueChange={setLocalInput}\n mode=\"commands\"\n isLoading={isLoading}\n placeholder={t('ai_assistant.chat.placeholder')}\n />\n )}\n\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {phase === 'idle' && !localInput && <IdleState />}\n {phase === 'routing' && <RoutingIndicator />}\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <ToolChatPage\n tool={selectedTool}\n messages={messages}\n pendingToolCalls={pendingToolCalls}\n isStreaming={isStreaming}\n isThinking={isThinking}\n agentStatus={agentStatus}\n onApproveToolCall={approveToolCall}\n onRejectToolCall={rejectToolCall}\n pendingQuestion={pendingQuestion}\n onAnswerQuestion={answerQuestion}\n />\n )}\n </div>\n\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <form onSubmit={handleChatSubmit} className=\"shrink-0 border-t p-3\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={chatInputRef}\n type=\"text\"\n value={chatInput}\n onChange={(e) => setChatInput(e.target.value)}\n onKeyDown={handleChatKeyDown}\n placeholder={t('ai_assistant.chat.describePlaceholder')}\n className={cn(\n 'flex-1 bg-muted rounded-lg px-4 py-2 text-sm outline-none',\n 'focus:ring-2 focus:ring-ring',\n 'disabled:opacity-50'\n )}\n disabled={isStreaming}\n />\n <Button\n type={isStreaming ? 'button' : 'submit'}\n size=\"icon\"\n variant={isStreaming ? 'destructive' : 'default'}\n onClick={isStreaming ? stopExecution : undefined}\n disabled={!isStreaming && !chatInput.trim()}\n >\n {isStreaming ? (\n <Square className=\"h-4 w-4\" />\n ) : (\n <Send className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </form>\n )}\n\n <CommandFooter\n phase={phase}\n connectionStatus={connectionStatus}\n isSessionAuthorized={isSessionAuthorized}\n showDebug={showDebug}\n onToggleDebug={() => setShowDebug(!showDebug)}\n />\n </Command>\n </div>\n\n {showDebug && (\n <div\n data-debug-panel\n className=\"fixed z-[9999] bg-gray-900 rounded-xl border border-gray-700 shadow-2xl flex flex-col overflow-hidden\"\n style={{\n top: '24px',\n left: '24px',\n width: '400px',\n maxHeight: 'calc(100vh - 48px)',\n }}\n >\n <DebugPanel\n events={debugEvents}\n onClear={clearDebugEvents}\n isOpen={true}\n onToggle={() => setShowDebug(false)}\n />\n </div>\n )}\n </>,\n document.body\n ) : null\n }\n\n // Render as docked panel (right, left, bottom)\n if (!isOpen) return null\n\n const positionStyles: Record<Exclude<DockPosition, 'floating'>, React.CSSProperties> = {\n right: {\n position: 'fixed',\n top: 0,\n right: 0,\n bottom: 0,\n width: dockState.width,\n zIndex: 40,\n },\n left: {\n position: 'fixed',\n top: 0,\n left: 0,\n bottom: 0,\n width: dockState.width,\n zIndex: 40,\n },\n bottom: {\n position: 'fixed',\n bottom: 0,\n left: 0,\n right: 0,\n height: dockState.height,\n zIndex: 40,\n },\n }\n\n const panelPosition = dockState.position as Exclude<DockPosition, 'floating'>\n\n return typeof document !== 'undefined' ? createPortal(\n <div\n className={cn(\n 'bg-background border shadow-xl flex flex-col',\n panelPosition === 'right' && 'border-l',\n panelPosition === 'left' && 'border-r',\n panelPosition === 'bottom' && 'border-t'\n )}\n style={positionStyles[panelPosition]}\n onKeyDown={handleInputKeyDown}\n >\n {/* Docked panel header */}\n <div className=\"flex items-center justify-end px-2 py-1.5 border-b shrink-0\">\n <DockControls\n position={dockState.position}\n onPositionChange={setPosition}\n onMinimize={toggleMinimized}\n onClose={close}\n />\n </div>\n\n {!dockState.isMinimized && (\n <>\n <Command className=\"flex flex-col flex-1 min-h-0\" shouldFilter={false}>\n <CommandHeader\n phase={phase}\n selectedTool={selectedTool}\n onBack={reset}\n />\n\n {phase === 'idle' && (\n <CommandInput\n value={localInput}\n onValueChange={setLocalInput}\n mode=\"commands\"\n isLoading={isLoading}\n placeholder={t('ai_assistant.chat.placeholder')}\n />\n )}\n\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {phase === 'idle' && !localInput && <IdleState />}\n {phase === 'routing' && <RoutingIndicator />}\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <ToolChatPage\n tool={selectedTool}\n messages={messages}\n pendingToolCalls={pendingToolCalls}\n isStreaming={isStreaming}\n isThinking={isThinking}\n agentStatus={agentStatus}\n onApproveToolCall={approveToolCall}\n onRejectToolCall={rejectToolCall}\n pendingQuestion={pendingQuestion}\n onAnswerQuestion={answerQuestion}\n />\n )}\n </div>\n\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <form onSubmit={handleChatSubmit} className=\"shrink-0 border-t p-3\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={chatInputRef}\n type=\"text\"\n value={chatInput}\n onChange={(e) => setChatInput(e.target.value)}\n onKeyDown={handleChatKeyDown}\n placeholder={t('ai_assistant.chat.describePlaceholder')}\n className={cn(\n 'flex-1 bg-muted rounded-lg px-4 py-2 text-sm outline-none',\n 'focus:ring-2 focus:ring-ring',\n 'disabled:opacity-50'\n )}\n disabled={isStreaming}\n />\n <Button\n type={isStreaming ? 'button' : 'submit'}\n size=\"icon\"\n variant={isStreaming ? 'destructive' : 'default'}\n onClick={isStreaming ? stopExecution : undefined}\n disabled={!isStreaming && !chatInput.trim()}\n >\n {isStreaming ? (\n <Square className=\"h-4 w-4\" />\n ) : (\n <Send className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </form>\n )}\n\n <CommandFooter\n phase={phase}\n connectionStatus={connectionStatus}\n isSessionAuthorized={isSessionAuthorized}\n showDebug={showDebug}\n onToggleDebug={() => setShowDebug(!showDebug)}\n />\n </Command>\n </>\n )}\n\n {showDebug && (\n <div\n className={cn(\n 'bg-gray-900 border-gray-700 flex flex-col overflow-hidden',\n panelPosition === 'right' && 'absolute left-0 top-0 bottom-0 w-[400px] -translate-x-full border-r',\n panelPosition === 'left' && 'absolute right-0 top-0 bottom-0 w-[400px] translate-x-full border-l',\n panelPosition === 'bottom' && 'absolute bottom-full left-0 right-0 h-[300px] border-t'\n )}\n >\n <DebugPanel\n events={debugEvents}\n onClear={clearDebugEvents}\n isOpen={true}\n onToggle={() => setShowDebug(false)}\n />\n </div>\n )}\n </div>,\n document.body\n ) : null\n}\n"],
|
|
5
|
-
"mappings": ";AAkCM,
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { createPortal } from 'react-dom'\nimport { Command } from 'cmdk'\nimport {\n Loader2,\n Send,\n Square,\n X,\n Minimize2,\n PanelRight,\n PanelLeft,\n PanelBottom,\n MessageCircle,\n} from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useCommandPaletteContext } from '../CommandPalette/CommandPaletteProvider'\nimport { CommandInput } from '../CommandPalette/CommandInput'\nimport { CommandHeader } from '../CommandPalette/CommandHeader'\nimport { CommandFooter } from '../CommandPalette/CommandFooter'\nimport { ToolChatPage } from '../CommandPalette/ToolChatPage'\nimport { DebugPanel } from '../CommandPalette/DebugPanel'\nimport { AiDot } from '../AiDot'\nimport type { DockPosition } from '../../types'\nimport { useDockPosition } from '../../hooks/useDockPosition'\n\n// Idle state - shown when palette is open but no query submitted\nfunction IdleState() {\n const t = useT()\n return (\n <div className=\"py-8 px-4 text-center text-muted-foreground\">\n <p className=\"mb-2\">{t('ai_assistant.chat.idleTitle')}</p>\n <p className=\"text-sm\">{t('ai_assistant.chat.idleExamples')}</p>\n <ul className=\"text-sm mt-2 space-y-1\">\n <li>"{t('ai_assistant.chat.example.search')}"</li>\n <li>"{t('ai_assistant.chat.example.create')}"</li>\n <li>"{t('ai_assistant.chat.example.show')}"</li>\n </ul>\n </div>\n )\n}\n\n// Routing indicator - shown while fast model analyzes intent\nfunction RoutingIndicator() {\n const t = useT()\n return (\n <div className=\"py-8 flex items-center justify-center gap-2\">\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n <span className=\"text-sm text-muted-foreground\">{t('ai_assistant.status.analyzing')}</span>\n </div>\n )\n}\n\ninterface DockControlsProps {\n position: DockPosition\n onPositionChange: (position: DockPosition) => void\n onMinimize: () => void\n onClose: () => void\n}\n\nfunction DockControls({\n position,\n onPositionChange,\n onMinimize,\n onClose,\n}: DockControlsProps) {\n const t = useT()\n const positions: { value: DockPosition; icon: React.ReactNode; labelKey: string }[] = [\n { value: 'floating', icon: <MessageCircle className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.floating' },\n { value: 'left', icon: <PanelLeft className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.left' },\n { value: 'bottom', icon: <PanelBottom className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.bottom' },\n { value: 'right', icon: <PanelRight className=\"h-3.5 w-3.5\" />, labelKey: 'ai_assistant.dock.right' },\n ]\n\n return (\n <div className=\"flex items-center gap-1\">\n {positions.map((pos) => (\n <Button\n key={pos.value}\n variant=\"ghost\"\n size=\"icon\"\n className={cn('h-6 w-6', position === pos.value && 'bg-accent')}\n onClick={() => onPositionChange(pos.value)}\n title={t(pos.labelKey)}\n >\n {pos.icon}\n </Button>\n ))}\n <div className=\"w-px h-4 bg-border mx-1\" />\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onMinimize}\n title={t('ai_assistant.dock.minimize')}\n >\n <Minimize2 className=\"h-3.5 w-3.5\" />\n </Button>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n className=\"h-6 w-6\"\n onClick={onClose}\n title={t('ai_assistant.dock.close')}\n >\n <X className=\"h-3.5 w-3.5\" />\n </Button>\n </div>\n )\n}\n\nconst FLOATING_POSITION_STYLE: React.CSSProperties = {\n bottom: 24,\n right: 24,\n}\n\nexport function DockableChat() {\n const t = useT()\n const {\n state,\n isThinking,\n agentStatus,\n isSessionAuthorized,\n messages,\n pendingToolCalls,\n selectedTool,\n close,\n reset,\n handleSubmit,\n sendAgenticMessage,\n stopExecution,\n approveToolCall,\n rejectToolCall,\n debugEvents,\n showDebug,\n setShowDebug,\n clearDebugEvents,\n pendingQuestion,\n answerQuestion,\n } = useCommandPaletteContext()\n\n const {\n dockState,\n setPosition,\n toggleMinimized,\n setMinimized,\n isFloating,\n isHydrated,\n } = useDockPosition()\n\n const {\n isOpen,\n phase,\n isLoading,\n isStreaming,\n connectionStatus,\n } = state\n\n const [localInput, setLocalInput] = React.useState('')\n const [chatInput, setChatInput] = React.useState('')\n const chatInputRef = React.useRef<HTMLInputElement>(null)\n\n // Reset local input when phase changes to idle\n React.useEffect(() => {\n if (phase === 'idle') {\n setLocalInput('')\n setChatInput('')\n }\n }, [phase])\n\n // Focus chat input when entering chatting phase\n React.useEffect(() => {\n if (phase === 'chatting' || phase === 'confirming' || phase === 'executing') {\n setTimeout(() => chatInputRef.current?.focus(), 50)\n }\n }, [phase])\n\n const handleInputSubmit = async () => {\n const query = localInput.trim()\n if (!query) return\n setLocalInput('')\n await handleSubmit(query)\n }\n\n const handleInputKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' && phase === 'idle' && localInput.trim()) {\n e.preventDefault()\n handleInputSubmit()\n }\n }\n\n const handleChatSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!chatInput.trim() || isStreaming) return\n\n const content = chatInput\n setChatInput('')\n await sendAgenticMessage(content)\n }\n\n const handleChatKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n if (phase !== 'idle') {\n reset()\n } else {\n close()\n }\n }\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n if (chatInput.trim() && !isStreaming) {\n const content = chatInput\n setChatInput('')\n sendAgenticMessage(content)\n }\n }\n }\n\n // Don't render until hydrated to avoid SSR mismatch\n if (!isHydrated) return null\n\n // When minimized in any mode, show the AiDot in bottom-right corner\n if (isOpen && dockState.isMinimized) {\n return typeof document !== 'undefined' ? createPortal(\n <AiDot\n onClick={() => setMinimized(false)}\n isActive={isStreaming || isThinking}\n hasMessages={messages.length > 0}\n position=\"bottom-right\"\n />,\n document.body\n ) : null\n }\n\n // Render as floating panel when in floating mode\n if (isFloating) {\n if (!isOpen) return null\n\n return typeof document !== 'undefined' ? createPortal(\n <>\n <div\n className={cn(\n 'fixed z-50',\n 'rounded-xl border bg-background shadow-2xl',\n 'flex flex-col',\n 'transition-all duration-200 ease-out'\n )}\n style={{\n ...FLOATING_POSITION_STYLE,\n width: dockState.width,\n height: dockState.height,\n maxHeight: 'calc(100vh - 48px)',\n }}\n onKeyDown={handleInputKeyDown}\n >\n <Command className=\"flex flex-col flex-1 min-h-0 rounded-xl overflow-hidden\" shouldFilter={false}>\n {/* Dock controls header */}\n <div className=\"flex items-center justify-end px-2 py-1.5 border-b shrink-0\">\n <DockControls\n position={dockState.position}\n onPositionChange={setPosition}\n onMinimize={toggleMinimized}\n onClose={close}\n />\n </div>\n\n <CommandHeader\n phase={phase}\n selectedTool={selectedTool}\n onBack={reset}\n />\n\n {phase === 'idle' && (\n <CommandInput\n value={localInput}\n onValueChange={setLocalInput}\n mode=\"commands\"\n isLoading={isLoading}\n placeholder={t('ai_assistant.chat.placeholder')}\n />\n )}\n\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {phase === 'idle' && !localInput && <IdleState />}\n {phase === 'routing' && <RoutingIndicator />}\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <ToolChatPage\n tool={selectedTool}\n messages={messages}\n pendingToolCalls={pendingToolCalls}\n isStreaming={isStreaming}\n isThinking={isThinking}\n agentStatus={agentStatus}\n onApproveToolCall={approveToolCall}\n onRejectToolCall={rejectToolCall}\n pendingQuestion={pendingQuestion}\n onAnswerQuestion={answerQuestion}\n />\n )}\n </div>\n\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <form onSubmit={handleChatSubmit} className=\"shrink-0 border-t p-3\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={chatInputRef}\n type=\"text\"\n value={chatInput}\n onChange={(e) => setChatInput(e.target.value)}\n onKeyDown={handleChatKeyDown}\n placeholder={t('ai_assistant.chat.describePlaceholder')}\n className={cn(\n 'flex-1 bg-muted rounded-lg px-4 py-2 text-sm outline-none',\n 'focus:ring-2 focus:ring-ring',\n 'disabled:opacity-50'\n )}\n disabled={isStreaming}\n />\n <Button\n type={isStreaming ? 'button' : 'submit'}\n size=\"icon\"\n variant={isStreaming ? 'destructive' : 'default'}\n onClick={isStreaming ? stopExecution : undefined}\n disabled={!isStreaming && !chatInput.trim()}\n >\n {isStreaming ? (\n <Square className=\"h-4 w-4\" />\n ) : (\n <Send className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </form>\n )}\n\n <CommandFooter\n phase={phase}\n connectionStatus={connectionStatus}\n isSessionAuthorized={isSessionAuthorized}\n showDebug={showDebug}\n onToggleDebug={() => setShowDebug(!showDebug)}\n />\n </Command>\n </div>\n\n {showDebug && (\n <div\n data-debug-panel\n className=\"fixed z-[9999] bg-gray-900 rounded-xl border border-gray-700 shadow-2xl flex flex-col overflow-hidden\"\n style={{\n top: '24px',\n left: '24px',\n width: '400px',\n maxHeight: 'calc(100vh - 48px)',\n }}\n >\n <DebugPanel\n events={debugEvents}\n onClear={clearDebugEvents}\n isOpen={true}\n onToggle={() => setShowDebug(false)}\n />\n </div>\n )}\n </>,\n document.body\n ) : null\n }\n\n // Render as docked panel (right, left, bottom)\n if (!isOpen) return null\n\n const positionStyles: Record<Exclude<DockPosition, 'floating'>, React.CSSProperties> = {\n right: {\n position: 'fixed',\n top: 0,\n right: 0,\n bottom: 0,\n width: dockState.width,\n zIndex: 40,\n },\n left: {\n position: 'fixed',\n top: 0,\n left: 0,\n bottom: 0,\n width: dockState.width,\n zIndex: 40,\n },\n bottom: {\n position: 'fixed',\n bottom: 0,\n left: 0,\n right: 0,\n height: dockState.height,\n zIndex: 40,\n },\n }\n\n const panelPosition = dockState.position as Exclude<DockPosition, 'floating'>\n\n return typeof document !== 'undefined' ? createPortal(\n <div\n className={cn(\n 'bg-background border shadow-xl flex flex-col',\n panelPosition === 'right' && 'border-l',\n panelPosition === 'left' && 'border-r',\n panelPosition === 'bottom' && 'border-t'\n )}\n style={positionStyles[panelPosition]}\n onKeyDown={handleInputKeyDown}\n >\n {/* Docked panel header */}\n <div className=\"flex items-center justify-end px-2 py-1.5 border-b shrink-0\">\n <DockControls\n position={dockState.position}\n onPositionChange={setPosition}\n onMinimize={toggleMinimized}\n onClose={close}\n />\n </div>\n\n {!dockState.isMinimized && (\n <>\n <Command className=\"flex flex-col flex-1 min-h-0\" shouldFilter={false}>\n <CommandHeader\n phase={phase}\n selectedTool={selectedTool}\n onBack={reset}\n />\n\n {phase === 'idle' && (\n <CommandInput\n value={localInput}\n onValueChange={setLocalInput}\n mode=\"commands\"\n isLoading={isLoading}\n placeholder={t('ai_assistant.chat.placeholder')}\n />\n )}\n\n <div className=\"flex-1 min-h-0 overflow-y-auto\">\n {phase === 'idle' && !localInput && <IdleState />}\n {phase === 'routing' && <RoutingIndicator />}\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <ToolChatPage\n tool={selectedTool}\n messages={messages}\n pendingToolCalls={pendingToolCalls}\n isStreaming={isStreaming}\n isThinking={isThinking}\n agentStatus={agentStatus}\n onApproveToolCall={approveToolCall}\n onRejectToolCall={rejectToolCall}\n pendingQuestion={pendingQuestion}\n onAnswerQuestion={answerQuestion}\n />\n )}\n </div>\n\n {(phase === 'chatting' || phase === 'confirming' || phase === 'executing') && (\n <form onSubmit={handleChatSubmit} className=\"shrink-0 border-t p-3\">\n <div className=\"flex items-center gap-2\">\n <input\n ref={chatInputRef}\n type=\"text\"\n value={chatInput}\n onChange={(e) => setChatInput(e.target.value)}\n onKeyDown={handleChatKeyDown}\n placeholder={t('ai_assistant.chat.describePlaceholder')}\n className={cn(\n 'flex-1 bg-muted rounded-lg px-4 py-2 text-sm outline-none',\n 'focus:ring-2 focus:ring-ring',\n 'disabled:opacity-50'\n )}\n disabled={isStreaming}\n />\n <Button\n type={isStreaming ? 'button' : 'submit'}\n size=\"icon\"\n variant={isStreaming ? 'destructive' : 'default'}\n onClick={isStreaming ? stopExecution : undefined}\n disabled={!isStreaming && !chatInput.trim()}\n >\n {isStreaming ? (\n <Square className=\"h-4 w-4\" />\n ) : (\n <Send className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </form>\n )}\n\n <CommandFooter\n phase={phase}\n connectionStatus={connectionStatus}\n isSessionAuthorized={isSessionAuthorized}\n showDebug={showDebug}\n onToggleDebug={() => setShowDebug(!showDebug)}\n />\n </Command>\n </>\n )}\n\n {showDebug && (\n <div\n className={cn(\n 'bg-gray-900 border-gray-700 flex flex-col overflow-hidden',\n panelPosition === 'right' && 'absolute left-0 top-0 bottom-0 w-[400px] -translate-x-full border-r',\n panelPosition === 'left' && 'absolute right-0 top-0 bottom-0 w-[400px] translate-x-full border-l',\n panelPosition === 'bottom' && 'absolute bottom-full left-0 right-0 h-[300px] border-t'\n )}\n >\n <DebugPanel\n events={debugEvents}\n onClear={clearDebugEvents}\n isOpen={true}\n onToggle={() => setShowDebug(false)}\n />\n </div>\n )}\n </div>,\n document.body\n ) : null\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useState, useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
4
|
+
import { apiFetch } from "@open-mercato/ui/backend/utils/api";
|
|
3
5
|
import { AI_CHAT_SHORTCUT } from "../constants.js";
|
|
4
6
|
import { filterTools } from "../utils/toolMatcher.js";
|
|
5
7
|
import { useMcpTools } from "./useMcpTools.js";
|
|
@@ -361,7 +363,7 @@ function useCommandPalette(options) {
|
|
|
361
363
|
}, [state.phase]);
|
|
362
364
|
const routeQuery = useCallback(
|
|
363
365
|
async (query) => {
|
|
364
|
-
const
|
|
366
|
+
const { ok, result, status } = await apiCall("/api/ai_assistant/route", {
|
|
365
367
|
method: "POST",
|
|
366
368
|
headers: { "Content-Type": "application/json" },
|
|
367
369
|
body: JSON.stringify({
|
|
@@ -372,10 +374,13 @@ function useCommandPalette(options) {
|
|
|
372
374
|
}))
|
|
373
375
|
})
|
|
374
376
|
});
|
|
375
|
-
if (!
|
|
376
|
-
throw new Error(`Routing failed: ${
|
|
377
|
+
if (!ok) {
|
|
378
|
+
throw new Error(`Routing failed: ${status}`);
|
|
377
379
|
}
|
|
378
|
-
|
|
380
|
+
if (!result) {
|
|
381
|
+
throw new Error("Routing returned empty response");
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
379
384
|
},
|
|
380
385
|
[tools]
|
|
381
386
|
);
|
|
@@ -401,7 +406,7 @@ function useCommandPalette(options) {
|
|
|
401
406
|
currentStreamController.current?.abort();
|
|
402
407
|
const controller = new AbortController();
|
|
403
408
|
currentStreamController.current = controller;
|
|
404
|
-
const response = await
|
|
409
|
+
const response = await apiFetch("/api/ai_assistant/chat", {
|
|
405
410
|
method: "POST",
|
|
406
411
|
headers: { "Content-Type": "application/json" },
|
|
407
412
|
body: JSON.stringify({
|
|
@@ -575,7 +580,7 @@ function useCommandPalette(options) {
|
|
|
575
580
|
createdAt: /* @__PURE__ */ new Date()
|
|
576
581
|
};
|
|
577
582
|
setMessages([userMessage]);
|
|
578
|
-
const response = await
|
|
583
|
+
const response = await apiFetch("/api/ai_assistant/chat", {
|
|
579
584
|
method: "POST",
|
|
580
585
|
headers: { "Content-Type": "application/json" },
|
|
581
586
|
body: JSON.stringify({
|
|
@@ -748,7 +753,7 @@ function useCommandPalette(options) {
|
|
|
748
753
|
currentStreamController.current?.abort();
|
|
749
754
|
const controller = new AbortController();
|
|
750
755
|
currentStreamController.current = controller;
|
|
751
|
-
const response = await
|
|
756
|
+
const response = await apiFetch("/api/ai_assistant/chat", {
|
|
752
757
|
method: "POST",
|
|
753
758
|
headers: { "Content-Type": "application/json" },
|
|
754
759
|
body: JSON.stringify({
|
|
@@ -979,7 +984,7 @@ function useCommandPalette(options) {
|
|
|
979
984
|
]);
|
|
980
985
|
try {
|
|
981
986
|
const sessionId = pendingQuestion.sessionID;
|
|
982
|
-
const
|
|
987
|
+
const { ok, result, status } = await apiCall("/api/ai_assistant/chat", {
|
|
983
988
|
method: "POST",
|
|
984
989
|
headers: { "Content-Type": "application/json" },
|
|
985
990
|
body: JSON.stringify({
|
|
@@ -990,9 +995,8 @@ function useCommandPalette(options) {
|
|
|
990
995
|
}
|
|
991
996
|
})
|
|
992
997
|
});
|
|
993
|
-
if (!
|
|
994
|
-
|
|
995
|
-
throw new Error(errorData.error || `Answer request failed: ${response.status}`);
|
|
998
|
+
if (!ok) {
|
|
999
|
+
throw new Error(result?.error || `Answer request failed: ${status}`);
|
|
996
1000
|
}
|
|
997
1001
|
} catch (error) {
|
|
998
1002
|
console.error("[answerQuestion] Error:", error);
|
|
@@ -1023,7 +1027,7 @@ function useCommandPalette(options) {
|
|
|
1023
1027
|
setMessages((prev) => [...prev, userMessage]);
|
|
1024
1028
|
setState((prev) => ({ ...prev, isStreaming: true }));
|
|
1025
1029
|
try {
|
|
1026
|
-
const response = await
|
|
1030
|
+
const response = await apiFetch("/api/ai_assistant/chat", {
|
|
1027
1031
|
method: "POST",
|
|
1028
1032
|
headers: { "Content-Type": "application/json" },
|
|
1029
1033
|
body: JSON.stringify({
|