diff --git a/package-lock.json b/package-lock.json index 8a8f11f..a2553ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openconduit/core", - "version": "2.0.0-beta.8", + "version": "2.0.0-beta.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@openconduit/core", - "version": "2.0.0-beta.8", + "version": "2.0.0-beta.9", "license": "AGPL-3.0", "dependencies": { "@codemirror/commands": "^6.10.3", diff --git a/package.json b/package.json index beae195..8549324 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openconduit/core", - "version": "2.0.0-beta.8", + "version": "2.0.0-beta.9", "description": "Shared UI components, stores, hooks, and service interface for OpenConduit", "main": "src/index.ts", "types": "src/index.ts", diff --git a/src/components/InputBar.tsx b/src/components/InputBar.tsx index 12bdec1..8695fd1 100644 --- a/src/components/InputBar.tsx +++ b/src/components/InputBar.tsx @@ -60,6 +60,7 @@ export default function InputBar({ onSend, onAbort, onClear, onCompact, onTrim, const [folderFiles, setFolderFiles] = useState(null); const [folderLoading, setFolderLoading] = useState(false); const [trimConfirm, setTrimConfirm] = useState(false); + const [noModelWarning, setNoModelWarning] = useState(false); const [slashMatches, setSlashMatches] = useState([]); const [slashIndex, setSlashIndex] = useState(0); const [slashPrefix, setSlashPrefix] = useState(''); @@ -212,12 +213,19 @@ export default function InputBar({ onSend, onAbort, onClear, onCompact, onTrim, textareaRef.current?.focus(); return; } + // Guard: if no model is selected, warn instead of silently dropping the prompt + const effectiveModel = activeConv?.model || activeConv?.routingProfileId || settings?.defaultModel; + if (!effectiveModel && conversationId) { + setNoModelWarning(true); + return; + } + setNoModelWarning(false); const fc = folderPath && folderFiles ? { rootName: folderPath.split('/').pop() ?? folderPath, rootPath: folderPath, files: folderFiles } : undefined; onSend(trimmed, attachments.length > 0 ? attachments : undefined, fc, reasoning !== 'off' ? reasoning : undefined); setContent(''); setAttachments([]); textareaRef.current?.focus(); - }, [content, attachments, folderPath, folderFiles, onSend, reasoning, btwMode, onBtw]); + }, [content, attachments, folderPath, folderFiles, onSend, reasoning, btwMode, onBtw, activeConv, settings, conversationId]); const handlePickFolder = useCallback(async () => { const picked = await service.folder?.pick(); @@ -322,6 +330,7 @@ export default function InputBar({ onSend, onAbort, onClear, onCompact, onTrim, const handleTextareaChange = (e: React.ChangeEvent) => { const val = e.target.value; setContent(val); + if (noModelWarning) setNoModelWarning(false); const el = e.target; el.style.height = 'auto'; el.style.height = Math.min(el.scrollHeight, 200) + 'px'; @@ -533,6 +542,23 @@ export default function InputBar({ onSend, onAbort, onClear, onCompact, onTrim, )} + {/* No-model warning */} + {noModelWarning && ( +
+
+ + + + No model selected — pick one in the model picker above before sending. +
+ +
+ )} + {/* Input box */}