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
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ CODEBUDDY_LOG_LEVEL=INFO
# Optional. Per-query timeout in milliseconds. Defaults to 15000, clamped to 1000-60000.
# SEARXNG_TIMEOUT_MS=15000

# Translate downstream thinking parameters into the reasoning_effort vocabulary
# that Hy-series models expect. Disabled by default, which forwards requests
# unchanged; enabled, it maps Claude Code's thinking and Codex's
# reasoning.effort onto no_think / low / high.
# Accepts: true / false (also 1 / 0).
# CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED=false

# Models are discovered from each saved credential. No model-list setting is needed.

# Optional file-backend data directory. Default: .codebuddy_data
Expand Down
15 changes: 10 additions & 5 deletions app/settings/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,14 @@ const settingsPlaceholders: Record<string, string> = {
};

/**
* Settings rendered as a switch instead of a text input. `CODEBUDDY_WEB_SEARCH_ENABLED`
* is the only boolean in the config today; the server hides its label when no
* search backend is configured, so the UI only ever sees it when it is usable.
* Settings rendered as a switch instead of a text input. These are the boolean
* entries in the config; the server hides the web search label when no search
* backend is configured, so the UI only ever sees it when it is usable.
*/
const BOOLEAN_SETTING_KEYS = new Set(['CODEBUDDY_WEB_SEARCH_ENABLED']);
const BOOLEAN_SETTING_KEYS = new Set([
'CODEBUDDY_WEB_SEARCH_ENABLED',
'CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED',
]);

const isTruthySetting = (value: SettingsValue): boolean => {
return value === true || value === 'true' || value === '1';
Expand Down Expand Up @@ -431,7 +434,9 @@ const Settings = () => {
? translations('settingsPanel.apiTimeoutHint')
: settingKey === 'CODEBUDDY_WEB_SEARCH_ENABLED'
? translations('settingsPanel.webSearchDescription')
: undefined
: settingKey === 'CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED'
? translations('settingsPanel.hyThoughtDepthHint')
: undefined
}
key={settingKey}
label={label}
Expand Down
39 changes: 31 additions & 8 deletions docs/en/guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ Settings controls service parameters, credential models, usage data, and console

## Service settings

| Field | Purpose |
| ----------------------------------------- | ----------------------------------------------------------------- |
| CodeBuddy API endpoint | Upstream URL; default `https://copilot.tencent.com` |
| Admin passkey RP ID / domain | WebAuthn hostname only; do not include scheme or port |
| Authentication mode (auto/token) | Upstream authentication method |
| Network environment (internal/ioa/public) | Upstream network environment |
| Log level | Choose `DEBUG`, `INFO`, `WARNING`, or `ERROR` |
| API timeout, first token (minutes) | Abort a request that produces no first delta in time; default `5` |
| Field | Purpose |
| ----------------------------------------- | ------------------------------------------------------------------------------------------ |
| CodeBuddy API endpoint | Upstream URL; default `https://copilot.tencent.com` |
| Admin passkey RP ID / domain | WebAuthn hostname only; do not include scheme or port |
| Authentication mode (auto/token) | Upstream authentication method |
| Network environment (internal/ioa/public) | Upstream network environment |
| Log level | Choose `DEBUG`, `INFO`, `WARNING`, or `ERROR` |
| API timeout, first token (minutes) | Abort a request that produces no first delta in time; default `5` |
| Translate thought depth for Hy models | Convert downstream thinking parameters into the upstream `reasoning_effort`; default `off` |

Click **Save** after changing a field.

Expand All @@ -22,6 +23,28 @@ it takes. Fractional minutes are accepted, clamped to `0.1`–`1440`. Set the
equivalent `CODEBUDDY_API_TIMEOUT_MINUTES` environment variable to seed the
value before the console is ever opened.

Hy-series models (`hy3` and friends) accept only three `reasoning_effort` values
— `no_think`, `low` and `high` — and no downstream client speaks that
vocabulary: Claude Code sends Anthropic `thinking`, while Codex sends Responses
`reasoning.effort`. Enabling the setting converts both onto the Hy vocabulary:

| Downstream value | Converted to |
| -------------------------------------------- | ------------ |
| `thinking.type: disabled`, `minimal`, `none` | `no_think` |
| `budget_tokens` ≤ 8K, `low`, `medium` | `low` |
| `budget_tokens` > 8K, `high`, `xhigh`, `max` | `high` |

Any model id starting with `hy` counts as a Hy model, case-insensitively, so
`hy3` and `hy3-ioa` match today and a future `hy4` is covered without a code
change. `hunyuan-*` is a different prefix and a separate product line, so it
does not match.

Once translated, the original `thinking` block is dropped: leaving it alongside
the converted effort would ask for the same thing twice in two vocabularies, and
would still be rejected by the upstream this conversion exists to satisfy. The
setting defaults to off, which forwards requests unchanged. Seed it before the
console is opened with `CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED` (`true` / `false`).

## Models and usage

- **Credential models** lists models for each credential; edit the list or click **Refresh**.
Expand Down
32 changes: 24 additions & 8 deletions docs/guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,35 @@

填写或选择以下项目后点击「保存」:

| 页面字段 | 说明 |
| ------------------------------- | -------------------------------------------- |
| CodeBuddy 官方 API 端点 | 上游地址,默认 `https://copilot.tencent.com` |
| 管理员 Passkey RP ID / 域名 | WebAuthn 使用的 hostname,不要填写协议或端口 |
| 认证模式(auto/token) | 上游认证方式 |
| 网络环境(internal/ioa/public) | 上游网络环境 |
| 日志级别 | 选择 `DEBUG`、`INFO`、`WARNING` 或 `ERROR` |
| API 超时时间,首个 token(分钟) | 首个 delta 迟迟不返回时中断请求;默认 `5` |
| 页面字段 | 说明 |
| ------------------------------- | ----------------------------------------------------- |
| CodeBuddy 官方 API 端点 | 上游地址,默认 `https://copilot.tencent.com` |
| 管理员 Passkey RP ID / 域名 | WebAuthn 使用的 hostname,不要填写协议或端口 |
| 认证模式(auto/token) | 上游认证方式 |
| 网络环境(internal/ioa/public) | 上游网络环境 |
| 日志级别 | 选择 `DEBUG`、`INFO`、`WARNING` 或 `ERROR` |
| API 超时时间,首个 token(分钟) | 首个 delta 迟迟不返回时中断请求;默认 `5` |
| 为 Hy 系列模型转换思想深度 | 把下游思考参数转为上游的 `reasoning_effort`;默认关闭 |

API 超时时间从发起请求开始计时,直到上游返回第一个 delta,因此它限制的是「迟迟没有开始输出」的等待
时间。一旦开始输出,即使回答较长也会允许其完成。支持小数分钟,取值范围 `0.1`~`1440`。也可以在打开
控制台之前通过环境变量 `CODEBUDDY_API_TIMEOUT_MINUTES` 预设该值。

Hy 系列模型(`hy3` 等)只接受 `reasoning_effort` 的 `no_think` / `low` / `high` 三档,而下游客户端
并不使用这套词表:Claude Code 发送 Anthropic `thinking`,Codex 发送 Responses `reasoning.effort`。
开启后,本服务会把两者转换到 Hy 的词表:

| 下游取值 | 转换结果 |
| -------------------------------------------- | ---------- |
| `thinking.type: disabled`、`minimal`、`none` | `no_think` |
| `budget_tokens` ≤ 8K、`low`、`medium` | `low` |
| `budget_tokens` > 8K、`high`、`xhigh`、`max` | `high` |

模型名以 `hy` 开头即视为 Hy 模型(忽略大小写),因此 `hy3`、`hy3-ioa`、以及未来的 `hy4` 都会生效;
`hunyuan-*` 是另一个前缀、属于不同产品线,不会被匹配。转换成功后,原始的 `thinking` 字段会被移除,
避免用两种词表重复表达同一件事、也避免上游因收到不认识的结构而报错。默认关闭,即原样转发、不做任何
转换。也可以通过环境变量 `CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED` 预设(`true` / `false`)。

## 凭证模型和用量

- 「凭证模型」列出每个凭证支持的模型;可以编辑模型列表,或点击「刷新」重新获取。
Expand Down
34 changes: 26 additions & 8 deletions docs/ja/guide/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

## サービス設定

| 項目 | 用途 |
| --------------------------------------- | ------------------------------------------------------------- |
| CodeBuddy API エンドポイント | 上流 URL。既定値は `https://copilot.tencent.com` |
| 管理者 passkey RP ID / ドメイン | WebAuthn の hostname。スキームとポートは含めない |
| 認証モード(auto/token) | 上流認証方式 |
| ネットワーク環境(internal/ioa/public) | 上流ネットワーク環境 |
| ログレベル | `DEBUG`、`INFO`、`WARNING`、`ERROR` を選択 |
| API タイムアウト・最初のトークン (分) | 最初の delta が返らないリクエストを打ち切る時間。既定値は `5` |
| 項目 | 用途 |
| --------------------------------------- | -------------------------------------------------------------------------- |
| CodeBuddy API エンドポイント | 上流 URL。既定値は `https://copilot.tencent.com` |
| 管理者 passkey RP ID / ドメイン | WebAuthn の hostname。スキームとポートは含めない |
| 認証モード(auto/token) | 上流認証方式 |
| ネットワーク環境(internal/ioa/public) | 上流ネットワーク環境 |
| ログレベル | `DEBUG`、`INFO`、`WARNING`、`ERROR` を選択 |
| API タイムアウト・最初のトークン (分) | 最初の delta が返らないリクエストを打ち切る時間。既定値は `5` |
| Hy モデルの思考深度を変換する | 下流の思考パラメーターを上流の `reasoning_effort` へ変換する。既定値は無効 |

変更後に「保存」を押します。

Expand All @@ -20,6 +21,23 @@ API タイムアウトは、リクエスト送信から上流が最初の delta
完了まで許可されます。小数分を指定でき、`0.1`〜`1440` に制限されます。コンソールを開く前に値を
設定する場合は、環境変数 `CODEBUDDY_API_TIMEOUT_MINUTES` を使用してください。

Hy モデル(`hy3` など)は `reasoning_effort` の `no_think` / `low` / `high` のみを受け付けますが、
下流クライアントはこの語彙を使いません。Claude Code は Anthropic の `thinking` を、Codex は
Responses の `reasoning.effort` を送信します。この設定を有効にすると、両者を Hy の語彙へ変換します。

| 下流の値 | 変換結果 |
| -------------------------------------------- | ---------- |
| `thinking.type: disabled`、`minimal`、`none` | `no_think` |
| `budget_tokens` ≤ 8K、`low`、`medium` | `low` |
| `budget_tokens` > 8K、`high`、`xhigh`、`max` | `high` |

モデル名が `hy` で始まるものはすべて Hy モデルとして扱います(大文字小文字を無視)。そのため `hy3` や
`hy3-ioa` は一致し、将来の `hy4` もコード変更なしで対象になります。`hunyuan-*` は別の接頭辞・別の
製品系列のため一致しません。変換できた場合、元の `thinking` フィールドは削除されます。同じ内容を
2 つの語彙で二重に指定することを避け、この変換が対象とする上流での拒否も防ぐためです。既定値は
無効で、リクエストはそのまま転送されます。コンソールを開く前に環境変数
`CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED` で設定できます(`true` / `false`)。

## モデルと使用量

- 「認証情報モデル」ではモデル一覧を編集するか、「更新」を押して再取得します。
Expand Down
45 changes: 45 additions & 0 deletions lib/server/domain/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,33 @@ export interface RuntimeConfig {
CODEBUDDY_LOG_LEVEL: string;
CODEBUDDY_API_TIMEOUT_MINUTES: number;
CODEBUDDY_WEB_SEARCH_ENABLED: boolean;
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: boolean;
}

/**
* Hy-series models take their thinking depth as `reasoning_effort` with the
* values `no_think` / `low` / `high` — a vocabulary no downstream client
* speaks. Claude Code sends Anthropic `thinking`, Codex sends Responses
* `reasoning.effort`. When this is on, those are translated onto the Hy
* vocabulary; when off, requests are forwarded exactly as they arrive.
*/

/**
* Every model id starting with `hy` is a Hy-series model and takes the
* `reasoning_effort` vocabulary, so matching is a single case-insensitive
* prefix test rather than an enumeration of known ids: the upstream decides
* which models exist, and new `hy*` releases should be covered without a code
* change. `hunyuan-*` is a different prefix and a separate product line, so it
* is not affected.
*/
export const HY_MODEL_PREFIX = 'hy';

export const isHyModel = (model: string | undefined | null): boolean => {
if (typeof model !== 'string') return false;

return model.trim().toLowerCase().startsWith(HY_MODEL_PREFIX);
};

/**
* Budget for a proxied request to produce its first delta, in minutes. It is
* deliberately generous: a slow model that is thinking still has to clear it,
Expand All @@ -44,6 +69,7 @@ const DEFAULT_CONFIG: RuntimeConfig = {
CODEBUDDY_LOG_LEVEL: 'INFO',
CODEBUDDY_API_TIMEOUT_MINUTES: DEFAULT_API_TIMEOUT_MINUTES,
CODEBUDDY_WEB_SEARCH_ENABLED: false,
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: false,
};
let configMutationQueue: Promise<void> = Promise.resolve();

Expand All @@ -59,6 +85,7 @@ const SETTING_LABELS_BY_LOCALE: Record<
CODEBUDDY_LOG_LEVEL: 'Log level',
CODEBUDDY_API_TIMEOUT_MINUTES: 'API timeout, first token (minutes)',
CODEBUDDY_WEB_SEARCH_ENABLED: 'Enable local web search',
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: 'Translate thought depth for Hy models',
},
'ja-JP': {
CODEBUDDY_API_ENDPOINT: 'CodeBuddy API エンドポイント',
Expand All @@ -68,6 +95,7 @@ const SETTING_LABELS_BY_LOCALE: Record<
CODEBUDDY_LOG_LEVEL: 'ログレベル',
CODEBUDDY_API_TIMEOUT_MINUTES: 'API タイムアウト・最初のトークン (分)',
CODEBUDDY_WEB_SEARCH_ENABLED: 'ローカル Web 検索を有効化',
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: 'Hy モデルの思考深度を変換する',
},
'zh-CN': {
CODEBUDDY_API_ENDPOINT: 'CodeBuddy 官方 API 端点',
Expand All @@ -77,6 +105,7 @@ const SETTING_LABELS_BY_LOCALE: Record<
CODEBUDDY_LOG_LEVEL: '日志级别',
CODEBUDDY_API_TIMEOUT_MINUTES: 'API 超时时间,首个 token(分钟)',
CODEBUDDY_WEB_SEARCH_ENABLED: '启用本地 WebSearch',
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: '为 Hy 系列模型转换思想深度',
},
};

Expand Down Expand Up @@ -217,6 +246,11 @@ export const getActiveConfig = async (): Promise<RuntimeConfig> => {
persisted.CODEBUDDY_WEB_SEARCH_ENABLED ??
process.env.CODEBUDDY_WEB_SEARCH_ENABLED,
),
CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED: normalizeValue(
'CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED',
persisted.CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED ??
process.env.CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED,
),
};
};

Expand Down Expand Up @@ -269,6 +303,17 @@ export const getApiFirstDeltaTimeoutMs = async (): Promise<number> => {
return config.CODEBUDDY_API_TIMEOUT_MINUTES * MINUTE_MS;
};

/**
* Whether downstream thinking parameters should be translated onto the Hy
* vocabulary. Resolved per request so toggling the setting in the console takes
* effect immediately.
*/
export const getHyThoughtDepthEnabled = async (): Promise<boolean> => {
const config = await getActiveConfig();

return config.CODEBUDDY_HY_THOUGHT_DEPTH_ENABLED;
};

export const getCodeBuddyApiEndpoint = async (): Promise<string> => {
const config = await getActiveConfig();
const explicit = config.CODEBUDDY_API_ENDPOINT.trim();
Expand Down
Loading
Loading