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
12 changes: 8 additions & 4 deletions src/main/presenter/agentRuntimePresenter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
supportsOpenAIImageGenerationSettings
} from '@shared/imageGenerationSettings'
import { isDeepSeekSeriesModelId } from '@shared/model'
import { isTtsModelConfig, isTtsModelId } from '@shared/ttsSettings'
import { nanoid } from 'nanoid'
import type { SQLitePresenter } from '../sqlitePresenter'
import { eventBus, SendTarget } from '@/eventbus'
Expand Down Expand Up @@ -1963,6 +1964,9 @@ export class AgentRuntimePresenter implements IAgentImplementation {
try {
let providerMessages = injectedMessages
let providerMaxTokens = requestMaxTokens
const isTtsRequest =
isTtsModelConfig(requestModelConfig) || isTtsModelId(requestModelId)
const effectiveRequestTools: MCPToolDefinition[] = isTtsRequest ? [] : requestTools

if (!bypassContextBudget) {
const protectedSteerTailCount =
Expand All @@ -1971,7 +1975,7 @@ export class AgentRuntimePresenter implements IAgentImplementation {
: 0
let requestPreflight = preflightRequestContext({
messages: injectedMessages,
tools: requestTools,
tools: effectiveRequestTools,
contextLength: requestModelConfig.contextLength,
requestedMaxTokens: requestMaxTokens,
minimumProtectedTailCount: protectedSteerTailCount
Expand All @@ -1988,7 +1992,7 @@ export class AgentRuntimePresenter implements IAgentImplementation {
baseSystemPrompt,
contextLength: requestModelConfig.contextLength,
requestedMaxTokens: requestPreflight.requestedMaxTokens,
tools: requestTools,
tools: effectiveRequestTools,
supportsVision,
supportsAudioInput,
interleavedReasoning,
Expand All @@ -2001,7 +2005,7 @@ export class AgentRuntimePresenter implements IAgentImplementation {
}
requestPreflight = preflightRequestContext({
messages: requestMessages,
tools: requestTools,
tools: effectiveRequestTools,
contextLength: requestModelConfig.contextLength,
requestedMaxTokens: requestMaxTokens,
minimumProtectedTailCount: protectedSteerTailCount
Expand Down Expand Up @@ -2041,7 +2045,7 @@ export class AgentRuntimePresenter implements IAgentImplementation {
requestModelConfig,
requestTemperature,
providerMaxTokens,
requestTools
effectiveRequestTools
)) {
if (!didConsumeSteerBatch && claimedSteerBatch.length > 0) {
pendingInputCoordinator.consumeClaimedSteerBatch(sessionId)
Expand Down
18 changes: 14 additions & 4 deletions src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import type { LLMCoreStreamEvent } from '@shared/types/core/llm-events'
import { mcpToolsToAISDKTools } from './toolMapper'
import { mapMessagesToModelMessages } from './messageMapper'
import { buildProviderOptions } from './providerOptionsMapper'
import { ProxyAgent } from 'undici'
import { proxyConfig } from '../../proxyConfig'
import { type AiSdkProviderKind, createAiSdkProviderContext } from './providerFactory'
import { adaptAiSdkStream } from './streamAdapter'

Expand Down Expand Up @@ -228,9 +230,11 @@ async function executeTtsPatternA(

const controller = new AbortController()
const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : undefined
const proxyUrl = proxyConfig.getProxyUrl()
const dispatcher = proxyUrl ? new ProxyAgent(proxyUrl) : undefined

try {
const response = await fetch(url, {
const fetchInit: RequestInit & { dispatcher?: ProxyAgent } = {
method: 'POST',
headers: {
...defaultHeaders,
Expand All @@ -239,7 +243,9 @@ async function executeTtsPatternA(
},
body: JSON.stringify(body),
signal: controller.signal
})
}
if (dispatcher) fetchInit.dispatcher = dispatcher
const response = await fetch(url, fetchInit)

if (!response.ok) {
const errText = await response.text().catch(() => '')
Expand Down Expand Up @@ -283,9 +289,11 @@ async function executeTtsPatternB(

const controller = new AbortController()
const timeoutId = timeout ? setTimeout(() => controller.abort(), timeout) : undefined
const proxyUrl = proxyConfig.getProxyUrl()
const dispatcher = proxyUrl ? new ProxyAgent(proxyUrl) : undefined

try {
const response = await fetch(url, {
const fetchInit: RequestInit & { dispatcher?: ProxyAgent } = {
method: 'POST',
headers: {
...defaultHeaders,
Expand All @@ -294,7 +302,9 @@ async function executeTtsPatternB(
},
body: JSON.stringify(body),
signal: controller.signal
})
}
if (dispatcher) fetchInit.dispatcher = dispatcher
const response = await fetch(url, fetchInit)

if (!response.ok) {
const errText = await response.text().catch(() => '')
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/settings/components/ProviderModelList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ const hasModelCapability = (model: RENDERER_MODEL_META, capability: ModelCapabil

const getModelTypeLabel = (type: ModelType) => {
if (type === ModelType.TTS) {
return t('settings.provider.voiceai.title')
return t('settings.provider.tts.title')
}
return t(`model.filter.typeOptions.${type}`)
}
Expand Down
36 changes: 18 additions & 18 deletions src/renderer/settings/components/VoiceAIProviderConfig.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<Icon icon="lucide:audio-waveform" class="h-5 w-5" />
</div>
<div class="space-y-1">
<p class="text-sm font-medium">{{ t('settings.provider.voiceai.title') }}</p>
<p class="text-sm font-medium">{{ t('settings.provider.tts.title') }}</p>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.description') }}
{{ t('settings.provider.tts.description') }}
</p>
</div>
</div>
Expand All @@ -18,11 +18,11 @@
<div class="grid gap-4 md:grid-cols-2">
<div class="space-y-2">
<Label :for="`${provider.id}-audio-format`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.audioFormat.label') }}
{{ t('settings.provider.tts.audioFormat.label') }}
</Label>
<Select v-model="audioFormat" :disabled="isHydrating">
<SelectTrigger :id="`${provider.id}-audio-format`">
<SelectValue :placeholder="t('settings.provider.voiceai.audioFormat.placeholder')" />
<SelectValue :placeholder="t('settings.provider.tts.audioFormat.placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem value="mp3">MP3</SelectItem>
Expand All @@ -31,17 +31,17 @@
</SelectContent>
</Select>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.audioFormat.helper') }}
{{ t('settings.provider.tts.audioFormat.helper') }}
</p>
</div>

<div class="space-y-2">
<Label :for="`${provider.id}-language`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.language.label') }}
{{ t('settings.provider.tts.language.label') }}
</Label>
<Select v-model="language" :disabled="isHydrating">
<SelectTrigger :id="`${provider.id}-language`">
<SelectValue :placeholder="t('settings.provider.voiceai.language.placeholder')" />
<SelectValue :placeholder="t('settings.provider.tts.language.placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem
Expand All @@ -54,37 +54,37 @@
</SelectContent>
</Select>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.language.helper') }}
{{ t('settings.provider.tts.language.helper') }}
</p>
</div>

<div class="space-y-2 md:col-span-2">
<Label :for="`${provider.id}-tts-model`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.model.label') }}
{{ t('settings.provider.tts.model.label') }}
</Label>
<Input
:id="`${provider.id}-tts-model`"
v-model="ttsModel"
:placeholder="t('settings.provider.voiceai.model.placeholder')"
:placeholder="t('settings.provider.tts.model.placeholder')"
:disabled="isHydrating"
/>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.model.helper') }}
{{ t('settings.provider.tts.model.helper') }}
</p>
</div>

<div class="space-y-2 md:col-span-2">
<Label :for="`${provider.id}-agent-id`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.agentId.label') }}
{{ t('settings.provider.tts.agentId.label') }}
</Label>
<Input
:id="`${provider.id}-agent-id`"
v-model="agentId"
:placeholder="t('settings.provider.voiceai.agentId.placeholder')"
:placeholder="t('settings.provider.tts.agentId.placeholder')"
:disabled="isHydrating"
/>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.agentId.helper') }}
{{ t('settings.provider.tts.agentId.helper') }}
</p>
</div>
</div>
Expand All @@ -95,7 +95,7 @@
<div class="space-y-2">
<div class="flex items-center justify-between">
<Label :for="`${provider.id}-temperature`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.temperature.label') }}
{{ t('settings.provider.tts.temperature.label') }}
</Label>
<span class="text-xs text-muted-foreground">{{ temperature.toFixed(2) }}</span>
</div>
Expand All @@ -108,14 +108,14 @@
@update:model-value="onTemperatureChange"
/>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.temperature.helper') }}
{{ t('settings.provider.tts.temperature.helper') }}
</p>
</div>

<div class="space-y-2">
<div class="flex items-center justify-between">
<Label :for="`${provider.id}-top-p`" class="text-xs font-medium">
{{ t('settings.provider.voiceai.topP.label') }}
{{ t('settings.provider.tts.topP.label') }}
</Label>
<span class="text-xs text-muted-foreground">{{ topP.toFixed(2) }}</span>
</div>
Expand All @@ -128,7 +128,7 @@
@update:model-value="onTopPChange"
/>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.topP.helper') }}
{{ t('settings.provider.tts.topP.helper') }}
</p>
</div>
</div>
Expand Down
11 changes: 0 additions & 11 deletions src/renderer/src/components/chat/ChatStatusBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,6 @@
:is-dark="themeStore.isDark"
/>
<span>{{ displayModelText }}</span>
<Icon
v-if="capabilitySupportsAudioInput === true"
icon="lucide:mic"
class="h-3 w-3 text-emerald-500"
:title="t('chat.modelPicker.audioInputSupported')"
/>
<Icon
v-if="showModelOptionsLoading"
icon="lucide:loader-2"
Expand Down Expand Up @@ -1065,7 +1059,6 @@ const numericInputErrors = ref<
})

const capabilitySupportsReasoning = ref<boolean | null>(null)
const capabilitySupportsAudioInput = ref<boolean | null>(null)
const capabilityReasoningPortrait = ref<ReasoningPortrait | null>(null)
const capabilitySupportsTemperature = ref<boolean | null>(null)
const capabilityProviderId = ref('')
Expand Down Expand Up @@ -2103,7 +2096,6 @@ const fetchCapabilities = async (providerId: string, modelId: string): Promise<v
modelId,
modelConfig.endpointType
)
capabilitySupportsAudioInput.value = capabilities.supportsAudioInput
const portrait = capabilities.reasoningPortrait ?? null

capabilityReasoningPortrait.value = portrait
Expand All @@ -2116,7 +2108,6 @@ const fetchCapabilities = async (providerId: string, modelId: string): Promise<v
} catch (error) {
console.warn('[ChatStatusBar] Failed to fetch model capabilities:', error)
capabilityProviderId.value = providerId
capabilitySupportsAudioInput.value = null
capabilitySupportsReasoning.value = null
capabilityReasoningPortrait.value = null
capabilitySupportsTemperature.value = null
Expand Down Expand Up @@ -2240,7 +2231,6 @@ const syncGenerationSettings = async () => {
localSettings.value = null
loadedSettingsSelection.value = null
capabilityProviderId.value = ''
capabilitySupportsAudioInput.value = null
capabilitySupportsReasoning.value = null
capabilityReasoningPortrait.value = null
return
Expand All @@ -2251,7 +2241,6 @@ const syncGenerationSettings = async () => {
localSettings.value = null
loadedSettingsSelection.value = null
capabilityProviderId.value = ''
capabilitySupportsAudioInput.value = null
capabilityReasoningPortrait.value = null
capabilitySupportsReasoning.value = null
return
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/src/components/settings/ModelConfigDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
{{ t('settings.model.modelConfig.type.options.imageGeneration') }}
</SelectItem>
<SelectItem value="tts">
{{ t('settings.provider.voiceai.title') }}
{{ t('settings.provider.tts.title') }}
</SelectItem>
</SelectContent>
</Select>
Expand Down Expand Up @@ -241,7 +241,7 @@
{{ t('settings.model.modelConfig.apiEndpoint.options.image') }}
</SelectItem>
<SelectItem value="audio-speech">
{{ t('settings.provider.voiceai.title') }}
{{ t('settings.provider.tts.title') }}
</SelectItem>
</SelectContent>
</Select>
Expand Down
16 changes: 8 additions & 8 deletions src/renderer/src/components/settings/TtsSettingsFields.vue
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
<template>
<div class="space-y-4">
<div class="space-y-2">
<Label>{{ t('settings.provider.voiceai.title') }}</Label>
<Label>{{ t('settings.provider.tts.title') }}</Label>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.description') }}
{{ t('settings.provider.tts.description') }}
</p>
</div>

<div class="space-y-2">
<Label>{{ t('settings.provider.voiceai.agentId.label') }}</Label>
<Label>{{ t('settings.provider.tts.agentId.label') }}</Label>
<Input
:model-value="tts.voice ?? ''"
:placeholder="t('settings.provider.voiceai.agentId.placeholder')"
:placeholder="t('settings.provider.tts.agentId.placeholder')"
@update:model-value="onVoiceInput"
/>
</div>

<div class="space-y-2">
<Label>{{ t('settings.provider.voiceai.audioFormat.label') }}</Label>
<Label>{{ t('settings.provider.tts.audioFormat.label') }}</Label>
<Select
:model-value="optionSelectValue(tts.responseFormat)"
@update:model-value="onResponseFormatSelect"
>
<SelectTrigger>
<SelectValue :placeholder="t('settings.provider.voiceai.audioFormat.placeholder')" />
<SelectValue :placeholder="t('settings.provider.tts.audioFormat.placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectItem :value="DEFAULT_SELECT_VALUE">
Expand All @@ -37,7 +37,7 @@
</div>

<div class="space-y-2">
<Label>{{ t('settings.provider.voiceai.temperature.label') }}</Label>
<Label>{{ t('settings.provider.tts.temperature.label') }}</Label>
<Input
:model-value="speedDraft"
inputmode="decimal"
Expand All @@ -47,7 +47,7 @@
@keydown.enter.prevent="commitSpeed"
/>
<p class="text-xs text-muted-foreground">
{{ t('settings.provider.voiceai.temperature.helper') }}
{{ t('settings.provider.tts.temperature.helper') }}
</p>
</div>

Expand Down
4 changes: 2 additions & 2 deletions src/renderer/src/i18n/da-DK/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -579,8 +579,8 @@
"stopModel": "Stop model",
"pulling": "Henter...",
"runModel": "Kør model",
"voiceai": {
"title": "Voice.ai tekst-til-tale",
"tts": {
"title": "Tekst-til-tale (TTS)",
"description": "Generér tale fra tekst. Stemmer vises i modellisten nedenfor.",
"audioFormat": {
"label": "Lydformat",
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/src/i18n/en-US/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -907,8 +907,8 @@
"verifyFailed": "Verification failed",
"verifySuccess": "Verification is successful"
},
"voiceai": {
"title": "Voice.ai Text-to-Speech",
"tts": {
"title": "Text-to-Speech (TTS)",
"description": "Generate speech from text. Voices appear in the model list below.",
"audioFormat": {
"label": "Audio Format",
Expand Down
Loading