@steerable/agent-shell-web 0.6.52 → 0.6.55
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/package.json +4 -4
- package/src/brand.ts +1 -1
- package/src/components/AgentSidebar.tsx +60 -52
- package/src/components/ChatHeader.tsx +41 -25
- package/src/components/ConfirmDialog.tsx +4 -3
- package/src/components/CreateProjectModal.tsx +29 -19
- package/src/components/LocalLlmSettingsModal.tsx +4 -3
- package/src/components/SidebarRelease.tsx +2 -1
- package/src/components/TerminalPanel.tsx +3 -2
- package/src/components/TerminalView.tsx +12 -7
- package/src/components/chat/ApprovalModal.tsx +39 -25
- package/src/components/chat/ApprovalPromptProvider.tsx +1 -1
- package/src/components/chat/AskUserPromptProvider.tsx +1 -1
- package/src/components/chat/AskUserQuestionMenu.tsx +19 -14
- package/src/components/chat/AssistantMessage.tsx +18 -13
- package/src/components/chat/ChatInput.tsx +138 -42
- package/src/components/chat/ChatProjectBadge.tsx +24 -19
- package/src/components/chat/EmptyChatHero.tsx +2 -1
- package/src/components/chat/ExecPolicyPicker.tsx +12 -11
- package/src/components/chat/ExecutedActionsCard.tsx +45 -33
- package/src/components/chat/FilePathCode.tsx +8 -3
- package/src/components/chat/InterruptedTurnCard.tsx +4 -3
- package/src/components/chat/LocalChatPanel.tsx +2 -1
- package/src/components/chat/Markdown.tsx +2 -1
- package/src/components/chat/MessageList.tsx +3 -2
- package/src/components/chat/ModelPicker.tsx +25 -16
- package/src/components/chat/OrchestrationChildrenCard.tsx +2 -1
- package/src/components/chat/OrchestrationFlowCard.tsx +23 -22
- package/src/components/chat/PlanTodoList.tsx +2 -1
- package/src/components/chat/ProjectTrustBanner.tsx +19 -5
- package/src/components/chat/SessionOrchestrationFlow.tsx +27 -26
- package/src/components/chat/SessionTodoList.tsx +8 -7
- package/src/components/chat/SessionTreeModal.tsx +10 -9
- package/src/components/chat/StreamingStatus.tsx +4 -3
- package/src/components/chat/SuggestedReplies.tsx +3 -2
- package/src/components/chat/TaskOutcomeCards.tsx +8 -5
- package/src/components/chat/TaskPanelModal.tsx +31 -21
- package/src/components/chat/TaskProcessPanel.tsx +14 -13
- package/src/components/chat/TurnFilesCard.tsx +14 -13
- package/src/components/chat/UserMessage.tsx +12 -11
- package/src/components/chat/executed-actions-model.ts +47 -35
- package/src/components/chat/orchestration-flow-model.ts +16 -5
- package/src/components/chat/process-status.ts +8 -7
- package/src/components/chat/todo-list-model.ts +5 -4
- package/src/components/chat/turn-files.ts +8 -8
- package/src/components/settings/AgentCapabilityFields.tsx +24 -21
- package/src/components/settings/AgentsSettingsPanel.tsx +30 -25
- package/src/components/settings/AppUpdateSettingsPanel.tsx +3 -2
- package/src/components/settings/AppearanceSettingsPanel.tsx +81 -37
- package/src/components/settings/DiagnoseSettingsPanel.tsx +11 -8
- package/src/components/settings/InsightsSettingsPanel.tsx +43 -28
- package/src/components/settings/LlmSettingsPanel.tsx +104 -83
- package/src/components/settings/McpSettingsPanel.tsx +193 -71
- package/src/components/settings/ModelIdCombobox.tsx +2 -1
- package/src/components/settings/OrchestrationSettingsPanel.tsx +8 -5
- package/src/components/settings/PortableSettingsPanel.tsx +83 -55
- package/src/components/settings/PythonRunnerSettingsPanel.tsx +22 -19
- package/src/components/settings/SecuritySettingsPanel.tsx +55 -31
- package/src/components/settings/SettingsNavMenu.tsx +3 -2
- package/src/components/settings/SettingsSaveButton.tsx +2 -1
- package/src/components/settings/SkillsSettingsPanel.tsx +36 -31
- package/src/components/settings/TelemetrySettingsPanel.tsx +15 -12
- package/src/components/settings/UsagePanel.tsx +19 -20
- package/src/components/settings/WebSearchSettingsPanel.tsx +23 -14
- package/src/components/settings/llm-vendors.ts +12 -7
- package/src/components/settings/model-capabilities.ts +16 -15
- package/src/components/settings/preset-choice-model.ts +6 -3
- package/src/fixtures/browser-dev-data.json +24 -24
- package/src/hooks/useProjects.ts +1 -1
- package/src/i18n/agent-label.ts +15 -0
- package/src/i18n/index.tsx +68 -0
- package/src/i18n/runtime.ts +117 -0
- package/src/i18n/translate.ts +65 -0
- package/src/layouts/AgentLayout.tsx +7 -6
- package/src/lib/app-release.ts +15 -10
- package/src/lib/attachments.ts +24 -7
- package/src/lib/browser-dev-electron-mock.ts +34 -34
- package/src/lib/chat-title.ts +3 -2
- package/src/lib/chat-transport.ts +6 -2
- package/src/lib/date-groups.ts +23 -15
- package/src/lib/electron-bridge.ts +19 -6
- package/src/lib/host-file-drop.ts +68 -0
- package/src/lib/host-paste.ts +38 -9
- package/src/lib/http-bridge.ts +4 -1
- package/src/lib/portable.ts +8 -7
- package/src/lib/show-thinking-content.ts +15 -3
- package/src/lib/tauri-bridge.ts +5 -0
- package/src/main.tsx +25 -2
- package/src/pages/AgentPage.tsx +17 -12
- package/src/pages/ChatPanelPreviewPage.tsx +46 -44
- package/src/pages/SettingsPage.tsx +48 -42
- package/src/vite-env.d.ts +3 -0
- package/vite.base.js +6 -2
|
@@ -32,6 +32,7 @@ import { ModelCapabilityChips } from '@/components/settings/ModelCapabilityChips
|
|
|
32
32
|
import { modelCapabilityChips } from '@/components/settings/model-capabilities';
|
|
33
33
|
import { ModelIdCombobox } from '@/components/settings/ModelIdCombobox';
|
|
34
34
|
import { SettingsSaveButton } from '@/components/settings/SettingsSaveButton';
|
|
35
|
+
import { t } from '@/i18n';
|
|
35
36
|
import { isElectron } from '@/lib/electron-bridge';
|
|
36
37
|
import {
|
|
37
38
|
COMPAT_AUTO,
|
|
@@ -124,7 +125,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
124
125
|
|
|
125
126
|
const reload = useCallback(async () => {
|
|
126
127
|
if (!isElectron()) {
|
|
127
|
-
setError('
|
|
128
|
+
setError(t('Open this in the desktop app'));
|
|
128
129
|
return;
|
|
129
130
|
}
|
|
130
131
|
setLoading(true);
|
|
@@ -136,7 +137,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
136
137
|
const { providers } = await getCatalogProviders();
|
|
137
138
|
if (providers.length > 0) nextVendors = mergeVendorOptions(providers);
|
|
138
139
|
} catch (err) {
|
|
139
|
-
console.warn('
|
|
140
|
+
console.warn('Failed to read provider catalog:', err);
|
|
140
141
|
}
|
|
141
142
|
setVendors(nextVendors);
|
|
142
143
|
const vendorId = inferVendorId(data, nextVendors);
|
|
@@ -154,7 +155,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
154
155
|
setCompatFlags(flags);
|
|
155
156
|
setCompatForm(formStateFromOverrides(data.compat, flags));
|
|
156
157
|
} catch (err) {
|
|
157
|
-
console.warn('
|
|
158
|
+
console.warn('Failed to read compat flag vocabulary:', err);
|
|
158
159
|
setCompatFlags([]);
|
|
159
160
|
setCompatForm({});
|
|
160
161
|
}
|
|
@@ -174,7 +175,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
174
175
|
setPresetPinnedIdx(-1);
|
|
175
176
|
}
|
|
176
177
|
} catch (err) {
|
|
177
|
-
console.warn('
|
|
178
|
+
console.warn('Failed to read vendor preset registry:', err);
|
|
178
179
|
setPresetList([]);
|
|
179
180
|
setPresetMode(presetModeFromChoice(data.presets));
|
|
180
181
|
}
|
|
@@ -327,7 +328,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
327
328
|
if (catalog.catalogStatus === 'offline') {
|
|
328
329
|
setKeyTest({
|
|
329
330
|
status: 'fail',
|
|
330
|
-
detail: catalog.error || '
|
|
331
|
+
detail: catalog.error || t('Gateway catalog unavailable'),
|
|
331
332
|
});
|
|
332
333
|
return;
|
|
333
334
|
}
|
|
@@ -344,7 +345,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
344
345
|
|
|
345
346
|
const handleSave = async () => {
|
|
346
347
|
if (!isElectron()) {
|
|
347
|
-
setError('
|
|
348
|
+
setError(t('Open this in the desktop app'));
|
|
348
349
|
return;
|
|
349
350
|
}
|
|
350
351
|
setSaving(true);
|
|
@@ -401,13 +402,13 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
401
402
|
{loading ? (
|
|
402
403
|
<div className="flex items-center gap-2 py-2 text-xs text-agent-muted-foreground">
|
|
403
404
|
<LuLoaderCircle className="h-4 w-4 animate-spin" />
|
|
404
|
-
|
|
405
|
+
{t('Loading current settings...')}
|
|
405
406
|
</div>
|
|
406
407
|
) : (
|
|
407
408
|
<>
|
|
408
409
|
<div>
|
|
409
410
|
<label className="mb-1.5 block text-xs font-medium text-agent-muted-foreground">
|
|
410
|
-
|
|
411
|
+
{t('Provider')}
|
|
411
412
|
</label>
|
|
412
413
|
<select
|
|
413
414
|
data-testid="llm-vendor-select"
|
|
@@ -416,7 +417,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
416
417
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-2 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
417
418
|
>
|
|
418
419
|
{featuredVendors.length > 0 && (
|
|
419
|
-
<optgroup label=
|
|
420
|
+
<optgroup label={t('Common')}>
|
|
420
421
|
{featuredVendors.map((v) => (
|
|
421
422
|
<option key={v.id} value={v.id}>
|
|
422
423
|
{v.label}
|
|
@@ -425,7 +426,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
425
426
|
</optgroup>
|
|
426
427
|
)}
|
|
427
428
|
{otherVendors.length > 0 && (
|
|
428
|
-
<optgroup label=
|
|
429
|
+
<optgroup label={t('All')}>
|
|
429
430
|
{otherVendors.map((v) => (
|
|
430
431
|
<option key={v.id} value={v.id}>
|
|
431
432
|
{v.label}
|
|
@@ -436,16 +437,16 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
436
437
|
</select>
|
|
437
438
|
<p className="mt-1.5 text-[11px] text-agent-muted-foreground">
|
|
438
439
|
{selectedVendor?.id === 'ollama'
|
|
439
|
-
? '
|
|
440
|
+
? t('Make sure `ollama serve` is running on this computer and you have run `ollama pull <model>`.')
|
|
440
441
|
: selectedVendor?.id === 'custom'
|
|
441
|
-
? '
|
|
442
|
+
? t('Any gateway compatible with OpenAI Chat Completions. For Anthropic / Gemini, pick the matching provider from the list above.')
|
|
442
443
|
: selectedVendor?.wireKind === 'anthropic'
|
|
443
|
-
? '
|
|
444
|
+
? t('Uses the native Anthropic Messages protocol.')
|
|
444
445
|
: selectedVendor?.wireKind === 'google'
|
|
445
|
-
? '
|
|
446
|
+
? t('Uses the native Google Gemini protocol.')
|
|
446
447
|
: selectedVendor?.wireKind === 'openai-responses'
|
|
447
|
-
? '
|
|
448
|
-
: '
|
|
448
|
+
? t('Uses the OpenAI Responses API (e.g. xAI Grok).')
|
|
449
|
+
: t('A cloud or local gateway compatible with OpenAI Chat Completions.')}
|
|
449
450
|
</p>
|
|
450
451
|
</div>
|
|
451
452
|
|
|
@@ -463,14 +464,14 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
463
464
|
selectedVendor?.apiBaseUrl ||
|
|
464
465
|
(selectedVendor?.id === 'custom'
|
|
465
466
|
? 'https://your-gateway.example/v1'
|
|
466
|
-
: '
|
|
467
|
+
: t('This provider has no default URL. Enter it manually.'))
|
|
467
468
|
}
|
|
468
469
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-3 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
469
470
|
/>
|
|
470
471
|
<p className="mt-1.5 text-[11px] text-agent-muted-foreground">
|
|
471
472
|
{selectedVendor?.apiBaseUrl
|
|
472
|
-
? '
|
|
473
|
-
: '
|
|
473
|
+
? t('The provider default URL is filled in. Change it for a private deployment.')
|
|
474
|
+
: t('The catalog has no default URL. Enter it manually.')}
|
|
474
475
|
</p>
|
|
475
476
|
</div>
|
|
476
477
|
|
|
@@ -488,15 +489,15 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
488
489
|
}
|
|
489
490
|
placeholder={
|
|
490
491
|
selectedVendor?.id === 'custom'
|
|
491
|
-
? 'sk-... (
|
|
492
|
-
: 'sk-... (
|
|
492
|
+
? t('sk-... (optional, can be blank for a private deployment)')
|
|
493
|
+
: t('sk-... (required, create one in the provider console)')
|
|
493
494
|
}
|
|
494
495
|
className="h-8 min-w-0 flex-1 rounded-agent-md border border-agent-border bg-agent-canvas px-3 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
495
496
|
/>
|
|
496
497
|
<button
|
|
497
498
|
type="button"
|
|
498
499
|
data-testid="llm-key-test"
|
|
499
|
-
title=
|
|
500
|
+
title={t('Fetch the model catalog from the gateway once with the current URL and key')}
|
|
500
501
|
disabled={!settings.baseUrl?.trim() || keyTest.status === 'testing'}
|
|
501
502
|
onClick={() => void handleTestKey()}
|
|
502
503
|
className="inline-flex h-8 shrink-0 items-center justify-center rounded-agent-md border border-agent-border bg-agent-canvas px-3 text-xs font-medium text-agent-foreground transition-colors hover:bg-agent-foreground/5 disabled:cursor-not-allowed disabled:opacity-50"
|
|
@@ -504,7 +505,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
504
505
|
{keyTest.status === 'testing' ? (
|
|
505
506
|
<LuLoaderCircle className="h-4 w-4 animate-spin" />
|
|
506
507
|
) : (
|
|
507
|
-
'
|
|
508
|
+
t('Test')
|
|
508
509
|
)}
|
|
509
510
|
</button>
|
|
510
511
|
</div>
|
|
@@ -519,36 +520,40 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
519
520
|
].join(' ')}
|
|
520
521
|
>
|
|
521
522
|
{keyTest.status === 'testing'
|
|
522
|
-
? '
|
|
523
|
+
? t('Verifying credentials…')
|
|
523
524
|
: keyTest.status === 'ok'
|
|
524
|
-
?
|
|
525
|
+
? t('Credentials work. The gateway returned {count} models.', { count: keyTest.count })
|
|
525
526
|
: keyTest.status === 'fail'
|
|
526
|
-
?
|
|
527
|
+
? t('Verification failed: {detail}', { detail: keyTest.detail })
|
|
527
528
|
: !settings.apiKey?.trim()
|
|
528
|
-
?
|
|
529
|
-
|
|
529
|
+
? t(
|
|
530
|
+
'No API key yet: create a key in the provider console (DeepSeek: platform.deepseek.com → API Keys), paste it in the box above, click "Test", and save once it passes.',
|
|
531
|
+
)
|
|
532
|
+
: t(
|
|
533
|
+
'Web search is configured on the settings page: choose free search or a Tavily key. OpenAI can use this chat key for hosted search.',
|
|
534
|
+
)}
|
|
530
535
|
</p>
|
|
531
536
|
</div>
|
|
532
537
|
)}
|
|
533
538
|
|
|
534
539
|
<div>
|
|
535
540
|
<label className="mb-1.5 block text-xs font-medium text-agent-muted-foreground">
|
|
536
|
-
|
|
541
|
+
{t('Model')}
|
|
537
542
|
</label>
|
|
538
543
|
<div className="flex items-center gap-2">
|
|
539
544
|
<div className="min-w-0 flex-1">
|
|
540
545
|
<ModelIdCombobox
|
|
541
546
|
value={settings.model}
|
|
542
547
|
options={modelOptions}
|
|
543
|
-
placeholder={liveEntries[0]?.id || catalogModels[0] || '
|
|
548
|
+
placeholder={liveEntries[0]?.id || catalogModels[0] || t('Choose or enter a model id')}
|
|
544
549
|
onChange={(model) => setSettings((prev) => ({ ...prev, model }))}
|
|
545
550
|
/>
|
|
546
551
|
</div>
|
|
547
552
|
<button
|
|
548
553
|
type="button"
|
|
549
554
|
data-testid="llm-model-refresh"
|
|
550
|
-
title=
|
|
551
|
-
aria-label=
|
|
555
|
+
title={t('Fetch the model list from the gateway again')}
|
|
556
|
+
aria-label={t('Refresh model catalog')}
|
|
552
557
|
disabled={!settings.baseUrl?.trim() || modelsRefreshing}
|
|
553
558
|
onClick={() => void handleRefreshModels()}
|
|
554
559
|
className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-agent-md border border-agent-border bg-agent-canvas text-agent-muted-foreground transition-colors hover:bg-agent-foreground/5 hover:text-agent-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
|
@@ -561,30 +566,32 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
561
566
|
data-testid="llm-model-capabilities"
|
|
562
567
|
className="mt-1.5 flex flex-wrap items-center gap-1.5 text-[11px] text-agent-muted-foreground"
|
|
563
568
|
>
|
|
564
|
-
<span
|
|
569
|
+
<span>{t('Current')}</span>
|
|
565
570
|
{selectedEntry ? (
|
|
566
571
|
selectedKnownEmpty ? (
|
|
567
|
-
<span
|
|
572
|
+
<span>{t('Text chat')}</span>
|
|
568
573
|
) : (
|
|
569
574
|
<ModelCapabilityChips entry={selectedEntry} detail />
|
|
570
575
|
)
|
|
571
576
|
) : (
|
|
572
|
-
<span
|
|
577
|
+
<span>{t('Capabilities unrecognized (not in the gateway catalog)')}</span>
|
|
573
578
|
)}
|
|
574
579
|
</div>
|
|
575
580
|
)}
|
|
576
581
|
<p className="mt-1.5 text-[11px] text-agent-muted-foreground">
|
|
577
582
|
{liveCatalogStatus === 'live'
|
|
578
|
-
?
|
|
583
|
+
? t('Fetched {count} models from the gateway. You can also type one in.', {
|
|
584
|
+
count: liveEntries.length,
|
|
585
|
+
})
|
|
579
586
|
: liveCatalogStatus === 'stale'
|
|
580
|
-
? '
|
|
587
|
+
? t('Failed to refresh the gateway catalog. Using the last cached copy; you can also type one in.')
|
|
581
588
|
: liveCatalogStatus === 'idle' && (settings.baseUrl || '').trim()
|
|
582
|
-
? '
|
|
589
|
+
? t('Fetching the model catalog from the gateway…')
|
|
583
590
|
: liveCatalogStatus === 'idle'
|
|
584
|
-
? '
|
|
591
|
+
? t('Enter a Base URL to fetch the gateway model catalog, or type a model in.')
|
|
585
592
|
: catalogModels.length > 0
|
|
586
|
-
? '
|
|
587
|
-
: '
|
|
593
|
+
? t('Gateway catalog unavailable. Using the provider built-in list for now; you can also type one in.')
|
|
594
|
+
: t('Gateway catalog unavailable. Enter the model id directly.')}
|
|
588
595
|
</p>
|
|
589
596
|
</div>
|
|
590
597
|
|
|
@@ -592,19 +599,23 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
592
599
|
<div className="rounded-agent-md border border-agent-border/60 p-3 space-y-3">
|
|
593
600
|
<div>
|
|
594
601
|
<h4 className="text-xs font-semibold text-agent-muted-foreground uppercase tracking-wide">
|
|
595
|
-
|
|
602
|
+
{t('Vendor parameter presets')}
|
|
596
603
|
</h4>
|
|
597
604
|
<p className="mt-1 text-[11px] text-agent-muted-foreground">
|
|
598
|
-
|
|
599
|
-
|
|
605
|
+
{t(
|
|
606
|
+
'Fill requests automatically with the best sampling parameters from vendor docs (temperature / top_p / top_k, etc.).',
|
|
607
|
+
)}{' '}
|
|
608
|
+
{t(
|
|
609
|
+
'"Auto" matches the built-in registry by Base URL + model name. Explicit manual settings such as Temperature always take precedence over presets.',
|
|
610
|
+
)}
|
|
600
611
|
</p>
|
|
601
612
|
</div>
|
|
602
613
|
<div className="flex gap-1.5">
|
|
603
614
|
{(
|
|
604
615
|
[
|
|
605
|
-
{ value: 'auto', label: '
|
|
606
|
-
{ value: 'off', label: '
|
|
607
|
-
{ value: 'pinned', label: '
|
|
616
|
+
{ value: 'auto', label: 'Auto (recommended)' },
|
|
617
|
+
{ value: 'off', label: 'Off' },
|
|
618
|
+
{ value: 'pinned', label: 'Pick a preset' },
|
|
608
619
|
] as { value: PresetMode; label: string }[]
|
|
609
620
|
).map((opt) => (
|
|
610
621
|
<button
|
|
@@ -618,7 +629,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
618
629
|
: 'bg-agent-muted text-agent-muted-foreground hover:text-agent-foreground'
|
|
619
630
|
}`}
|
|
620
631
|
>
|
|
621
|
-
{opt.label}
|
|
632
|
+
{t(opt.label)}
|
|
622
633
|
</button>
|
|
623
634
|
))}
|
|
624
635
|
</div>
|
|
@@ -631,7 +642,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
631
642
|
>
|
|
632
643
|
{presetPinnedIdx === -1 && (
|
|
633
644
|
<option value={-1}>
|
|
634
|
-
{settings.presets?.override ? '
|
|
645
|
+
{settings.presets?.override ? t('Custom (saved override)') : t('Select…')}
|
|
635
646
|
</option>
|
|
636
647
|
)}
|
|
637
648
|
{presetList.map((d, i) => (
|
|
@@ -642,21 +653,23 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
642
653
|
</select>
|
|
643
654
|
) : (
|
|
644
655
|
<p className="text-[11px] text-agent-muted-foreground">
|
|
645
|
-
|
|
656
|
+
{t('The preset registry comes from the sidecar. Nothing is available while the sidecar is not ready.')}
|
|
646
657
|
</p>
|
|
647
658
|
))}
|
|
648
659
|
<p className="text-[11px] text-agent-muted-foreground/80" data-preset-preview>
|
|
649
660
|
{presetMode === 'off'
|
|
650
|
-
? '
|
|
661
|
+
? t('Off: vendor preset parameters are not sent.')
|
|
651
662
|
: presetMode === 'pinned'
|
|
652
|
-
?
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
663
|
+
? t('Effective parameters: {summary}', {
|
|
664
|
+
summary: summarizePreset(
|
|
665
|
+
presetPinnedIdx >= 0 && presetList[presetPinnedIdx]
|
|
666
|
+
? overrideFromDescriptor(presetList[presetPinnedIdx])
|
|
667
|
+
: (settings.presets?.override ?? null),
|
|
668
|
+
),
|
|
669
|
+
})
|
|
657
670
|
: resolvedPreset
|
|
658
|
-
?
|
|
659
|
-
: '
|
|
671
|
+
? t('Matched preset: {summary}', { summary: summarizePreset(resolvedPreset) })
|
|
672
|
+
: t('The current Base URL + model match no preset. No extra sampling parameters are sent.')}
|
|
660
673
|
</p>
|
|
661
674
|
</div>
|
|
662
675
|
)}
|
|
@@ -665,17 +678,17 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
665
678
|
<div className="rounded-agent-md border border-agent-border/60 p-3 space-y-3">
|
|
666
679
|
<div>
|
|
667
680
|
<h4 className="text-xs font-semibold text-agent-muted-foreground uppercase tracking-wide">
|
|
668
|
-
|
|
681
|
+
{t('Advanced compatibility flags (optional)')}
|
|
669
682
|
</h4>
|
|
670
683
|
<p className="mt-1 text-[11px] text-agent-muted-foreground">
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
684
|
+
{t(
|
|
685
|
+
'Change these only when the vendor gateway differs from the OpenAI protocol and auto-detection does not cover it. "Auto" = the framework matches known vendors by Base URL host name (DeepSeek / Moonshot / OpenRouter / DashScope) and falls back to OpenAI reference behavior otherwise.',
|
|
686
|
+
)}
|
|
674
687
|
</p>
|
|
675
688
|
</div>
|
|
676
689
|
{compatFlags.length === 0 ? (
|
|
677
690
|
<p className="text-[11px] text-agent-muted-foreground">
|
|
678
|
-
|
|
691
|
+
{t('The flag vocabulary comes from the sidecar. This stays empty while the sidecar is not ready; saving is not affected.')}
|
|
679
692
|
</p>
|
|
680
693
|
) : (
|
|
681
694
|
compatFlags.map((flag) => (
|
|
@@ -686,9 +699,9 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
686
699
|
{flag.kind === 'bool' ? (
|
|
687
700
|
<div className="flex gap-1.5">
|
|
688
701
|
{[
|
|
689
|
-
{ value: COMPAT_AUTO, label: '
|
|
690
|
-
{ value: 'true', label: '
|
|
691
|
-
{ value: 'false', label: '
|
|
702
|
+
{ value: COMPAT_AUTO, label: 'Auto' },
|
|
703
|
+
{ value: 'true', label: 'Yes' },
|
|
704
|
+
{ value: 'false', label: 'No' },
|
|
692
705
|
].map((opt) => (
|
|
693
706
|
<button
|
|
694
707
|
key={opt.value}
|
|
@@ -702,7 +715,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
702
715
|
: 'bg-agent-muted text-agent-muted-foreground hover:text-agent-foreground'
|
|
703
716
|
}`}
|
|
704
717
|
>
|
|
705
|
-
{opt.label}
|
|
718
|
+
{t(opt.label)}
|
|
706
719
|
</button>
|
|
707
720
|
))}
|
|
708
721
|
</div>
|
|
@@ -714,7 +727,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
714
727
|
}
|
|
715
728
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-2 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
716
729
|
>
|
|
717
|
-
<option value={COMPAT_AUTO}
|
|
730
|
+
<option value={COMPAT_AUTO}>{t('Auto')}</option>
|
|
718
731
|
{flag.kind
|
|
719
732
|
.slice('enum:'.length)
|
|
720
733
|
.split(',')
|
|
@@ -734,7 +747,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
734
747
|
[flag.key]: e.target.value || COMPAT_AUTO,
|
|
735
748
|
}))
|
|
736
749
|
}
|
|
737
|
-
placeholder=
|
|
750
|
+
placeholder={t('Comma-separated; blank = auto')}
|
|
738
751
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-2 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
739
752
|
/>
|
|
740
753
|
)}
|
|
@@ -756,8 +769,8 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
756
769
|
<div className="flex gap-1">
|
|
757
770
|
{(
|
|
758
771
|
[
|
|
759
|
-
{ value: 'auto', label: '
|
|
760
|
-
{ value: 'manual', label: '
|
|
772
|
+
{ value: 'auto', label: 'Auto' },
|
|
773
|
+
{ value: 'manual', label: 'Manual' },
|
|
761
774
|
] as const
|
|
762
775
|
).map((opt) => (
|
|
763
776
|
<button
|
|
@@ -779,18 +792,22 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
779
792
|
: 'bg-agent-muted text-agent-muted-foreground hover:text-agent-foreground'
|
|
780
793
|
}`}
|
|
781
794
|
>
|
|
782
|
-
{opt.label}
|
|
795
|
+
{t(opt.label)}
|
|
783
796
|
</button>
|
|
784
797
|
))}
|
|
785
798
|
</div>
|
|
786
799
|
</div>
|
|
787
800
|
{settings.temperature === undefined ? (
|
|
788
801
|
<p className="text-[11px] text-agent-muted-foreground">
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
802
|
+
{t(
|
|
803
|
+
'Auto: uses the preset temperature when a vendor preset matches{match}. Otherwise nothing is sent (the vendor server default applies). An explicit manual value takes precedence over the preset.',
|
|
804
|
+
{
|
|
805
|
+
match:
|
|
806
|
+
presetMode === 'auto' && resolvedPreset?.temperature != null
|
|
807
|
+
? t(' (current match: {value})', { value: resolvedPreset.temperature })
|
|
808
|
+
: '',
|
|
809
|
+
},
|
|
810
|
+
)}
|
|
794
811
|
</p>
|
|
795
812
|
) : (
|
|
796
813
|
<input
|
|
@@ -809,7 +826,7 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
809
826
|
|
|
810
827
|
<div>
|
|
811
828
|
<label className="mb-1.5 block text-xs font-medium text-agent-muted-foreground">
|
|
812
|
-
|
|
829
|
+
{t('Token budget limit')}
|
|
813
830
|
</label>
|
|
814
831
|
<input
|
|
815
832
|
type="number"
|
|
@@ -822,30 +839,34 @@ export const LlmSettingsPanel = forwardRef<LlmSettingsPanelHandle, LlmSettingsPa
|
|
|
822
839
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-3 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
823
840
|
/>
|
|
824
841
|
<p className="mt-1.5 text-[11px] text-agent-muted-foreground">
|
|
825
|
-
|
|
842
|
+
{t(
|
|
843
|
+
'Maximum tokens a single conversation may consume in total (default 60,000). It stops automatically when the limit is exceeded, to prevent endless model loops or unexpected token usage.',
|
|
844
|
+
)}
|
|
826
845
|
</p>
|
|
827
846
|
</div>
|
|
828
847
|
|
|
829
848
|
{/* ───── 超时设置 ───── */}
|
|
830
849
|
<div className="border-t border-agent-border/60 pt-3 space-y-3">
|
|
831
850
|
<h4 className="text-xs font-semibold text-agent-muted-foreground uppercase tracking-wide">
|
|
832
|
-
|
|
851
|
+
{t('Timeouts')}
|
|
833
852
|
</h4>
|
|
834
853
|
|
|
835
854
|
<div>
|
|
836
855
|
<label className="mb-1.5 block text-xs font-medium text-agent-muted-foreground">
|
|
837
|
-
|
|
856
|
+
{t('Default local command timeout (seconds)')}
|
|
838
857
|
</label>
|
|
839
858
|
<input
|
|
840
859
|
type="number"
|
|
841
860
|
min={1}
|
|
842
861
|
value={execTimeoutInput}
|
|
843
862
|
onChange={(e) => setExecTimeoutInput(e.target.value)}
|
|
844
|
-
placeholder=
|
|
863
|
+
placeholder={t('Blank = default (background 30s / terminal 60s)')}
|
|
845
864
|
className="h-8 w-full rounded-agent-md border border-agent-border bg-agent-canvas px-3 text-xs text-agent-foreground focus:outline-none focus:ring-2 focus:ring-agent-foreground/30"
|
|
846
865
|
/>
|
|
847
866
|
<p className="mt-1.5 text-[11px] text-agent-muted-foreground">
|
|
848
|
-
|
|
867
|
+
{t(
|
|
868
|
+
'Default wait time for local commands that do not set a timeout explicitly. Launch commands containing "gui" are exempt: on timeout they are treated as "program started and still running", not as a failure or a repeated launch.',
|
|
869
|
+
)}
|
|
849
870
|
</p>
|
|
850
871
|
</div>
|
|
851
872
|
|