Skip to content
Draft
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
7 changes: 7 additions & 0 deletions gui/src/combo-public-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** Placeholder shown before the draft id/alias can form a public model id. */
export const PUBLIC_MODEL_PREVIEW_PLACEHOLDER = "…";

/** True when the preview value is a real public model id clients can request. */
export function canCopyPublicModelId(model: string): boolean {
return model.trim().length > 0 && model !== PUBLIC_MODEL_PREVIEW_PLACEHOLDER;
}
11 changes: 5 additions & 6 deletions gui/src/components/combo-workspace-add-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
intersectComboEfforts,
validateComboDraft,
} from "../combo-workspace-data";
import { PUBLIC_MODEL_PREVIEW_PLACEHOLDER } from "../combo-public-model";
import { IconX } from "../icons";
import { useT } from "../i18n/shared";
import { Notice } from "../ui";
import type { ModelOption, ProviderOption } from "./combo-workspace-types";
import { EffortSelect, StrategySeg, TargetEditor } from "./combo-workspace-controls";
import { EffortSelect, PublicModelPreview, StrategySeg, TargetEditor } from "./combo-workspace-controls";
import { clampedNumberInput } from "./combo-workspace-utils";

export function AddComboModal({
Expand Down Expand Up @@ -139,11 +140,9 @@ export function AddComboModal({
<p className="muted" style={{ fontSize: 12, margin: "8px 0 0" }}>
{t("cws.field.aliasHint")}
</p>
<p className="muted" style={{ fontSize: 12, margin: "8px 0 0" }}>
{t("cws.field.idHint", {
model: draft.id.trim() ? comboPublicModelId(draft.id, draft.alias) : "…",
})}
</p>
<PublicModelPreview
model={draft.id.trim() ? comboPublicModelId(draft.id, draft.alias) : PUBLIC_MODEL_PREVIEW_PLACEHOLDER}
/>
</div>
<div className="cwi-field">
<span className="field-label">{t("cws.strategy")}</span>
Expand Down
39 changes: 39 additions & 0 deletions gui/src/components/combo-workspace-controls.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useState } from "react";
import type { ComboEffort, ComboStrategy, ComboTarget } from "../combo-workspace-data";
import { canCopyPublicModelId } from "../combo-public-model";
import { COMBO_EFFORTS, newComboTarget } from "../combo-workspace-data";
import { IconArrowDown, IconArrowUp, IconGrip, IconPlus, IconTrash } from "../icons";
import { useT } from "../i18n/shared";
import { formatProviderDisplayName } from "../provider-icons";
import type { ModelOption, ProviderOption } from "./combo-workspace-types";
import { clampedNumberInput, enabledProviders, modelsForProvider } from "./combo-workspace-utils";
import { useCopyFeedback } from "./use-copy-feedback";

export function StrategySeg({
value,
Expand Down Expand Up @@ -262,3 +264,40 @@ export function TargetEditor({
</div>
);
}

/** Effective public model id clients will request — mono value + copy. */
export function PublicModelPreview({ model }: { model: string }) {
const t = useT();
const { outcomeFor, copy } = useCopyFeedback<string>();
const canCopy = canCopyPublicModelId(model);
const outcome = outcomeFor(model);
const copyLabel = outcome === "copied"
? t("cws.copiedPublicModel")
: outcome === "unavailable"
? t("cws.copyUnavailable")
: t("cws.copyPublicModel");
// Split around a sentinel so the model token stays mono in any locale word order.
const sentinel = "\u0001";
const [before, after = ""] = t("cws.field.publicModelPreview", { model: sentinel }).split(sentinel);

return (
<div className="cwi-public-model-preview">
<p className="muted cwi-public-model-preview-text">
{before}
<code className="mono cwi-public-model-preview-value">{model}</code>
{after}
</p>
<button
type="button"
className="btn btn-ghost btn-sm cwi-public-model-preview-copy"
disabled={!canCopy}
onClick={() => {
if (canCopy) copy(model, model);
}}
title={copyLabel}
>
<span aria-live="polite">{copyLabel}</span>
</button>
</div>
);
}
Comment on lines +269 to +303

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared ellipsis placeholder into a named constant.

canCopy on Line 271 hardcodes model !== "…" to detect the placeholder value. The same "…" literal is duplicated in gui/src/components/combo-workspace-add-modal.tsx (Line 143) and gui/src/components/combo-workspace-detail-panel.tsx (Line 217). Correctness of canCopy depends on all three literals staying byte-for-byte identical (for example, a future edit that swaps "…" for "..." in one call site silently breaks the copy button in that view).

Export a shared constant from combo-workspace-controls.tsx (or combo-workspace-data.ts) and import it at all three sites, so the placeholder has one source of truth.

♻️ Proposed refactor
+export const COMBO_ID_PLACEHOLDER = "…";
+
 export function PublicModelPreview({ model }: { model: string }) {
   const t = useT();
   const { outcomeFor, copy } = useCopyFeedback<string>();
-  const canCopy = model.trim().length > 0 && model !== "…";
+  const canCopy = model.trim().length > 0 && model !== COMBO_ID_PLACEHOLDER;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gui/src/components/combo-workspace-controls.tsx` around lines 268 - 302,
Define and export a shared ellipsis placeholder constant in
combo-workspace-controls.tsx or combo-workspace-data.ts, then replace the
hardcoded "…" checks/usages in PublicModelPreview,
combo-workspace-add-modal.tsx, and combo-workspace-detail-panel.tsx with that
constant. Update imports at both consuming sites so all placeholder comparisons
and values use one source of truth.

39 changes: 23 additions & 16 deletions gui/src/components/combo-workspace-detail-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import {
intersectComboEfforts,
validateComboDraft,
} from "../combo-workspace-data";
import { PUBLIC_MODEL_PREVIEW_PLACEHOLDER } from "../combo-public-model";
import { IconChevron, IconTrash } from "../icons";
import { useT } from "../i18n/shared";
import { Notice } from "../ui";
import type { ModelOption, ProviderOption } from "./combo-workspace-types";
import { EffortSelect, StrategySeg, TargetEditor } from "./combo-workspace-controls";
import { EffortSelect, PublicModelPreview, StrategySeg, TargetEditor } from "./combo-workspace-controls";
import { clampedNumberInput } from "./combo-workspace-utils";
import { useCopyFeedback } from "./use-copy-feedback";

type DetailTab = "config" | "about";

Expand Down Expand Up @@ -46,11 +48,11 @@ export function DetailPanel({
onDirtyChange: (dirty: boolean) => void;
}) {
const t = useT();
const { outcomeFor, copy } = useCopyFeedback<string>();
const [tab, setTab] = useState<DetailTab>("config");
const [draft, setDraft] = useState<ComboItem>(baseline);
const [busy, setBusy] = useState(false);
const [msg, setMsg] = useState<{ ok: boolean; text: string } | null>(null);
const [copied, setCopied] = useState(false);
const dirty = !draftEquals(draft, baseline);
const baselineSyncKey = `${baseline.id}:${baseline.alias ?? ""}:${baseline.strategy}:${baseline.stickyLimit}:${baseline.defaultEffort}:${baseline.targets.map((t) => `${t.provider}/${t.model}:${t.weight ?? 1}`).join(",")}`;
const effortMap = useMemo(() => {
Expand Down Expand Up @@ -82,15 +84,6 @@ export function DetailPanel({
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentional: key captures baseline payload
}, [baselineSyncKey]);

const copyModel = async () => {
try {
await navigator.clipboard.writeText(baseline.model);
setCopied(true);
window.setTimeout(() => setCopied(false), 1200);
} catch {
/* ignore */
}
};

const save = async () => {
const code = validateComboDraft(draft, {
Expand Down Expand Up @@ -132,6 +125,14 @@ export function DetailPanel({
const headerModel = isCreate
? (draft.id.trim() ? comboPublicModelId(draft.id, draft.alias) : t("cws.addTitle"))
: baseline.model;
// Public model id clients request — same string PublicModelPreview copies.
const copyModelId = baseline.model;
const copyOutcome = outcomeFor(copyModelId);
const copyLabel = copyOutcome === "copied"
? t("cws.copied")
: copyOutcome === "unavailable"
? t("cws.copyUnavailable")
: t("cws.copyModel");

return (
<div className="combos-workspace-detail">
Expand All @@ -144,8 +145,13 @@ export function DetailPanel({
)}
<h2 className="combos-workspace-detail-title">{headerModel}</h2>
{!isCreate && (
<button type="button" className="chip cwi-copy-chip" onClick={() => { void copyModel(); }} title={t("cws.copyModel")}>
{copied ? t("cws.copied") : t("cws.copyModel")}
<button
type="button"
className="chip cwi-copy-chip"
onClick={() => copy(copyModelId, copyModelId)}
title={copyLabel}
>
<span aria-live="polite">{copyLabel}</span>
</button>
)}
<div className="combos-workspace-detail-actions">
Expand Down Expand Up @@ -188,9 +194,7 @@ export function DetailPanel({
}))}
/>
<p className="muted" style={{ fontSize: 12, margin: "8px 0 0" }}>
{isCreate
? t("cws.field.idInternalHint")
: t("cws.field.idHintEdit", { model: comboPublicModelId(draft.id, draft.alias) })}
{isCreate ? t("cws.field.idInternalHint") : t("cws.field.idHintEdit")}
</p>
</div>
<div className="cwi-field">
Expand All @@ -210,6 +214,9 @@ export function DetailPanel({
<p className="muted" style={{ fontSize: 12, margin: "8px 0 0" }}>
{t("cws.field.aliasHint")}
</p>
<PublicModelPreview
model={draft.id.trim() ? comboPublicModelId(draft.id, draft.alias) : PUBLIC_MODEL_PREVIEW_PLACEHOLDER}
/>
</div>
<div className="cwi-field">
<span className="field-label">{t("cws.strategy")}</span>
Expand Down
12 changes: 8 additions & 4 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1715,6 +1715,9 @@ export const de: Record<TKey, string> = {
"cws.allCombos": "Alle Combos",
"cws.copyModel": "ID kopieren",
"cws.copied": "Kopiert",
"cws.copiedPublicModel": "Kopiert",
"cws.copyPublicModel": "Kopieren",
"cws.copyUnavailable": "Zwischenablage nicht verfügbar",
"cws.tab.config": "Konfiguration",
"cws.tab.about": "Info",
"cws.strategy": "Strategie",
Expand All @@ -1723,12 +1726,13 @@ export const de: Record<TKey, string> = {
"cws.strategy.failoverHint": "Ziele der Reihe nach versuchen. Bei einem wiederholbaren Fehler (Limit, Ausfall, Abo-Sperre) zum nächsten springen.",
"cws.strategy.roundRobinHint": "Datenverkehr deterministisch nach Gewicht verteilen. Das gewählte Ziel für einen Block erfolgreicher Anfragen behalten und dann weiterschalten.",
"cws.field.id": "Combo-ID",
"cws.field.idHintEdit": "Das Ändern der ID benennt die Combo um. Clients fordern {model} an.",
"cws.field.idHintEdit": "Das Ändern der ID benennt die Combo um. Ohne öffentlichen Modellnamen fordern Clients combo/<id> an.",
"cws.field.alias": "Öffentlicher Modellname",
"cws.field.aliasPlaceholder": "deepseek-v4-flash oder vendor/model",
"cws.field.aliasHint": "Optional. Verwenden Sie einen Namen ohne Präfix, ein eigenes Präfix wie vendor/model oder lassen Sie das Feld leer für combo/<id>.",
"cws.field.idHint": "Clients fordern {model} an",
"cws.field.idInternalHint": "Interne Combo-ID. Sie kann nach dem Erstellen geändert werden.",
"cws.field.aliasHint": "Optional. Überschreibt den Namen, den Clients anfordern. Name ohne Präfix, eigenes Präfix wie vendor/model, oder leer lassen für combo/<id>.",
"cws.field.publicModelPreview": "Clients fordern an: {model}",
"cws.field.idHint": "Clients fordern an: {model}",
"cws.field.idInternalHint": "Interne Combo-ID. Ohne öffentlichen Modellnamen fordern Clients combo/<id> an.",
"cws.field.stickyLimit": "Sticky-Erfolge vor Rotation",
"cws.field.stickyLimitHint": "Das gewählte Ziel für so viele erfolgreiche Anfragen behalten, bevor die gewichtete Auswahl weiterschaltet.",
"cws.field.defaultEffort": "Standard-Reasoning",
Expand Down
12 changes: 8 additions & 4 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1749,6 +1749,9 @@ export const en = {
"cws.allCombos": "All combos",
"cws.copyModel": "Copy id",
"cws.copied": "Copied",
"cws.copiedPublicModel": "Copied",
"cws.copyPublicModel": "Copy",
"cws.copyUnavailable": "Clipboard unavailable",
"cws.tab.config": "Config",
"cws.tab.about": "About",
"cws.strategy": "Strategy",
Expand All @@ -1757,12 +1760,13 @@ export const en = {
"cws.strategy.failoverHint": "Try targets in order. If the first fails with a retryable error (rate limit, outage, subscription gate), hop to the next.",
"cws.strategy.roundRobinHint": "Deterministically balance traffic by weight. Keep each selected target for a batch of successful requests, then advance.",
"cws.field.id": "Combo id",
"cws.field.idHint": "Clients will request {model}",
"cws.field.idInternalHint": "Internal combo id. You can change it after creation.",
"cws.field.idHintEdit": "Renaming moves the combo to a new id. Clients request {model}.",
"cws.field.idHint": "Clients request: {model}",
"cws.field.idInternalHint": "Internal id for this combo. When no public model name is set, clients use combo/<id>.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update combo test for new ID helper copy

Changing this source string leaves the existing empty-workspace test asserting the old helper copy (Internal combo id. You can change it after creation.), so the required GUI test suite will fail in tests/combo-workspace-empty.test.tsx as soon as dependencies are installed. Update that assertion along with the locale copy (or keep the old text) so cd gui && bun test tests stays green.

AGENTS.md reference: gui/AGENTS.md:L42-L50

Useful? React with 👍 / 👎.

"cws.field.idHintEdit": "Changing the id renames the combo. When no public model name is set, clients use combo/<id>.",
"cws.field.alias": "Public model name",
"cws.field.aliasPlaceholder": "deepseek-v4-flash or vendor/model",
"cws.field.aliasHint": "Optional. Use a bare name with no prefix, a custom prefix like vendor/model, or leave blank to use combo/<id>.",
"cws.field.aliasHint": "Optional override for the name clients request. Use a bare name, a custom prefix like vendor/model, or leave blank for combo/<id>.",
"cws.field.publicModelPreview": "Clients request: {model}",
Comment on lines +1763 to +1769

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm cws.field.idHint has no remaining callers in the GUI source before deleting it everywhere.
rg -n '"cws\.field\.idHint"' gui/src
rg -nP 't\(\s*"cws\.field\.idHint"' gui/src

Repository: lidge-jun/opencodex

Length of output: 587


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== i18n locale files =="
git ls-files 'gui/src/i18n/*.ts' | sort

echo
echo "== duplicate-text candidates around cws.field keys in each locale =="
python3 - <<'PY'
import os, pathlib, re
files = sorted(pathlib.Path('gui/src/i18n').glob('*.ts'))
for pat in ['en', 'de', 'ja', 'ko', 'ru', 'zh']:
    for f in files:
        if f.stem != pat:
            continue
        txt = f.read_text(encoding='utf-8')
        keys = ['cws.field.idHint','cws.field.publicModelPreview','cws.field.idInternalHint','cws.field.idHintEdit','cws.field.alias','cws.field.aliasPlaceholder','cws.field.aliasHint']
        print(f"\n{f}")
        for key, line in [(key, txt.splitlines()[i].strip()) for i, line in enumerate(txt.splitlines(), 1) if key in line and 'cws.field.' in line][:7]:
            pass
        # print lines containing target keys and nearby keys for context
        for i, line in enumerate(txt.splitlines(), 1):
            if any(k in line for k in keys):
                print(f"{i:<4} {line}")
PY

echo
echo "== call sites for cws.field.idHint via common UI i18n helpers =="
rg -n '(\buseI18n|useTranslation|i18n\.)\(([^)]*idHint|[^)]*publicModelPreview|[^)]*idInternalHint|[^)]*idHintEdit)[^)]*|t\(\s*["\047]cws\.field\.(idHint|publicModelPreview|idInternalHint|idHintEdit|alias)(["\047])' gui/src || true

echo
echo "== broader idHint/publicModelPreview text matches (excludes i18n definitions) =="
rg -n --glob '!gui/src/i18n/*.ts' 'idHint|publicModelPreview|Clients request: \{model\}|Clients 要求|クライアントのリクエスト|클라이언트 요청|Клиенты запрашивают' gui/src || true

Repository: lidge-jun/opencodex

Length of output: 582


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== i18n locale files =="
git ls-files 'gui/src/i18n/*.ts' | sort

echo
echo "== target cws.field keys in each locale =="
for f in gui/src/i18n/en.ts gui/src/i18n/de.ts gui/src/i18n/ja.ts gui/src/i18n/ko.ts gui/src/i18n/ru.ts gui/src/i18n/zh.ts; do
  echo "-- $f --"
  git -C "$(dirname "$f")" grep -n -e '"cws\.field\.idHint"' -e '"cws\.field\.publicModelPreview"' -e '"cws\.field\.idInternalHint"' -e '"cws\.field\.idHintEdit"' "$f" || true
done

echo
echo "== call sites for cws.field.idHint in GUI source (excluding i18n locale definitions) =="
rg -n --glob '!gui/src/i18n/*.ts' 'cws\.field\.idHint|cws\.field\.publicModelPreview|cws\.field\.idInternalHint|cws\.field\.idHintEdit|t\(' gui/src || true

echo
echo "== static text matches outside i18n locale definitions =="
rg -n --glob '!gui/src/i18n/*.ts' 'Clients request: \{model\}|Clients fordern an: \{model\}|クライアントのリクエスト: \{model\}|클라이언트 요청: \{model\}|Клиенты запрашивают: \{model\}|客户端请求:\{model\}|Clients request|publicModelPreview' gui/src || true

Repository: lidge-jun/opencodex

Length of output: 50376


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== cws.field target key definitions by locale =="
for f in gui/src/i18n/en.ts gui/src/i18n/de.ts gui/src/i18n/ja.ts gui/src/i18n/ko.ts gui/src/i18n/ru.ts gui/src/i18n/zh.ts; do
  echo "-- $f --"
  rg -n '"cws\.field\.(idHint|publicModelPreview|idInternalHint|idHintEdit)"' "$f" || true
done

echo
echo "== GUI source references to target cws.field keys outside i18n locale files =="
rg -n --glob '!gui/src/i18n/*.ts' 'cws\.field\.(idHint|publicModelPreview|idInternalHint|idHintEdit)\b' gui/src || true

echo
echo "== GUI source direct text match for publicModelPreview equivalent outside i18n locale files =="
rg -n --glob '!gui/src/i^8n/*.ts' 'Clients request: \{model\}|Clients fordern an: \{model\}|Клиенты запрашивают: \{model\}|クライアントのリクエスト: \{model\}|클라이언트 요청: \{model\}|客户端请求:\{model\}' gui/src || true

Repository: lidge-jun/opencodex

Length of output: 3859


Remove the unused cws.field.idHint entries from all locale catalogs. The GUI now renders the request preview through cws.field.publicModelPreview (gui/src/components/combo-workspace-controls.tsx:280), while ID-related combo text uses cws.field.idInternalHint / cws.field.idHintEdit (gui/src/components/combo-workspace-add-modal.tsx:122, gui/src/components/combo-workspace-detail-panel.tsx:196). Since locale files implement the shared key type from gui/src/i18n/en.ts, delete cws.field.idHint from every locale, not just one.

📍 Affects 6 files
  • gui/src/i18n/en.ts#L1763-L1769 (this comment)
  • gui/src/i18n/de.ts#L1729-L1735
  • gui/src/i18n/ja.ts#L1797-L1803
  • gui/src/i18n/ko.ts#L1756-L1762
  • gui/src/i18n/ru.ts#L1839-L1845
  • gui/src/i18n/zh.ts#L1749-L1755
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@gui/src/i18n/en.ts` around lines 1763 - 1769, Remove the unused
cws.field.idHint entry from every locale catalog: gui/src/i18n/en.ts
(1763-1769), gui/src/i18n/de.ts (1729-1735), gui/src/i18n/ja.ts (1797-1803),
gui/src/i18n/ko.ts (1756-1762), gui/src/i18n/ru.ts (1839-1845), and
gui/src/i18n/zh.ts (1749-1755). Keep cws.field.publicModelPreview,
cws.field.idInternalHint, and cws.field.idHintEdit unchanged.

"cws.field.stickyLimit": "Sticky successes before rotate",
"cws.field.stickyLimitHint": "Retain the selected target for this many successful requests before the weighted selector advances.",
"cws.field.defaultEffort": "Default reasoning",
Expand Down
12 changes: 8 additions & 4 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1782,6 +1782,9 @@ export const ja: Record<TKey, string> = {
"cws.allCombos": "すべてのコンボ",
"cws.copyModel": "ID をコピー",
"cws.copied": "コピーしました",
"cws.copiedPublicModel": "コピーしました",
"cws.copyPublicModel": "コピー",
"cws.copyUnavailable": "クリップボードを利用できません",
"cws.renamed": "{from} を {to} に変更しました。",
"cws.tab.config": "設定",
"cws.tab.about": "概要",
Expand All @@ -1791,12 +1794,13 @@ export const ja: Record<TKey, string> = {
"cws.strategy.failoverHint": "ターゲットを順に試します。最初が再試行可能なエラー(レート制限、障害、サブスクリプションゲート)で失敗した場合、次へホップします。",
"cws.strategy.roundRobinHint": "重みで決定論的にトラフィックを分散します。選んだターゲットを成功リクエストのバッチ分保持し、次へ進みます。",
"cws.field.id": "コンボ ID",
"cws.field.idHint": "クライアントは {model} をリクエストします",
"cws.field.idInternalHint": "コンボの内部 ID。作成後も変更できます。",
"cws.field.idHintEdit": "ID を変更するとコンボの名前が変更されます。クライアントは {model} をリクエストします。",
"cws.field.idHint": "クライアントのリクエスト: {model}",
"cws.field.idInternalHint": "コンボの内部 ID。公開モデル名を設定しない場合、クライアントは combo/<id> を使用します。",
"cws.field.idHintEdit": "ID を変更するとコンボの名前が変更されます。公開モデル名を設定しない場合、クライアントは combo/<id> を使用します。",
"cws.field.alias": "公開モデル名",
"cws.field.aliasPlaceholder": "deepseek-v4-flash または vendor/model",
"cws.field.aliasHint": "任意。プレフィックスなしの名前、vendor/model のようなカスタムプレフィックスを指定するか、空欄のままにすると combo/<id> を使用します。",
"cws.field.aliasHint": "任意。クライアントがリクエストする名前の上書き。プレフィックスなしの名前、vendor/model のようなカスタムプレフィックス、または空欄で combo/<id>。",
"cws.field.publicModelPreview": "クライアントのリクエスト: {model}",
"cws.field.stickyLimit": "ローテーション前の固定成功数",
"cws.field.stickyLimitHint": "重み付きセレクタが進む前に、選んだターゲットをこの回数の成功リクエスト分保持します。",
"cws.field.defaultEffort": "デフォルトの推論",
Expand Down
12 changes: 8 additions & 4 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,9 @@ export const ko: Record<TKey, string> = {
"cws.allCombos": "모든 콤보",
"cws.copyModel": "ID 복사",
"cws.copied": "복사됨",
"cws.copiedPublicModel": "복사됨",
"cws.copyPublicModel": "복사",
"cws.copyUnavailable": "클립보드를 사용할 수 없음",
"cws.tab.config": "설정",
"cws.tab.about": "정보",
"cws.strategy": "전략",
Expand All @@ -1750,12 +1753,13 @@ export const ko: Record<TKey, string> = {
"cws.strategy.failoverHint": "대상을 순서대로 시도합니다. 재시도 가능한 오류(한도, 장애, 구독 게이트)면 다음으로 넘어갑니다.",
"cws.strategy.roundRobinHint": "가중치에 따라 트래픽을 결정적으로 분배합니다. 선택된 대상을 성공 요청 묶음 동안 유지한 뒤 다음 대상으로 진행합니다.",
"cws.field.id": "콤보 ID",
"cws.field.idHintEdit": "ID를 변경하면 콤보 이름이 바뀝니다. 클라이언트는 {model}을(를) 요청합니다.",
"cws.field.idHintEdit": "ID를 변경하면 콤보 이름이 바뀝니다. 공개 모델 이름을 설정하지 않으면 클라이언트는 combo/<id>를 사용합니다.",
"cws.field.alias": "공개 모델 이름",
"cws.field.aliasPlaceholder": "deepseek-v4-flash 또는 vendor/model",
"cws.field.aliasHint": "선택 사항입니다. 접두사 없는 이름, vendor/model 같은 사용자 지정 접두사를 사용하거나 비워 두어 combo/<id>를 사용할 수 있습니다.",
"cws.field.idHint": "클라이언트는 {model}을(를) 요청합니다",
"cws.field.idInternalHint": "내부 콤보 ID입니다. 생성 후에도 변경할 수 있습니다.",
"cws.field.aliasHint": "선택 사항입니다. 클라이언트가 요청하는 이름을 재정의합니다. 접두사 없는 이름, vendor/model 같은 사용자 지정 접두사, 또는 비워 두면 combo/<id>.",
"cws.field.publicModelPreview": "클라이언트 요청: {model}",
"cws.field.idHint": "클라이언트 요청: {model}",
"cws.field.idInternalHint": "내부 콤보 ID입니다. 공개 모델 이름을 설정하지 않으면 클라이언트는 combo/<id>를 사용합니다.",
"cws.field.stickyLimit": "회전 전 sticky 성공 횟수",
"cws.field.stickyLimitHint": "가중 선택기가 다음 대상으로 진행하기 전에 선택된 대상을 이 성공 요청 횟수만큼 유지합니다.",
"cws.field.defaultEffort": "기본 추론 수준",
Expand Down
Loading
Loading