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
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ja/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ interface ProviderAdapter {
## `anthropic`

**対象:** Anthropic **Messages**(`/v1/messages`)。
**認証:** `key`(`x-api-key`)または `oauth`(Bearer + `anthropic-beta`、Claude Pro/Max 用)。
**認証:** `key`(デフォルトは `x-api-key`、または `apiKeyTransport: "bearer"` による `Authorization: Bearer`)または `oauth`(Bearer + `anthropic-beta`、Claude Pro/Max 用)。

- メッセージを Anthropic content block(text、base64 image、`tool_use`、`thinking`)に変換します。
- **Extended thinking の計算:** Anthropic は `max_tokens > thinking.budget_tokens` を要求します。
Expand Down
1 change: 1 addition & 0 deletions docs-site/src/content/docs/ja/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ token の代わりに使えます。すべての候補は timing side channel
| `responsesPath?` | `string` | `key` 認証の `openai-responses` リクエストに使う任意の相対 resource path。`/` で始め、URL scheme、query、fragment を含めてはいけません。省略時は従来の `/v1/responses` URL 構築を維持します。 |
| `disabled?` | `boolean` | 設定はディスクに残すがルーティングとモデル/カタログ一覧から除外します。 |
| `apiKey?` | `string` | API キーまたはリクエスト時に解釈する `${ENV_VAR}` / `$ENV_VAR` 参照。 |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API キーのヘッダー方式。デフォルトはネイティブの `x-api-key` です。`Authorization: Bearer <key>` が必要な互換 gateway では `"bearer"` を設定します。key 認証の `anthropic` プロバイダーでのみ有効です。 |
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 複数キーを納める pool。`apiKey` はアクティブ項目を反映します。各項目には `id`、`key`、選択 `label`、選択数値 `addedAt` があります。 |
| `defaultModel?` | `string` | 明示的なモデルなしでこのプロバイダーを選んだときに使うモデル。 |
| `models?` | `string[]` | seed/fallback モデル一覧。`liveModels` が `false` ならここにあるモデルだけが発見されます。 |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ko/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ interface ProviderAdapter {
## `anthropic`

**대상:** Anthropic **Messages**(`/v1/messages`).
**인증:** `key`(`x-api-key`) 또는 `oauth`(Bearer + `anthropic-beta`, Claude Pro/Max용).
**인증:** `key`(기본 `x-api-key`, 또는 `apiKeyTransport: "bearer"` 설정 시 `Authorization: Bearer`) 또는 `oauth`(Bearer + `anthropic-beta`, Claude Pro/Max용).

- 메시지를 Anthropic content block(text, base64 image, `tool_use`, `thinking`)으로 변환합니다.
- **Extended thinking 계산:** Anthropic은 `max_tokens > thinking.budget_tokens`를 요구합니다.
Expand Down
1 change: 1 addition & 0 deletions docs-site/src/content/docs/ko/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ token 대신 쓸 수 있습니다. 모든 후보는 timing side channel을 막
| `responsesPath?` | `string` | `key` 인증 `openai-responses` 요청에 사용할 선택적 상대 resource path. `/`로 시작해야 하며 URL scheme, query, fragment를 포함할 수 없습니다. 생략하면 기존 `/v1/responses` URL 구성을 유지합니다. |
| `disabled?` | `boolean` | 설정은 디스크에 남기되 라우팅과 모델/카탈로그 목록에서 제외합니다. |
| `apiKey?` | `string` | API 키 또는 요청 시점에 해석할 `${ENV_VAR}` / `$ENV_VAR` 참조. |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API 키 헤더 방식입니다. 기본값은 네이티브 `x-api-key`이며, `Authorization: Bearer <key>`를 요구하는 호환 gateway에는 `"bearer"`를 설정합니다. key 인증 `anthropic` 프로바이더에서만 유효합니다. |
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 여러 키를 담는 pool. `apiKey`는 활성 항목을 반영합니다. 각 항목에는 `id`, `key`, 선택 `label`, 선택 숫자 `addedAt`이 있습니다. |
| `defaultModel?` | `string` | 명시적인 모델 없이 이 프로바이더를 선택했을 때 쓸 모델. |
| `models?` | `string[]` | seed/fallback 모델 목록. `liveModels`가 `false`이면 여기 있는 모델만 발견됩니다. |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ streams the response back **untranslated**.
## `anthropic`

**Targets:** Anthropic **Messages** (`/v1/messages`).
**Auth:** `key` (`x-api-key`) or `oauth` (Bearer + `anthropic-beta`, for Claude Pro/Max).
**Auth:** `key` (`x-api-key` by default, or `Authorization: Bearer` with `apiKeyTransport: "bearer"`) or `oauth` (Bearer + `anthropic-beta`, for Claude Pro/Max).

- Converts messages to Anthropic content blocks (text, base64 image, `tool_use`, `thinking`).
- **Extended thinking math:** Anthropic requires `max_tokens > thinking.budget_tokens`. The adapter
Expand Down
1 change: 1 addition & 0 deletions docs-site/src/content/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ or bind the forward explicitly to loopback (`ssh -L 127.0.0.1:20100:localhost:10
| `responsesPath?` | `string` | Optional relative resource path for key-auth `openai-responses` requests. It must start with `/` and contain no URL scheme, query, or fragment. When omitted, the adapter keeps its legacy `/v1/responses` URL construction. |
| `disabled?` | `boolean` | Keep the provider on disk but exclude it from routing and model/catalog listings. |
| `apiKey?` | `string` | API key, or an `${ENV_VAR}` / `$ENV_VAR` reference resolved at request time. |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API-key header style. Defaults to native `x-api-key`; set `"bearer"` for compatible gateways that require `Authorization: Bearer <key>`. Valid only for key-auth `anthropic` providers. |
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | Multi-key pool. `apiKey` mirrors the active entry; each item has `id`, `key`, optional `label`, and optional numeric `addedAt`. |
| `defaultModel?` | `string` | Model used when this provider is selected without an explicit model. |
| `models?` | `string[]` | Seed/fallback model list. When `liveModels` is `false`, these are the only discovered models. |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/ru/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ interface ProviderAdapter {
## `anthropic`

**Назначение:** Anthropic **Messages** (`/v1/messages`).
**Аутентификация:** `key` (`x-api-key`) или `oauth` (Bearer + `anthropic-beta`, для Claude Pro/Max).
**Аутентификация:** `key` (по умолчанию `x-api-key`, либо `Authorization: Bearer` при `apiKeyTransport: "bearer"`) или `oauth` (Bearer + `anthropic-beta`, для Claude Pro/Max).

- Преобразует сообщения в блоки контента Anthropic (text, base64 image, `tool_use`, `thinking`).
- **Арифметика extended thinking:** Anthropic требует `max_tokens > thinking.budget_tokens`.
Expand Down
1 change: 1 addition & 0 deletions docs-site/src/content/docs/ru/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ x-opencodex-api-key: your-secret-token
| `responsesPath?` | `string` | Необязательный относительный путь ресурса для запросов `openai-responses` с аутентификацией `key`. Должен начинаться с `/` и не содержать схему URL, query или fragment. Если поле опущено, сохраняется прежнее построение URL `/v1/responses`. |
| `disabled?` | `boolean` | Провайдер остаётся на диске, но исключается из маршрутизации и списков моделей/каталога. |
| `apiKey?` | `string` | API-ключ или ссылка `${ENV_VAR}` / `$ENV_VAR`, разрешаемая в момент запроса. |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Способ передачи API-ключа Anthropic. По умолчанию используется нативный `x-api-key`; для совместимых gateway, требующих `Authorization: Bearer <key>`, задайте `"bearer"`. Допустимо только для `anthropic` provider с key-аутентификацией. |
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | Пул из нескольких ключей. `apiKey` отражает активную запись; каждый элемент содержит `id`, `key`, необязательный `label` и необязательное числовое `addedAt`. |
| `defaultModel?` | `string` | Модель, используемая при выборе этого провайдера без явной модели. |
| `models?` | `string[]` | Список seed/fallback-моделей. Когда `liveModels` равен `false`, обнаруживаются только эти модели. |
Expand Down
2 changes: 1 addition & 1 deletion docs-site/src/content/docs/zh-cn/reference/adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface ProviderAdapter {
## `anthropic`

**目标:** Anthropic **Messages**(`/v1/messages`)。
**认证:** `key`(`x-api-key`)或 `oauth`(Bearer + `anthropic-beta`,用于 Claude Pro/Max)。
**认证:** `key`(默认 `x-api-key`,或设置 `apiKeyTransport: "bearer"` 后使用 `Authorization: Bearer`)或 `oauth`(Bearer + `anthropic-beta`,用于 Claude Pro/Max)。

- 把消息转换成 Anthropic content block(text、base64 image、`tool_use`、`thinking`)。
- **Extended thinking 计算:** Anthropic 要求 `max_tokens > thinking.budget_tokens`。adapter 把
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ x-opencodex-api-key: your-secret-token
| `responsesPath?` | `string` | `key` 认证的 `openai-responses` 请求可选相对 resource path。必须以 `/` 开头,且不得包含 URL scheme、query 或 fragment。省略时保留原有的 `/v1/responses` URL 构造。 |
| `disabled?` | `boolean` | 配置保留在磁盘上,但从路由和模型/目录列表排除。 |
| `apiKey?` | `string` | API key,或在请求时解析的 `${ENV_VAR}` / `$ENV_VAR` 引用。 |
| `apiKeyTransport?` | `"x-api-key" \| "bearer"` | Anthropic API key 的请求头方式。默认使用原生 `x-api-key`;兼容 gateway 要求 `Authorization: Bearer <key>` 时设为 `"bearer"`。仅适用于使用 key 认证的 `anthropic` provider。 |
| `apiKeyPool?` | `ApiKeyPoolEntry[]` | 多 key pool。`apiKey` 映射当前活动条目;每项包含 `id`、`key`、可选 `label` 和可选数字 `addedAt`。 |
| `defaultModel?` | `string` | 选中该 provider 但未指定明确模型时使用的模型。 |
| `models?` | `string[]` | seed/fallback 模型列表。`liveModels` 为 `false` 时,只会发现这些模型。 |
Expand Down
1 change: 1 addition & 0 deletions gui/src/components/AddProviderModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ export default function AddProviderModal({
: p.baseUrl,
authMode: p.auth,
apiKey: "",
apiKeyTransport: undefined,
defaultModel: p.defaultModel ?? "",
allowPrivateNetwork: false,
},
Expand Down
12 changes: 12 additions & 0 deletions gui/src/components/add-provider-form-pane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,18 @@ export function AddProviderFormPane({
<AddProviderField label={t("modal.apiKey")}>
<input className="input" type="password" value={form.apiKey} onChange={e => onFormChange({ ...form, apiKey: e.target.value })} placeholder={t("modal.apiKeyPlaceholder")} />
</AddProviderField>
{form.adapter === "anthropic" && form.authMode === "key" && (
<AddProviderField label={t("modal.apiKeyTransport")}>
<select
className="input"
value={form.apiKeyTransport ?? "x-api-key"}
onChange={e => onFormChange({ ...form, apiKeyTransport: e.target.value === "bearer" ? "bearer" : undefined })}
>
<option value="x-api-key">{t("modal.apiKeyTransportNative")}</option>
<option value="bearer">{t("modal.apiKeyTransportBearer")}</option>
</select>
</AddProviderField>
)}
</>
)}
{!isReservedForward && <AddProviderField label={t("modal.defaultModel")}>
Expand Down
2 changes: 1 addition & 1 deletion gui/src/components/add-provider-modal-reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export function createInitialAddProviderState(
return {
preset: initialCustom ? customPreset : null,
form: initialCustom
? { name: "", adapter: "openai-chat", baseUrl: "", authMode: "key", apiKey: "", defaultModel: "", allowPrivateNetwork: false }
? { name: "", adapter: "openai-chat", baseUrl: "", authMode: "key", apiKey: "", apiKeyTransport: undefined, defaultModel: "", allowPrivateNetwork: false }
: null,
saving: false,
error: "",
Expand Down
18 changes: 17 additions & 1 deletion gui/src/components/provider-workspace/ProviderSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function ProviderSettings({
const [baseUrl, setBaseUrl] = useState(item.baseUrl);
const [defaultModel, setDefaultModel] = useState(item.defaultModel ?? "");
const [authMode, setAuthMode] = useState(initialAuth);
const [apiKeyTransport, setApiKeyTransport] = useState(item.apiKeyTransport ?? "x-api-key");
const [note, setNote] = useState(item.note ?? "");
const [allowPrivateNetwork, setAllowPrivateNetwork] = useState(item.allowPrivateNetwork ?? false);
const [liveModels, setLiveModels] = useState(item.liveModels !== false);
Expand All @@ -55,12 +56,13 @@ export default function ProviderSettings({
setBaseUrl(item.baseUrl);
setDefaultModel(item.defaultModel ?? "");
setAuthMode(String(item.authMode ?? (item.keyOptional ? "local" : "key")));
setApiKeyTransport(item.apiKeyTransport ?? "x-api-key");
setNote(item.note ?? "");
setAllowPrivateNetwork(item.allowPrivateNetwork ?? false);
setLiveModels(item.liveModels !== false);
setMsg(null);
queueMicrotask(() => setEndpointChoice(matchChoiceId(baseUrlChoices, item.baseUrl)));
}, [item.adapter, item.baseUrl, item.defaultModel, item.authMode, item.keyOptional, item.note, item.allowPrivateNetwork, item.liveModels, baseUrlChoices]);
}, [item.adapter, item.baseUrl, item.defaultModel, item.authMode, item.apiKeyTransport, item.keyOptional, item.note, item.allowPrivateNetwork, item.liveModels, baseUrlChoices]);
/* eslint-enable react-hooks/set-state-in-effect */

useEffect(() => {
Expand Down Expand Up @@ -97,6 +99,7 @@ export default function ProviderSettings({
|| baseUrl.trim() !== item.baseUrl
|| defaultModel.trim() !== (item.defaultModel ?? "")
|| authMode !== String(item.authMode ?? (item.keyOptional ? "local" : "key"))
|| (adapter.trim() === "anthropic" && authMode === "key" && apiKeyTransport !== (item.apiKeyTransport ?? "x-api-key"))
|| note.trim() !== (item.note ?? "")
|| allowPrivateNetwork !== (item.allowPrivateNetwork ?? false)
|| liveModels !== (item.liveModels !== false);
Expand All @@ -118,6 +121,7 @@ export default function ProviderSettings({

const isPreset = isCatalogProviderId(item.name);
const hasEndpointPicker = choicesStatus === "ready" && !!(baseUrlChoices && baseUrlChoices.length > 0);
const supportsApiKeyTransport = adapter.trim() === "anthropic" && authMode === "key";
// Lock plain baseUrl for presets while loading or when there is no picker.
// On fetch error, keep it editable so allowBaseUrlOverride providers are not trapped.
const plainBaseUrlLocked = isPreset && choicesStatus !== "error";
Expand All @@ -132,6 +136,8 @@ export default function ProviderSettings({
setMsg(null);
try {
const patch: ProviderUpdatePatch = { adapter: adapter.trim(), baseUrl: nextBaseUrl, defaultModel: defaultModel.trim(), authMode, note: note.trim(), allowPrivateNetwork, liveModels };
if (supportsApiKeyTransport) patch.apiKeyTransport = apiKeyTransport;
else if (item.apiKeyTransport !== undefined) patch.apiKeyTransport = "";
const res = await onUpdateProvider(item.name, patch);
setMsg(res.ok ? { ok: true, text: t("pws.settingsSaved") } : { ok: false, text: res.error || t("prov.saveFailed") });
return res.ok;
Expand All @@ -153,6 +159,7 @@ export default function ProviderSettings({
const discard = () => {
setAdapter(item.adapter); setBaseUrl(item.baseUrl);
setDefaultModel(item.defaultModel ?? ""); setAuthMode(initialAuth);
setApiKeyTransport(item.apiKeyTransport ?? "x-api-key");
setNote(item.note ?? ""); setAllowPrivateNetwork(item.allowPrivateNetwork ?? false); setLiveModels(item.liveModels !== false); setMsg(null);
setEndpointChoice(matchChoiceId(baseUrlChoices, item.baseUrl));
};
Expand Down Expand Up @@ -233,6 +240,15 @@ export default function ProviderSettings({
</select>
)}
</label>
{supportsApiKeyTransport && (
<label className="pwi-settings-field">
<span className="pwi-settings-label">{t("modal.apiKeyTransport")}</span>
<select className="input" value={apiKeyTransport} onChange={e => setApiKeyTransport(e.target.value as "x-api-key" | "bearer")}>
<option value="x-api-key">{t("modal.apiKeyTransportNative")}</option>
<option value="bearer">{t("modal.apiKeyTransportBearer")}</option>
</select>
</label>
)}
<label className="pwi-settings-field">
<span className="pwi-settings-label">{t("pws.note")}</span>
<textarea className="input pwi-settings-textarea" value={note} onChange={e => setNote(e.target.value)} rows={2} />
Expand Down
1 change: 1 addition & 0 deletions gui/src/components/provider-workspace/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export type ProviderUpdatePatch = {
baseUrl?: string;
defaultModel?: string;
apiKey?: string;
apiKeyTransport?: "x-api-key" | "bearer" | "";
authMode?: string;
note?: string;
disabled?: boolean;
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,9 @@ export const de: Record<TKey, string> = {
"modal.localHint": "Es wird kein API-Schlüssel gespeichert. Damit wird Cursors öffentlicher Modellkatalog für Codex hinzugefügt; live Cursor-Transport und native Datei-/Shell-Ausführung bleiben deaktiviert, bis sie geprüft sind.",
"modal.getApiKey": "{label}-API-Schlüssel holen",
"modal.apiKey": "API-Schlüssel",
"modal.apiKeyTransport": "API-Schlüssel-Header",
"modal.apiKeyTransportNative": "x-api-key (Anthropic-Standard)",
"modal.apiKeyTransportBearer": "Authorization: Bearer",
"modal.apiKeyPlaceholder": "sk-… (oder $ENV_VAR)",
"modal.defaultModelPlaceholder": "z. B. gpt-5.5",
"modal.baseUrlPlaceholder": "https://...",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,9 @@ export const en = {
"modal.localHint": "No API key is stored. This adds Cursor's static public model catalog for Codex, but live Cursor transport and native file/shell execution remain disabled until audited.",
"modal.getApiKey": "Get your {label} API key",
"modal.apiKey": "API key",
"modal.apiKeyTransport": "API key header",
"modal.apiKeyTransportNative": "x-api-key (Anthropic native)",
"modal.apiKeyTransportBearer": "Authorization: Bearer",
"modal.apiKeyPlaceholder": "sk-… (or $ENV_VAR)",
"modal.defaultModelPlaceholder": "e.g. gpt-5.5",
"modal.baseUrlPlaceholder": "https://...",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,9 @@ export const ja: Record<TKey, string> = {
"modal.localHint": "API キーは保存されません。Cursor の静的な公開モデルカタログを Codex に追加しますが、ライブの Cursor トランスポートとネイティブのファイル/シェル実行は監査されるまで無効のままです。",
"modal.getApiKey": "{label} の API キーを取得",
"modal.apiKey": "API キー",
"modal.apiKeyTransport": "API キーヘッダー",
"modal.apiKeyTransportNative": "x-api-key (Anthropic 標準)",
"modal.apiKeyTransportBearer": "Authorization: Bearer",
"modal.apiKeyPlaceholder": "sk-… (または $ENV_VAR)",
"modal.defaultModelPlaceholder": "例: gpt-5.5",
"modal.baseUrlPlaceholder": "https://...",
Expand Down
3 changes: 3 additions & 0 deletions gui/src/i18n/ko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1280,6 +1280,9 @@ export const ko: Record<TKey, string> = {
"modal.localHint": "API 키는 저장되지 않습니다. Cursor의 공개 모델 카탈로그만 Codex에 추가되며, live Cursor 전송과 네이티브 파일/셸 실행은 검토 전까지 비활성입니다.",
"modal.getApiKey": "{label} API 키 받기",
"modal.apiKey": "API 키",
"modal.apiKeyTransport": "API 키 헤더",
"modal.apiKeyTransportNative": "x-api-key (Anthropic 기본)",
"modal.apiKeyTransportBearer": "Authorization: Bearer",
"modal.apiKeyPlaceholder": "sk-… (또는 $ENV_VAR)",
"modal.defaultModelPlaceholder": "예: gpt-5.5",
"modal.baseUrlPlaceholder": "https://...",
Expand Down
Loading
Loading