diff --git a/crates/goose/src/providers/ollama.rs b/crates/goose/src/providers/ollama.rs index 95c57a65c414..d90fcc115082 100644 --- a/crates/goose/src/providers/ollama.rs +++ b/crates/goose/src/providers/ollama.rs @@ -30,9 +30,13 @@ use url::Url; pub const OLLAMA_HOST: &str = "localhost"; pub const OLLAMA_TIMEOUT: u64 = 600; // seconds pub const OLLAMA_DEFAULT_PORT: u16 = 11434; -pub const OLLAMA_DEFAULT_MODEL: &str = "qwen2.5"; +pub const OLLAMA_DEFAULT_MODEL: &str = "qwen3"; // Ollama can run many models, we only provide the default -pub const OLLAMA_KNOWN_MODELS: &[&str] = &[OLLAMA_DEFAULT_MODEL]; +pub const OLLAMA_KNOWN_MODELS: &[&str] = &[ + OLLAMA_DEFAULT_MODEL, + "qwen3-coder:30b", + "qwen3-coder:480b-cloud", +]; pub const OLLAMA_DOC_URL: &str = "https://ollama.com/library"; #[derive(serde::Serialize)] diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index 4f7d6a2cba63..1f36c5630d3a 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -22,7 +22,7 @@ import MentionPopover, { FileItemWithMatch } from './MentionPopover'; import { useDictationSettings } from '../hooks/useDictationSettings'; import { useContextManager } from './context_management/ContextManager'; import { useChatContext } from '../contexts/ChatContext'; -import { COST_TRACKING_ENABLED } from '../updates'; +import { COST_TRACKING_ENABLED, VOICE_DICTATION_ELEVENLABS_ENABLED } from '../updates'; import { CostTracker } from './bottom_menu/CostTracker'; import { DroppedFile, useFileDrop } from '../hooks/useFileDrop'; import { Recipe } from '../recipe'; @@ -1184,9 +1184,6 @@ export default function ChatInput({ !agentIsReady || isExtensionsLoading; - const isUserInputDisabled = - isAnyImageLoading || isAnyDroppedFileLoading || isRecording || isTranscribing || isCompacting; - // Queue management functions - no storage persistence, only in-memory const handleRemoveQueuedMessage = (messageId: string) => { setQueuedMessages((prev) => prev.filter((msg) => msg.id !== messageId)); @@ -1301,7 +1298,6 @@ export default function ChatInput({ onBlur={() => setIsFocused(false)} ref={textAreaRef} rows={1} - disabled={isUserInputDisabled} style={{ maxHeight: `${maxHeight}px`, overflowY: 'auto', @@ -1348,7 +1344,8 @@ export default function ChatInput({ OpenAI API key is not configured. Set it up in Settings {'>'}{' '} Models.

- ) : dictationSettings.provider === 'elevenlabs' ? ( + ) : VOICE_DICTATION_ELEVENLABS_ENABLED && + dictationSettings.provider === 'elevenlabs' ? (

ElevenLabs API key is not configured. Set it up in Settings {'>'}{' '} Chat {'>'} Voice Dictation. diff --git a/ui/desktop/src/components/recipes/shared/RecipeFormFields.tsx b/ui/desktop/src/components/recipes/shared/RecipeFormFields.tsx index 553c04f763b5..dc168748e676 100644 --- a/ui/desktop/src/components/recipes/shared/RecipeFormFields.tsx +++ b/ui/desktop/src/components/recipes/shared/RecipeFormFields.tsx @@ -38,6 +38,16 @@ export function RecipeFormFields({ const [newParameterName, setNewParameterName] = useState(''); const [expandedParameters, setExpandedParameters] = useState>(new Set()); + // Force re-render when instructions, prompt, or activities change + const [_forceRender, setForceRender] = useState(0); + + React.useEffect(() => { + return form.store.subscribe(() => { + // Force re-render when any form field changes to update parameter usage indicators + setForceRender((prev) => prev + 1); + }); + }, [form.store]); + const parseParametersFromInstructions = React.useCallback( (instructions: string, prompt?: string, activities?: string[]): Parameter[] => { const instructionVars = extractTemplateVariables(instructions); diff --git a/ui/desktop/src/components/settings/dictation/ProviderInfo.tsx b/ui/desktop/src/components/settings/dictation/ProviderInfo.tsx index 2cfedd7f1d2d..5104502d206c 100644 --- a/ui/desktop/src/components/settings/dictation/ProviderInfo.tsx +++ b/ui/desktop/src/components/settings/dictation/ProviderInfo.tsx @@ -1,4 +1,5 @@ import { DictationProvider } from '../../../hooks/useDictationSettings'; +import { VOICE_DICTATION_ELEVENLABS_ENABLED } from '../../../updates'; interface ProviderInfoProps { provider: DictationProvider; @@ -15,7 +16,7 @@ export const ProviderInfo = ({ provider }: ProviderInfoProps) => { configured in the Models section.

)} - {provider === 'elevenlabs' && ( + {VOICE_DICTATION_ELEVENLABS_ENABLED && provider === 'elevenlabs' && (

Uses ElevenLabs speech-to-text API for high-quality transcription. diff --git a/ui/desktop/src/components/settings/dictation/ProviderSelector.tsx b/ui/desktop/src/components/settings/dictation/ProviderSelector.tsx index b1b868b6af9a..479cd7b581b9 100644 --- a/ui/desktop/src/components/settings/dictation/ProviderSelector.tsx +++ b/ui/desktop/src/components/settings/dictation/ProviderSelector.tsx @@ -4,6 +4,7 @@ import { DictationProvider, DictationSettings } from '../../../hooks/useDictatio import { useConfig } from '../../ConfigContext'; import { ElevenLabsKeyInput } from './ElevenLabsKeyInput'; import { ProviderInfo } from './ProviderInfo'; +import { VOICE_DICTATION_ELEVENLABS_ENABLED } from '../../../updates'; interface ProviderSelectorProps { settings: DictationSettings; @@ -85,26 +86,30 @@ export const ProviderSelector = ({ settings, onProviderChange }: ProviderSelecto

- + {VOICE_DICTATION_ELEVENLABS_ENABLED && ( + + )}
)}
- {settings.provider === 'elevenlabs' && } + {VOICE_DICTATION_ELEVENLABS_ENABLED && settings.provider === 'elevenlabs' && ( + + )} diff --git a/ui/desktop/src/components/settings/dictation/VoiceDictationToggle.tsx b/ui/desktop/src/components/settings/dictation/VoiceDictationToggle.tsx index c68c3f75e6ab..06597dc23663 100644 --- a/ui/desktop/src/components/settings/dictation/VoiceDictationToggle.tsx +++ b/ui/desktop/src/components/settings/dictation/VoiceDictationToggle.tsx @@ -7,6 +7,7 @@ import { } from '../../../hooks/dictationConstants'; import { useConfig } from '../../ConfigContext'; import { ProviderSelector } from './ProviderSelector'; +import { VOICE_DICTATION_ELEVENLABS_ENABLED } from '../../../updates'; export const VoiceDictationToggle = () => { const [settings, setSettings] = useState({ @@ -24,6 +25,15 @@ export const VoiceDictationToggle = () => { if (savedSettings) { const parsed = JSON.parse(savedSettings); loadedSettings = parsed; + + // If ElevenLabs is disabled and user has it selected, reset to OpenAI + if (!VOICE_DICTATION_ELEVENLABS_ENABLED && loadedSettings.provider === 'elevenlabs') { + loadedSettings = { + ...loadedSettings, + provider: 'openai', + }; + localStorage.setItem(DICTATION_SETTINGS_KEY, JSON.stringify(loadedSettings)); + } } else { loadedSettings = await getDefaultDictationSettings(getProviders); } diff --git a/ui/desktop/src/updates.ts b/ui/desktop/src/updates.ts index 978b7624298d..f385af4be5e8 100644 --- a/ui/desktop/src/updates.ts +++ b/ui/desktop/src/updates.ts @@ -2,3 +2,4 @@ export const UPDATES_ENABLED = true; export const COST_TRACKING_ENABLED = true; export const ANNOUNCEMENTS_ENABLED = false; export const CONFIGURATION_ENABLED = true; +export const VOICE_DICTATION_ELEVENLABS_ENABLED = true;