Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/goose/src/providers/ollama.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
9 changes: 3 additions & 6 deletions ui/desktop/src/components/ChatInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -1301,7 +1298,6 @@ export default function ChatInput({
onBlur={() => setIsFocused(false)}
ref={textAreaRef}
rows={1}
disabled={isUserInputDisabled}
style={{
maxHeight: `${maxHeight}px`,
overflowY: 'auto',
Expand Down Expand Up @@ -1348,7 +1344,8 @@ export default function ChatInput({
OpenAI API key is not configured. Set it up in <b>Settings</b> {'>'}{' '}
<b>Models.</b>
</p>
) : dictationSettings.provider === 'elevenlabs' ? (
) : VOICE_DICTATION_ELEVENLABS_ENABLED &&
dictationSettings.provider === 'elevenlabs' ? (
<p>
ElevenLabs API key is not configured. Set it up in <b>Settings</b> {'>'}{' '}
<b>Chat</b> {'>'} <b>Voice Dictation.</b>
Expand Down
10 changes: 10 additions & 0 deletions ui/desktop/src/components/recipes/shared/RecipeFormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ export function RecipeFormFields({
const [newParameterName, setNewParameterName] = useState('');
const [expandedParameters, setExpandedParameters] = useState<Set<string>>(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);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DictationProvider } from '../../../hooks/useDictationSettings';
import { VOICE_DICTATION_ELEVENLABS_ENABLED } from '../../../updates';

interface ProviderInfoProps {
provider: DictationProvider;
Expand All @@ -15,7 +16,7 @@ export const ProviderInfo = ({ provider }: ProviderInfoProps) => {
configured in the Models section.
</p>
)}
{provider === 'elevenlabs' && (
{VOICE_DICTATION_ELEVENLABS_ENABLED && provider === 'elevenlabs' && (
<div>
<p className="text-xs text-text-muted">
Uses ElevenLabs speech-to-text API for high-quality transcription.
Expand Down
23 changes: 14 additions & 9 deletions ui/desktop/src/components/settings/dictation/ProviderSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -85,26 +86,30 @@ export const ProviderSelector = ({ settings, onProviderChange }: ProviderSelecto
<div className="absolute right-0 mt-1 w-48 bg-background-default border border-border-default rounded-md shadow-lg z-10">
<button
onClick={() => handleProviderChange('openai')}
className="w-full px-3 py-2 text-left text-sm transition-colors first:rounded-t-md hover:bg-background-subtle text-text-default"
className={`w-full px-3 py-2 text-left text-sm transition-colors hover:bg-background-subtle text-text-default ${!VOICE_DICTATION_ELEVENLABS_ENABLED ? 'first:rounded-t-md last:rounded-b-md' : 'first:rounded-t-md'}`}
>
OpenAI Whisper
{!hasOpenAIKey && <span className="text-xs ml-1">(not configured)</span>}
{settings.provider === 'openai' && <span className="float-right">✓</span>}
</button>

<button
onClick={() => handleProviderChange('elevenlabs')}
className="w-full px-3 py-2 text-left text-sm hover:bg-background-subtle transition-colors text-text-default last:rounded-b-md"
>
ElevenLabs
{settings.provider === 'elevenlabs' && <span className="float-right">✓</span>}
</button>
{VOICE_DICTATION_ELEVENLABS_ENABLED && (
<button
onClick={() => handleProviderChange('elevenlabs')}
className="w-full px-3 py-2 text-left text-sm hover:bg-background-subtle transition-colors text-text-default last:rounded-b-md"
>
ElevenLabs
{settings.provider === 'elevenlabs' && <span className="float-right">✓</span>}
</button>
)}
</div>
)}
</div>
</div>

{settings.provider === 'elevenlabs' && <ElevenLabsKeyInput />}
{VOICE_DICTATION_ELEVENLABS_ENABLED && settings.provider === 'elevenlabs' && (
<ElevenLabsKeyInput />
)}

<ProviderInfo provider={settings.provider} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DictationSettings>({
Expand All @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions ui/desktop/src/updates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading