@cat-factory/app 0.47.0 → 0.47.2
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/app/components/providers/AiPresetMismatchDialog.vue +26 -13
- package/app/components/providers/AiProviderOnboardingModal.vue +18 -15
- package/app/components/providers/ApiKeysSection.vue +81 -63
- package/app/components/providers/PersonalCredentialModal.vue +35 -29
- package/app/components/providers/PersonalSubscriptionSection.vue +10 -0
- package/app/components/providers/VendorCredentialsModal.vue +82 -39
- package/i18n/locales/en.json +167 -0
- package/i18n/locales/es.json +161 -0
- package/i18n/locales/fr.json +161 -0
- package/i18n/locales/pl.json +161 -0
- package/i18n/locales/uk.json +161 -0
- package/package.json +1 -1
|
@@ -9,6 +9,7 @@ import { computed, ref, watch } from 'vue'
|
|
|
9
9
|
import type { SubscriptionVendor } from '~/types/domain'
|
|
10
10
|
import IntegrationBackTitle from '~/components/layout/IntegrationBackTitle.vue'
|
|
11
11
|
|
|
12
|
+
const { t, n } = useI18n()
|
|
12
13
|
const ui = useUiStore()
|
|
13
14
|
const workspace = useWorkspaceStore()
|
|
14
15
|
const creds = useVendorCredentialsStore()
|
|
@@ -25,27 +26,51 @@ const back = useIntegrationBack(open)
|
|
|
25
26
|
// Initialised from the ui store so a caller can deep-link to a tab — the user-scoped
|
|
26
27
|
// "My subscriptions" entry opens straight onto the `personal` tab.
|
|
27
28
|
const activeTab = ref(ui.vendorCredentialsTab)
|
|
28
|
-
const tabs = [
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
const tabs = computed(() => [
|
|
30
|
+
{
|
|
31
|
+
value: 'pool',
|
|
32
|
+
label: t('providers.vendorCredentials.tabs.pool'),
|
|
33
|
+
icon: 'i-lucide-users',
|
|
34
|
+
slot: 'pool',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
value: 'direct',
|
|
38
|
+
label: t('providers.vendorCredentials.tabs.direct'),
|
|
39
|
+
icon: 'i-lucide-key-round',
|
|
40
|
+
slot: 'direct',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
value: 'proxy',
|
|
44
|
+
label: t('providers.vendorCredentials.tabs.proxy'),
|
|
45
|
+
icon: 'i-lucide-route',
|
|
46
|
+
slot: 'proxy',
|
|
47
|
+
},
|
|
32
48
|
{
|
|
33
49
|
value: 'personal',
|
|
34
|
-
label: '
|
|
50
|
+
label: t('providers.vendorCredentials.tabs.personal'),
|
|
35
51
|
icon: 'i-lucide-user',
|
|
36
52
|
slot: 'personal',
|
|
37
53
|
},
|
|
38
|
-
]
|
|
54
|
+
])
|
|
39
55
|
|
|
40
56
|
// Only commercial coding-plan vendors that permit team/organization use are poolable here.
|
|
41
57
|
// Claude, GLM and ChatGPT/Codex are licensed for individual use only, so they are connected
|
|
42
58
|
// per-user in the "Personal subscriptions" section below (PersonalSubscriptionSection).
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
59
|
+
// Labels resolve through i18n (reactive to the locale) via literal keys.
|
|
60
|
+
const VENDORS = computed<{ value: SubscriptionVendor; label: string; harness: string }[]>(() => [
|
|
61
|
+
{
|
|
62
|
+
value: 'kimi',
|
|
63
|
+
label: t('providers.vendorCredentials.vendors.kimi.label'),
|
|
64
|
+
harness: 'Claude Code',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
value: 'deepseek',
|
|
68
|
+
label: t('providers.vendorCredentials.vendors.deepseek.label'),
|
|
69
|
+
harness: 'Claude Code',
|
|
70
|
+
},
|
|
71
|
+
])
|
|
47
72
|
|
|
48
|
-
const visibleVendors = computed(() => VENDORS)
|
|
73
|
+
const visibleVendors = computed(() => VENDORS.value)
|
|
49
74
|
|
|
50
75
|
const vendor = ref<SubscriptionVendor>('kimi')
|
|
51
76
|
const label = ref('')
|
|
@@ -68,22 +93,22 @@ const steps = computed<string[]>(() => {
|
|
|
68
93
|
switch (vendor.value) {
|
|
69
94
|
case 'kimi':
|
|
70
95
|
return [
|
|
71
|
-
'
|
|
72
|
-
'
|
|
73
|
-
'
|
|
96
|
+
t('providers.vendorCredentials.vendors.kimi.step1'),
|
|
97
|
+
t('providers.vendorCredentials.vendors.kimi.step2'),
|
|
98
|
+
t('providers.vendorCredentials.vendors.kimi.step3'),
|
|
74
99
|
]
|
|
75
100
|
case 'deepseek':
|
|
76
101
|
return [
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
'
|
|
102
|
+
t('providers.vendorCredentials.vendors.deepseek.step1'),
|
|
103
|
+
t('providers.vendorCredentials.vendors.deepseek.step2'),
|
|
104
|
+
t('providers.vendorCredentials.vendors.deepseek.step3'),
|
|
80
105
|
]
|
|
81
106
|
default:
|
|
82
107
|
return []
|
|
83
108
|
}
|
|
84
109
|
})
|
|
85
110
|
|
|
86
|
-
const tokenPlaceholder = computed(() => '
|
|
111
|
+
const tokenPlaceholder = computed(() => t('providers.vendorCredentials.tokenPlaceholder'))
|
|
87
112
|
|
|
88
113
|
async function add() {
|
|
89
114
|
if (!token.value.trim()) return
|
|
@@ -91,15 +116,21 @@ async function add() {
|
|
|
91
116
|
try {
|
|
92
117
|
await creds.add({
|
|
93
118
|
vendor: vendor.value,
|
|
94
|
-
label:
|
|
119
|
+
label:
|
|
120
|
+
label.value.trim() ||
|
|
121
|
+
t('providers.vendorCredentials.defaultLabel', { vendor: vendor.value }),
|
|
95
122
|
token: token.value.trim(),
|
|
96
123
|
})
|
|
97
124
|
token.value = ''
|
|
98
125
|
label.value = ''
|
|
99
|
-
toast.add({
|
|
126
|
+
toast.add({
|
|
127
|
+
title: t('providers.vendorCredentials.toast.connected'),
|
|
128
|
+
icon: 'i-lucide-check',
|
|
129
|
+
color: 'success',
|
|
130
|
+
})
|
|
100
131
|
} catch (e) {
|
|
101
132
|
toast.add({
|
|
102
|
-
title: '
|
|
133
|
+
title: t('providers.vendorCredentials.toast.connectFailed'),
|
|
103
134
|
description: e instanceof Error ? e.message : String(e),
|
|
104
135
|
color: 'error',
|
|
105
136
|
})
|
|
@@ -113,7 +144,7 @@ async function remove(id: string) {
|
|
|
113
144
|
await creds.remove(id)
|
|
114
145
|
} catch (e) {
|
|
115
146
|
toast.add({
|
|
116
|
-
title: '
|
|
147
|
+
title: t('providers.vendorCredentials.toast.removeFailed'),
|
|
117
148
|
description: e instanceof Error ? e.message : String(e),
|
|
118
149
|
color: 'error',
|
|
119
150
|
})
|
|
@@ -121,14 +152,18 @@ async function remove(id: string) {
|
|
|
121
152
|
}
|
|
122
153
|
|
|
123
154
|
function vendorLabel(v: SubscriptionVendor): string {
|
|
124
|
-
return VENDORS.find((x) => x.value === v)?.label ?? v
|
|
155
|
+
return VENDORS.value.find((x) => x.value === v)?.label ?? v
|
|
125
156
|
}
|
|
126
157
|
</script>
|
|
127
158
|
|
|
128
159
|
<template>
|
|
129
|
-
<UModal
|
|
160
|
+
<UModal
|
|
161
|
+
v-model:open="open"
|
|
162
|
+
:title="t('providers.vendorCredentials.title')"
|
|
163
|
+
:ui="{ content: 'max-w-2xl' }"
|
|
164
|
+
>
|
|
130
165
|
<template #title>
|
|
131
|
-
<IntegrationBackTitle title="
|
|
166
|
+
<IntegrationBackTitle :title="t('providers.vendorCredentials.title')" @back="back" />
|
|
132
167
|
</template>
|
|
133
168
|
<template #body>
|
|
134
169
|
<UTabs
|
|
@@ -141,17 +176,12 @@ function vendorLabel(v: SubscriptionVendor): string {
|
|
|
141
176
|
<template #pool>
|
|
142
177
|
<div class="space-y-5">
|
|
143
178
|
<p class="text-sm text-slate-400">
|
|
144
|
-
|
|
145
|
-
permits team/organization use to run agent steps on the Claude Code harness instead of
|
|
146
|
-
an API key. Tokens are stored encrypted, pooled, and rotated by usage. Subscription
|
|
147
|
-
models are flat-rate quota — they don’t draw on your spend budget. Individual-use
|
|
148
|
-
subscriptions (Claude, GLM, ChatGPT/Codex) are connected per-user in the Personal
|
|
149
|
-
subscriptions tab.
|
|
179
|
+
{{ t('providers.vendorCredentials.poolIntro') }}
|
|
150
180
|
</p>
|
|
151
181
|
|
|
152
182
|
<!-- vendor picker -->
|
|
153
183
|
<div class="flex flex-wrap items-end gap-3">
|
|
154
|
-
<UFormField label="
|
|
184
|
+
<UFormField :label="t('providers.vendorCredentials.vendorField')">
|
|
155
185
|
<USelect
|
|
156
186
|
v-model="vendor"
|
|
157
187
|
:items="visibleVendors.map((v) => ({ label: v.label, value: v.value }))"
|
|
@@ -169,10 +199,13 @@ function vendorLabel(v: SubscriptionVendor): string {
|
|
|
169
199
|
|
|
170
200
|
<!-- add form -->
|
|
171
201
|
<div class="space-y-2">
|
|
172
|
-
<UFormField label="
|
|
173
|
-
<UInput
|
|
202
|
+
<UFormField :label="t('providers.vendorCredentials.labelField')">
|
|
203
|
+
<UInput
|
|
204
|
+
v-model="label"
|
|
205
|
+
:placeholder="t('providers.vendorCredentials.labelPlaceholder')"
|
|
206
|
+
/>
|
|
174
207
|
</UFormField>
|
|
175
|
-
<UFormField label="
|
|
208
|
+
<UFormField :label="t('providers.vendorCredentials.tokenField')">
|
|
176
209
|
<UTextarea
|
|
177
210
|
v-model="token"
|
|
178
211
|
:rows="3"
|
|
@@ -187,7 +220,7 @@ function vendorLabel(v: SubscriptionVendor): string {
|
|
|
187
220
|
icon="i-lucide-plus"
|
|
188
221
|
@click="add()"
|
|
189
222
|
>
|
|
190
|
-
|
|
223
|
+
{{ t('providers.vendorCredentials.connect') }}
|
|
191
224
|
</UButton>
|
|
192
225
|
</div>
|
|
193
226
|
</div>
|
|
@@ -195,7 +228,9 @@ function vendorLabel(v: SubscriptionVendor): string {
|
|
|
195
228
|
<!-- connected pool -->
|
|
196
229
|
<div v-if="creds.credentials.length" class="space-y-2">
|
|
197
230
|
<h4 class="text-xs font-semibold uppercase tracking-wide text-slate-500">
|
|
198
|
-
|
|
231
|
+
{{
|
|
232
|
+
t('providers.vendorCredentials.connected', { count: creds.credentials.length })
|
|
233
|
+
}}
|
|
199
234
|
</h4>
|
|
200
235
|
<div
|
|
201
236
|
v-for="c in creds.credentials"
|
|
@@ -206,8 +241,16 @@ function vendorLabel(v: SubscriptionVendor): string {
|
|
|
206
241
|
<span class="font-medium text-slate-200">{{ c.label }}</span>
|
|
207
242
|
<span class="ml-2 text-xs text-slate-500">{{ vendorLabel(c.vendor) }}</span>
|
|
208
243
|
<div class="text-[11px] tabular-nums text-slate-500">
|
|
209
|
-
{{
|
|
210
|
-
|
|
244
|
+
{{
|
|
245
|
+
t(
|
|
246
|
+
'providers.vendorCredentials.usage',
|
|
247
|
+
{
|
|
248
|
+
tokens: n(c.inputTokens + c.outputTokens, 'decimal'),
|
|
249
|
+
count: c.requestCount,
|
|
250
|
+
},
|
|
251
|
+
c.requestCount,
|
|
252
|
+
)
|
|
253
|
+
}}
|
|
211
254
|
</div>
|
|
212
255
|
</div>
|
|
213
256
|
<UButton
|
package/i18n/locales/en.json
CHANGED
|
@@ -1654,5 +1654,172 @@
|
|
|
1654
1654
|
"removeFailed": "Could not remove runner"
|
|
1655
1655
|
}
|
|
1656
1656
|
}
|
|
1657
|
+
},
|
|
1658
|
+
"providers": {
|
|
1659
|
+
"presetMismatch": {
|
|
1660
|
+
"title": "Preset uses unavailable models",
|
|
1661
|
+
"intro": "The workspace default model preset \"{name}\" assigns models that aren't available under the current configuration. Tasks that use this preset would fail when they reach those steps.",
|
|
1662
|
+
"unavailable": "Unavailable",
|
|
1663
|
+
"advice": "Either repoint the preset at models you have configured, or add the missing provider.",
|
|
1664
|
+
"later": "Later",
|
|
1665
|
+
"configureVendors": "Configure vendors",
|
|
1666
|
+
"editPresets": "Edit presets",
|
|
1667
|
+
"defaultPresetName": "default preset"
|
|
1668
|
+
},
|
|
1669
|
+
"onboarding": {
|
|
1670
|
+
"title": "Set up an AI model provider",
|
|
1671
|
+
"noModelTitle": "No AI model is available on this workspace yet.",
|
|
1672
|
+
"noModelBody": "Agents need a model to run. AI works out of the box only on a Cloudflare deployment with Workers AI enabled; otherwise connect at least one source below.",
|
|
1673
|
+
"operatorNote": "AWS Bedrock and Cloudflare Workers AI are enabled by the deployment operator via environment configuration, not from this screen.",
|
|
1674
|
+
"routes": {
|
|
1675
|
+
"keys": {
|
|
1676
|
+
"title": "Provider keys & subscriptions",
|
|
1677
|
+
"body": "Add a direct provider API key (OpenAI, Anthropic, Qwen, …) or connect a commercial coding-plan subscription (Kimi, DeepSeek) or a personal one (Claude, GLM, Codex).",
|
|
1678
|
+
"cta": "Open LLM vendors"
|
|
1679
|
+
},
|
|
1680
|
+
"openrouter": {
|
|
1681
|
+
"title": "OpenRouter gateway",
|
|
1682
|
+
"body": "Enable models through the OpenRouter gateway with a single key. Browse and turn on the models you want.",
|
|
1683
|
+
"cta": "Browse OpenRouter models"
|
|
1684
|
+
},
|
|
1685
|
+
"local": {
|
|
1686
|
+
"title": "My local runners",
|
|
1687
|
+
"body": "Point cat-factory at a model you run yourself (Ollama, LM Studio, llama.cpp, vLLM, …). No API key, no spend.",
|
|
1688
|
+
"cta": "Configure local runners"
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
},
|
|
1692
|
+
"personalCredential": {
|
|
1693
|
+
"titleWrongPassword": "Incorrect personal password",
|
|
1694
|
+
"titleNoSubscription": "Connect your {vendor} subscription",
|
|
1695
|
+
"titleExpired": "Your {vendor} subscription expired",
|
|
1696
|
+
"titleDefault": "Enter your personal password",
|
|
1697
|
+
"fallbackVendor": "subscription",
|
|
1698
|
+
"connectBody": "This task uses a {vendor} model, which runs on your own {vendor} subscription. Connect (or renew) it first, then start the run again.",
|
|
1699
|
+
"connectCta": "Connect subscription",
|
|
1700
|
+
"passwordBody": "Enter the personal password that protects your {vendor} subscription. It unlocks your credential for this run only and is cached in this browser so you won't be asked again for a while.",
|
|
1701
|
+
"passwordField": "Personal password",
|
|
1702
|
+
"passwordPlaceholder": "your personal password",
|
|
1703
|
+
"submit": "Unlock & run",
|
|
1704
|
+
"cancel": "Cancel",
|
|
1705
|
+
"toast": {
|
|
1706
|
+
"started": "Run started",
|
|
1707
|
+
"startFailed": "Could not start the run"
|
|
1708
|
+
},
|
|
1709
|
+
"vendors": {
|
|
1710
|
+
"claude": "Claude",
|
|
1711
|
+
"glm": "GLM (Z.ai)",
|
|
1712
|
+
"codex": "ChatGPT (Codex)"
|
|
1713
|
+
}
|
|
1714
|
+
},
|
|
1715
|
+
"apiKeys": {
|
|
1716
|
+
"directHeading": "Direct provider API keys",
|
|
1717
|
+
"proxyHeading": "Proxy / gateway API keys",
|
|
1718
|
+
"directAccountIntro": "Connect a vendor API key shared by every workspace in this account. Keys are stored encrypted, pooled, and rotated by usage. Account keys are admin-managed.",
|
|
1719
|
+
"directIntro": "Connect a vendor API key so models run directly on that provider. Keys are stored encrypted, pooled, and rotated by usage. Scope a key to this workspace (shared with the team) or to you (your own pool, usable anywhere).",
|
|
1720
|
+
"proxyAccountIntro": "Connect a proxy key (OpenRouter, LiteLLM) shared by every workspace in this account. A proxy is an intermediary that fronts many vendors behind a single key. Keys are stored encrypted, pooled, and rotated by usage.",
|
|
1721
|
+
"proxyIntro": "Connect a proxy key (OpenRouter, LiteLLM). A proxy is an intermediary that reaches many vendors' models through a single gateway, rather than one vendor directly. Keys are stored encrypted, pooled, and rotated by usage. Scope a key to this workspace (shared with the team) or to you (your own pool, usable anywhere).",
|
|
1722
|
+
"scopeField": "Scope",
|
|
1723
|
+
"scopeWorkspace": "This workspace",
|
|
1724
|
+
"scopeUser": "My keys (only me)",
|
|
1725
|
+
"providerField": "Provider",
|
|
1726
|
+
"proxyField": "Proxy",
|
|
1727
|
+
"openKeys": "Open {provider} keys ↗",
|
|
1728
|
+
"cachingNote": "Enables prompt caching for {provider} models, so a long multi-turn run reuses its cached prompt prefix instead of re-sending it every turn.",
|
|
1729
|
+
"labelField": "Label (optional)",
|
|
1730
|
+
"labelPlaceholder": "e.g. team key",
|
|
1731
|
+
"defaultLabel": "{provider} key",
|
|
1732
|
+
"keyField": "API key",
|
|
1733
|
+
"keyPlaceholder": "paste the API key",
|
|
1734
|
+
"connect": "Connect",
|
|
1735
|
+
"connected": "Connected ({count})",
|
|
1736
|
+
"usage": "{tokens} tok this window · {count} call | {tokens} tok this window · {count} calls",
|
|
1737
|
+
"@usage": {
|
|
1738
|
+
"description": "Usage readout for a connected API key. {tokens} is a preformatted token count; {count} is the number of API calls in the window and drives the plural. Provide ALL plural forms your language needs (English has 2; Polish/Ukrainian need 3 - one/few/many - via the custom pluralRules in i18n.config.ts)."
|
|
1739
|
+
},
|
|
1740
|
+
"toast": {
|
|
1741
|
+
"connected": "API key connected",
|
|
1742
|
+
"connectFailed": "Could not connect key",
|
|
1743
|
+
"removeFailed": "Could not remove key"
|
|
1744
|
+
},
|
|
1745
|
+
"providers": {
|
|
1746
|
+
"openai": {
|
|
1747
|
+
"label": "OpenAI",
|
|
1748
|
+
"step1": "Open platform.openai.com → API keys and create a new secret key.",
|
|
1749
|
+
"step2": "Copy the key (starts with sk-…); it is shown only once."
|
|
1750
|
+
},
|
|
1751
|
+
"anthropic": {
|
|
1752
|
+
"label": "Anthropic (Claude API)",
|
|
1753
|
+
"step1": "Open console.anthropic.com → Settings → API Keys and create a key.",
|
|
1754
|
+
"step2": "Copy the key (starts with sk-ant-…)."
|
|
1755
|
+
},
|
|
1756
|
+
"qwen": {
|
|
1757
|
+
"label": "Qwen (Alibaba DashScope)",
|
|
1758
|
+
"step1": "Open the DashScope console (international) → API-KEY and create a key.",
|
|
1759
|
+
"step2": "Copy the key; it authenticates the OpenAI-compatible Qwen endpoint."
|
|
1760
|
+
},
|
|
1761
|
+
"deepseek": {
|
|
1762
|
+
"label": "DeepSeek",
|
|
1763
|
+
"step1": "Open platform.deepseek.com → API keys and create a key.",
|
|
1764
|
+
"step2": "Copy the key (starts with sk-…)."
|
|
1765
|
+
},
|
|
1766
|
+
"moonshot": {
|
|
1767
|
+
"label": "Moonshot (Kimi API)",
|
|
1768
|
+
"step1": "Open platform.moonshot.ai → API Keys and create a key.",
|
|
1769
|
+
"step2": "Copy the key; it authenticates the OpenAI-compatible Moonshot endpoint."
|
|
1770
|
+
},
|
|
1771
|
+
"openrouter": {
|
|
1772
|
+
"label": "OpenRouter",
|
|
1773
|
+
"step1": "Open openrouter.ai → Keys and create an API key.",
|
|
1774
|
+
"step2": "Copy the key (starts with sk-or-…); it reaches 300+ models through one gateway."
|
|
1775
|
+
},
|
|
1776
|
+
"litellm": {
|
|
1777
|
+
"label": "LiteLLM (self-hosted gateway)",
|
|
1778
|
+
"step1": "Generate a virtual key on your LiteLLM gateway (or use its master key).",
|
|
1779
|
+
"step2": "The gateway's base URL is set by your deployment operator (LITELLM_BASE_URL), not here."
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
},
|
|
1783
|
+
"vendorCredentials": {
|
|
1784
|
+
"title": "LLM Vendors",
|
|
1785
|
+
"tabs": {
|
|
1786
|
+
"pool": "Workspace pool",
|
|
1787
|
+
"direct": "Direct providers",
|
|
1788
|
+
"proxy": "Proxies",
|
|
1789
|
+
"personal": "Personal subscriptions"
|
|
1790
|
+
},
|
|
1791
|
+
"poolIntro": "Connect a commercial coding-plan subscription (Kimi, DeepSeek) that permits team/organization use to run agent steps on the Claude Code harness instead of an API key. Tokens are stored encrypted, pooled, and rotated by usage. Subscription models are flat-rate quota, so they don't draw on your spend budget. Individual-use subscriptions (Claude, GLM, ChatGPT/Codex) are connected per-user in the Personal subscriptions tab.",
|
|
1792
|
+
"vendorField": "Vendor",
|
|
1793
|
+
"labelField": "Label (optional)",
|
|
1794
|
+
"labelPlaceholder": "e.g. work account",
|
|
1795
|
+
"defaultLabel": "{vendor} token",
|
|
1796
|
+
"tokenField": "Token",
|
|
1797
|
+
"tokenPlaceholder": "your coding-plan API key",
|
|
1798
|
+
"connect": "Connect",
|
|
1799
|
+
"connected": "Connected ({count})",
|
|
1800
|
+
"usage": "{tokens} tok this window · {count} run | {tokens} tok this window · {count} runs",
|
|
1801
|
+
"@usage": {
|
|
1802
|
+
"description": "Usage readout for a connected subscription token. {tokens} is a preformatted token count; {count} is the number of runs in the window and drives the plural. Provide ALL plural forms your language needs (English has 2; Polish/Ukrainian need 3 - one/few/many - via the custom pluralRules in i18n.config.ts)."
|
|
1803
|
+
},
|
|
1804
|
+
"toast": {
|
|
1805
|
+
"connected": "Token connected",
|
|
1806
|
+
"connectFailed": "Could not connect token",
|
|
1807
|
+
"removeFailed": "Could not remove token"
|
|
1808
|
+
},
|
|
1809
|
+
"vendors": {
|
|
1810
|
+
"kimi": {
|
|
1811
|
+
"label": "Kimi (Moonshot coding plan)",
|
|
1812
|
+
"step1": "Open your Moonshot (Kimi) coding-plan console and create an API key for the Anthropic-compatible endpoint.",
|
|
1813
|
+
"step2": "Copy the API key. Agent steps will run via Claude Code against Moonshot's Anthropic endpoint with full context.",
|
|
1814
|
+
"step3": "Paste the key below."
|
|
1815
|
+
},
|
|
1816
|
+
"deepseek": {
|
|
1817
|
+
"label": "DeepSeek (coding plan)",
|
|
1818
|
+
"step1": "Open your DeepSeek coding-plan console and create an API key for the Anthropic-compatible endpoint.",
|
|
1819
|
+
"step2": "Copy the API key. Agent steps will run via Claude Code against DeepSeek's Anthropic endpoint with full context.",
|
|
1820
|
+
"step3": "Paste the key below."
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1657
1824
|
}
|
|
1658
1825
|
}
|
package/i18n/locales/es.json
CHANGED
|
@@ -1609,5 +1609,166 @@
|
|
|
1609
1609
|
"removeFailed": "No se pudo eliminar el runner"
|
|
1610
1610
|
}
|
|
1611
1611
|
}
|
|
1612
|
+
},
|
|
1613
|
+
"providers": {
|
|
1614
|
+
"presetMismatch": {
|
|
1615
|
+
"title": "El preajuste usa modelos no disponibles",
|
|
1616
|
+
"intro": "El preajuste de modelo predeterminado del espacio de trabajo \"{name}\" asigna modelos que no están disponibles con la configuración actual. Las tareas que usen este preajuste fallarían al llegar a esos pasos.",
|
|
1617
|
+
"unavailable": "No disponibles",
|
|
1618
|
+
"advice": "Reapunta el preajuste a modelos que tengas configurados o añade el proveedor que falta.",
|
|
1619
|
+
"later": "Más tarde",
|
|
1620
|
+
"configureVendors": "Configurar proveedores",
|
|
1621
|
+
"editPresets": "Editar preajustes",
|
|
1622
|
+
"defaultPresetName": "preajuste predeterminado"
|
|
1623
|
+
},
|
|
1624
|
+
"onboarding": {
|
|
1625
|
+
"title": "Configurar un proveedor de modelos de IA",
|
|
1626
|
+
"noModelTitle": "Todavía no hay ningún modelo de IA disponible en este espacio de trabajo.",
|
|
1627
|
+
"noModelBody": "Los agentes necesitan un modelo para ejecutarse. La IA funciona de inmediato solo en un despliegue de Cloudflare con Workers AI habilitado; de lo contrario, conecta al menos una fuente abajo.",
|
|
1628
|
+
"operatorNote": "AWS Bedrock y Cloudflare Workers AI los habilita el operador del despliegue mediante la configuración del entorno, no desde esta pantalla.",
|
|
1629
|
+
"routes": {
|
|
1630
|
+
"keys": {
|
|
1631
|
+
"title": "Claves y suscripciones de proveedores",
|
|
1632
|
+
"body": "Añade una clave de API directa de un proveedor (OpenAI, Anthropic, Qwen, …) o conecta una suscripción comercial de plan de programación (Kimi, DeepSeek) o una personal (Claude, GLM, Codex).",
|
|
1633
|
+
"cta": "Abrir proveedores de LLM"
|
|
1634
|
+
},
|
|
1635
|
+
"openrouter": {
|
|
1636
|
+
"title": "Pasarela OpenRouter",
|
|
1637
|
+
"body": "Habilita modelos a través de la pasarela OpenRouter con una sola clave. Explora y activa los modelos que quieras.",
|
|
1638
|
+
"cta": "Explorar modelos de OpenRouter"
|
|
1639
|
+
},
|
|
1640
|
+
"local": {
|
|
1641
|
+
"title": "Mis ejecutores locales",
|
|
1642
|
+
"body": "Apunta cat-factory a un modelo que ejecutes tú mismo (Ollama, LM Studio, llama.cpp, vLLM, …). Sin clave de API ni gasto.",
|
|
1643
|
+
"cta": "Configurar ejecutores locales"
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
"personalCredential": {
|
|
1648
|
+
"titleWrongPassword": "Contraseña personal incorrecta",
|
|
1649
|
+
"titleNoSubscription": "Conecta tu suscripción de {vendor}",
|
|
1650
|
+
"titleExpired": "Tu suscripción de {vendor} ha caducado",
|
|
1651
|
+
"titleDefault": "Introduce tu contraseña personal",
|
|
1652
|
+
"fallbackVendor": "suscripción",
|
|
1653
|
+
"connectBody": "Esta tarea usa un modelo de {vendor}, que se ejecuta con tu propia suscripción de {vendor}. Conéctala (o renuévala) primero y luego inicia la ejecución de nuevo.",
|
|
1654
|
+
"connectCta": "Conectar suscripción",
|
|
1655
|
+
"passwordBody": "Introduce la contraseña personal que protege tu suscripción de {vendor}. Desbloquea tu credencial solo para esta ejecución y se almacena en este navegador un tiempo para no volver a pedírtela enseguida.",
|
|
1656
|
+
"passwordField": "Contraseña personal",
|
|
1657
|
+
"passwordPlaceholder": "tu contraseña personal",
|
|
1658
|
+
"submit": "Desbloquear y ejecutar",
|
|
1659
|
+
"cancel": "Cancelar",
|
|
1660
|
+
"toast": {
|
|
1661
|
+
"started": "Ejecución iniciada",
|
|
1662
|
+
"startFailed": "No se pudo iniciar la ejecución"
|
|
1663
|
+
},
|
|
1664
|
+
"vendors": {
|
|
1665
|
+
"claude": "Claude",
|
|
1666
|
+
"glm": "GLM (Z.ai)",
|
|
1667
|
+
"codex": "ChatGPT (Codex)"
|
|
1668
|
+
}
|
|
1669
|
+
},
|
|
1670
|
+
"apiKeys": {
|
|
1671
|
+
"directHeading": "Claves de API de proveedores directos",
|
|
1672
|
+
"proxyHeading": "Claves de API de proxy / pasarela",
|
|
1673
|
+
"directAccountIntro": "Conecta una clave de API de proveedor compartida por todos los espacios de trabajo de esta cuenta. Las claves se almacenan cifradas, se agrupan y se rotan según el uso. Las claves de cuenta las gestiona un administrador.",
|
|
1674
|
+
"directIntro": "Conecta una clave de API de proveedor para que los modelos se ejecuten directamente en ese proveedor. Las claves se almacenan cifradas, se agrupan y se rotan según el uso. Asigna el alcance de una clave a este espacio de trabajo (compartida con el equipo) o a ti (tu propio grupo, usable en cualquier sitio).",
|
|
1675
|
+
"proxyAccountIntro": "Conecta una clave de proxy (OpenRouter, LiteLLM) compartida por todos los espacios de trabajo de esta cuenta. Un proxy es un intermediario que da acceso a muchos proveedores tras una sola clave. Las claves se almacenan cifradas, se agrupan y se rotan según el uso.",
|
|
1676
|
+
"proxyIntro": "Conecta una clave de proxy (OpenRouter, LiteLLM). Un proxy es un intermediario que llega a los modelos de muchos proveedores a través de una sola pasarela, en lugar de un proveedor directo. Las claves se almacenan cifradas, se agrupan y se rotan según el uso. Asigna el alcance de una clave a este espacio de trabajo (compartida con el equipo) o a ti (tu propio grupo, usable en cualquier sitio).",
|
|
1677
|
+
"scopeField": "Alcance",
|
|
1678
|
+
"scopeWorkspace": "Este espacio de trabajo",
|
|
1679
|
+
"scopeUser": "Mis claves (solo yo)",
|
|
1680
|
+
"providerField": "Proveedor",
|
|
1681
|
+
"proxyField": "Proxy",
|
|
1682
|
+
"openKeys": "Abrir claves de {provider} ↗",
|
|
1683
|
+
"cachingNote": "Habilita la caché de prompts para los modelos de {provider}, de modo que una ejecución larga de varios turnos reutiliza su prefijo de prompt en caché en lugar de reenviarlo cada turno.",
|
|
1684
|
+
"labelField": "Etiqueta (opcional)",
|
|
1685
|
+
"labelPlaceholder": "p. ej. clave del equipo",
|
|
1686
|
+
"defaultLabel": "Clave de {provider}",
|
|
1687
|
+
"keyField": "Clave de API",
|
|
1688
|
+
"keyPlaceholder": "pega la clave de API",
|
|
1689
|
+
"connect": "Conectar",
|
|
1690
|
+
"connected": "Conectadas ({count})",
|
|
1691
|
+
"usage": "{tokens} tok esta ventana · {count} llamada | {tokens} tok esta ventana · {count} llamadas",
|
|
1692
|
+
"toast": {
|
|
1693
|
+
"connected": "Clave de API conectada",
|
|
1694
|
+
"connectFailed": "No se pudo conectar la clave",
|
|
1695
|
+
"removeFailed": "No se pudo eliminar la clave"
|
|
1696
|
+
},
|
|
1697
|
+
"providers": {
|
|
1698
|
+
"openai": {
|
|
1699
|
+
"label": "OpenAI",
|
|
1700
|
+
"step1": "Abre platform.openai.com → API keys y crea una nueva clave secreta.",
|
|
1701
|
+
"step2": "Copia la clave (empieza por sk-…); solo se muestra una vez."
|
|
1702
|
+
},
|
|
1703
|
+
"anthropic": {
|
|
1704
|
+
"label": "Anthropic (API de Claude)",
|
|
1705
|
+
"step1": "Abre console.anthropic.com → Settings → API Keys y crea una clave.",
|
|
1706
|
+
"step2": "Copia la clave (empieza por sk-ant-…)."
|
|
1707
|
+
},
|
|
1708
|
+
"qwen": {
|
|
1709
|
+
"label": "Qwen (Alibaba DashScope)",
|
|
1710
|
+
"step1": "Abre la consola de DashScope (internacional) → API-KEY y crea una clave.",
|
|
1711
|
+
"step2": "Copia la clave; autentica el endpoint de Qwen compatible con OpenAI."
|
|
1712
|
+
},
|
|
1713
|
+
"deepseek": {
|
|
1714
|
+
"label": "DeepSeek",
|
|
1715
|
+
"step1": "Abre platform.deepseek.com → API keys y crea una clave.",
|
|
1716
|
+
"step2": "Copia la clave (empieza por sk-…)."
|
|
1717
|
+
},
|
|
1718
|
+
"moonshot": {
|
|
1719
|
+
"label": "Moonshot (API de Kimi)",
|
|
1720
|
+
"step1": "Abre platform.moonshot.ai → API Keys y crea una clave.",
|
|
1721
|
+
"step2": "Copia la clave; autentica el endpoint de Moonshot compatible con OpenAI."
|
|
1722
|
+
},
|
|
1723
|
+
"openrouter": {
|
|
1724
|
+
"label": "OpenRouter",
|
|
1725
|
+
"step1": "Abre openrouter.ai → Keys y crea una clave de API.",
|
|
1726
|
+
"step2": "Copia la clave (empieza por sk-or-…); llega a más de 300 modelos a través de una sola pasarela."
|
|
1727
|
+
},
|
|
1728
|
+
"litellm": {
|
|
1729
|
+
"label": "LiteLLM (pasarela autoalojada)",
|
|
1730
|
+
"step1": "Genera una clave virtual en tu pasarela LiteLLM (o usa su clave maestra).",
|
|
1731
|
+
"step2": "La URL base de la pasarela la establece el operador de tu despliegue (LITELLM_BASE_URL), no aquí."
|
|
1732
|
+
}
|
|
1733
|
+
}
|
|
1734
|
+
},
|
|
1735
|
+
"vendorCredentials": {
|
|
1736
|
+
"title": "Proveedores de LLM",
|
|
1737
|
+
"tabs": {
|
|
1738
|
+
"pool": "Grupo del espacio de trabajo",
|
|
1739
|
+
"direct": "Proveedores directos",
|
|
1740
|
+
"proxy": "Proxies",
|
|
1741
|
+
"personal": "Suscripciones personales"
|
|
1742
|
+
},
|
|
1743
|
+
"poolIntro": "Conecta una suscripción comercial de plan de programación (Kimi, DeepSeek) que permita uso de equipo/organización para ejecutar los pasos de agente en el harness de Claude Code en lugar de una clave de API. Los tokens se almacenan cifrados, se agrupan y se rotan según el uso. Los modelos de suscripción tienen cuota de tarifa plana, así que no consumen tu presupuesto de gasto. Las suscripciones de uso individual (Claude, GLM, ChatGPT/Codex) se conectan por usuario en la pestaña de Suscripciones personales.",
|
|
1744
|
+
"vendorField": "Proveedor",
|
|
1745
|
+
"labelField": "Etiqueta (opcional)",
|
|
1746
|
+
"labelPlaceholder": "p. ej. cuenta de trabajo",
|
|
1747
|
+
"defaultLabel": "Token de {vendor}",
|
|
1748
|
+
"tokenField": "Token",
|
|
1749
|
+
"tokenPlaceholder": "tu clave de API del plan de programación",
|
|
1750
|
+
"connect": "Conectar",
|
|
1751
|
+
"connected": "Conectados ({count})",
|
|
1752
|
+
"usage": "{tokens} tok esta ventana · {count} ejecución | {tokens} tok esta ventana · {count} ejecuciones",
|
|
1753
|
+
"toast": {
|
|
1754
|
+
"connected": "Token conectado",
|
|
1755
|
+
"connectFailed": "No se pudo conectar el token",
|
|
1756
|
+
"removeFailed": "No se pudo eliminar el token"
|
|
1757
|
+
},
|
|
1758
|
+
"vendors": {
|
|
1759
|
+
"kimi": {
|
|
1760
|
+
"label": "Kimi (plan de programación de Moonshot)",
|
|
1761
|
+
"step1": "Abre la consola de tu plan de programación de Moonshot (Kimi) y crea una clave de API para el endpoint compatible con Anthropic.",
|
|
1762
|
+
"step2": "Copia la clave de API. Los pasos de agente se ejecutarán vía Claude Code contra el endpoint de Anthropic de Moonshot con contexto completo.",
|
|
1763
|
+
"step3": "Pega la clave abajo."
|
|
1764
|
+
},
|
|
1765
|
+
"deepseek": {
|
|
1766
|
+
"label": "DeepSeek (plan de programación)",
|
|
1767
|
+
"step1": "Abre la consola de tu plan de programación de DeepSeek y crea una clave de API para el endpoint compatible con Anthropic.",
|
|
1768
|
+
"step2": "Copia la clave de API. Los pasos de agente se ejecutarán vía Claude Code contra el endpoint de Anthropic de DeepSeek con contexto completo.",
|
|
1769
|
+
"step3": "Pega la clave abajo."
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1612
1773
|
}
|
|
1613
1774
|
}
|