From 451bdb572c68a6a93f0f0542c7ddb03c857d1ee5 Mon Sep 17 00:00:00 2001 From: musi Date: Tue, 30 Jun 2026 22:27:16 +0800 Subject: [PATCH] Expand configuration docs for dashboard, keys, and providers --- docs/src/content/docs/en/configuration.md | 8 +- .../content/docs/en/configuration/api-keys.md | 52 ++++ .../content/docs/en/configuration/overview.md | 59 ++++ .../docs/en/configuration/providers.md | 134 +++++++- .../content/docs/en/configuration/server.md | 32 ++ .../src/content/docs/en/configuration/tray.md | 45 +++ docs/src/content/docs/en/index.md | 4 +- docs/src/content/docs/zh/configuration.md | 8 +- .../content/docs/zh/configuration/api-keys.md | 52 ++++ .../content/docs/zh/configuration/overview.md | 59 ++++ .../content/docs/zh/configuration/provider.md | 134 +++++++- .../content/docs/zh/configuration/server.md | 32 ++ .../src/content/docs/zh/configuration/tray.md | 45 +++ docs/src/content/docs/zh/index.md | 4 +- docs/src/i18n/content.ts | 20 +- docs/src/pages/configuration.astro | 17 +- docs/src/pages/configuration/[slug].astro | 4 + docs/src/pages/en/configuration.astro | 17 +- docs/src/pages/en/configuration/[slug].astro | 4 + .../pages/home/components/providers.tsx | 2 +- .../pages/home/components/virtual-models.tsx | 285 +++++++++++++++--- src/renderer/pages/home/shared/i18n.tsx | 6 + .../pages/home/shared/virtual-models.ts | 137 ++++++--- tests/renderer/virtual-models.test.ts | 47 +++ 24 files changed, 1080 insertions(+), 127 deletions(-) create mode 100644 docs/src/content/docs/en/configuration/api-keys.md create mode 100644 docs/src/content/docs/en/configuration/overview.md create mode 100644 docs/src/content/docs/en/configuration/server.md create mode 100644 docs/src/content/docs/en/configuration/tray.md create mode 100644 docs/src/content/docs/zh/configuration/api-keys.md create mode 100644 docs/src/content/docs/zh/configuration/overview.md create mode 100644 docs/src/content/docs/zh/configuration/server.md create mode 100644 docs/src/content/docs/zh/configuration/tray.md create mode 100644 tests/renderer/virtual-models.test.ts diff --git a/docs/src/content/docs/en/configuration.md b/docs/src/content/docs/en/configuration.md index dd828f84..36f1c24b 100644 --- a/docs/src/content/docs/en/configuration.md +++ b/docs/src/content/docs/en/configuration.md @@ -2,7 +2,7 @@ title: Claude Code Router Detailed Configuration pageTitle: Detailed Configuration eyebrow: Detailed Configuration -lead: Configure providers, routing, Agent Config, Fusion, Bots, and the config database location in detail. +lead: Configure the overview dashboard, API keys, server, providers, routing, Agent Config, Fusion, Bots, tray, and the config database location in detail. --- ## Page Structure @@ -11,6 +11,9 @@ Detailed configuration docs are split into standalone pages. Every left-sidebar | Page | Covers | | --- | --- | +| Overview Dashboard | System status, account balance, usage widgets, layout editing, and share cards | +| API Keys | Client access keys, expiration, and local limits | +| Server | Host, port, proxy mode, system proxy, network capture, and CA certificate | | Provider Config | Upstream services, protocol, Base URL, model list, and credentials | | One click import | Provider deeplink protocol, manifest import, one-click import buttons, and security boundaries | | Routing Config | Default routing, conditional rules, fallback, and request rewrites | @@ -19,8 +22,9 @@ Detailed configuration docs are split into standalone pages. Every left-sidebar | Agent Config | Agent launch method, model, scope, multi-instance launching, and Bot binding | | Extension Mechanism | Wrapper plugins, core gateway plugins, custom extension creation, and debugging | | Bots And IM Agent Relay | Bot forwarding, handoff mode, and platform pages | +| Tray Configuration | Tray icon, balance progress, and tray window widgets | | Config Database Location | SQLite config database location maintained by the desktop app | ## Content Relationships -Provider Config and One click import cover how upstream model services enter CCR. Routing determines where model requests go. Agent Config covers Claude Code, Codex, and ZCode launch, multi-instance usage, and model selection. Fusion covers vision, web search, and MCP tools. Extension Mechanism covers local plugin creation, installation, and debugging. Bots cover IM platform relay. +Overview Dashboard shows system status and usage. API Keys control client access to CCR. Server controls the local gateway listener and proxy features. Provider Config and One click import cover how upstream model services enter CCR. Routing determines where model requests go. Agent Config covers Claude Code, Codex, and ZCode launch, multi-instance usage, and model selection. Fusion covers vision, web search, and MCP tools. Extension Mechanism covers local plugin creation, installation, and debugging. Bots cover IM platform relay. Tray Configuration covers the menu bar icon and tray window. diff --git a/docs/src/content/docs/en/configuration/api-keys.md b/docs/src/content/docs/en/configuration/api-keys.md new file mode 100644 index 00000000..766e5889 --- /dev/null +++ b/docs/src/content/docs/en/configuration/api-keys.md @@ -0,0 +1,52 @@ +--- +title: API Keys +pageTitle: API Keys +eyebrow: Detailed Configuration +lead: Manage API keys that clients use to access the CCR gateway, with expiration and local limits. +--- + +## Basic Concept + +The API Keys page manages client access keys for CCR. These keys are different from provider `API key` values and provider credential pools: API Keys control who can call CCR; provider keys control how CCR calls upstream providers. + +When API keys are configured, clients should send `Authorization: Bearer ` or `x-api-key: `. + +## List Fields + +| Field | Capability | +| --- | --- | +| Search API keys | Filters the list by key name or key value. | +| Add API key | Opens the create dialog and generates a new client access key. | +| Name | Display name for the key. Use it to identify a client, team, purpose, or automation. | +| Key | Masked access key. Use `Copy API key` to copy the full key. | +| Expires | Expiration time. After expiration, clients can no longer use the key to access CCR. | +| Limits | Local limit summary. Shows `No limits configured` when no limits are set. | +| Edit API key | Edits expiration and limits. The key value itself is not shown again. | +| Remove API key | Deletes the client access key. Deleted keys stop working immediately. | + +## Create And Edit + +| Field | Capability | +| --- | --- | +| Name | Display name for the new key. Examples: `Claude Code - laptop`, `CI`, or a team name. | +| Expiration | Selects the validity period: `Never`, `7 days`, `30 days`, `90 days`, or `Custom`. | +| Expires at | Appears for `Custom` expiration and sets the exact date and time. | +| API key created | Confirmation dialog after creation. It displays the full key. | +| Copy this key now. It may not be shown again. | Reminder to copy the key immediately because CCR will not show it again after the dialog closes. | + +## Advanced Settings + +`Advanced settings` adds local limits to a client key. When a limit is reached, requests using that key are rejected or limited; provider-side quota is not changed. + +| Field | Capability | +| --- | --- | +| Advanced settings | Expands or collapses limit editing. | +| No limits configured | The key has no local limits. | +| Requests | Limits by request count. | +| Tokens | Limits by token count. | +| Images | Limits by image count. | +| per minute | Uses a 1-minute limit window. | +| per hour | Uses a 1-hour limit window. | +| per day | Uses a 1-day limit window. | +| Add limit | Adds one limit rule. | +| Remove limit | Removes the current limit rule. | diff --git a/docs/src/content/docs/en/configuration/overview.md b/docs/src/content/docs/en/configuration/overview.md new file mode 100644 index 00000000..9f07d509 --- /dev/null +++ b/docs/src/content/docs/en/configuration/overview.md @@ -0,0 +1,59 @@ +--- +title: Overview Dashboard +pageTitle: Overview Dashboard +eyebrow: Detailed Configuration +lead: Customize the CCR home dashboard for system status, account balance, requests, tokens, cost, model distribution, and share cards. +--- + +## Basic Concept + +Overview is the CCR dashboard. It turns gateway status, provider accounts, request usage, and analysis results into draggable widgets. You can switch the time range, edit widgets, resize them, change styles, and generate shareable cards from selected data. + +Overview depends on request logs, usage stats, and provider account usage. Some widgets require Request logs or Agent observability to be enabled in Settings. Account balance widgets require `Fetch usage` on providers. + +## Top Controls + +| Field | Capability | +| --- | --- | +| Usage over time | Changes the statistics range used by the dashboard. | +| Today / 24h / 7d / 30d | Available time windows. Widgets recalculate requests, tokens, cost, and trends for the selected range. | +| Edit widgets | Enters layout editing mode. | +| Reset layout | Restores the default overview layout. | +| Done | Leaves editing mode and keeps the current widget configuration. | + +## Widget Editing + +In editing mode, the left `Components` panel adds widgets, the middle `Preview` panel shows the current layout, and the right `Component properties` panel edits the selected widget. + +| Field | Capability | +| --- | --- | +| Components | List of widgets that can be added. | +| Preview | Current dashboard layout. Widgets can be dragged to reorder. | +| Component properties | Configuration for the selected widget. | +| Component category | Changes the widget category, such as status, account, metric, trend, activity, breakdown, analysis, or share card. | +| Data | Selects the data shown by the widget, such as requests, tokens, cost, account, client analysis, or provider analysis. | +| Widget size | Controls the widget's grid width and height. | +| Style | Changes visual style, such as cards, compact, bar, line, ring, and more. | +| Remove widget | Removes the selected widget from the overview. | + +## Widget Types + +| Widget | Capability | +| --- | --- | +| Status component | Shows a system status timeline for recent gateway health. | +| Account component | Shows provider account balance, quota, or usage. Requires provider `Fetch usage`. | +| Metric component | Shows requests, total tokens, input tokens, output tokens, cache tokens, cache ratio, estimated cost, success rate, errors, or average latency. | +| Trend component | Shows usage trend over time. | +| Activity component | Shows token activity as a heatmap. | +| Breakdown component | Shows Token mix or Model distribution. | +| Analysis component | Shows Client Analysis or Provider Analysis. | +| Share card | Generates shareable PNG cards such as AI Usage Wrapped, CCR Route Map, Model Leaderboard, AI Fuel Cockpit, Token Calendar Poster, and Spend Receipt. | + +## Data Sources + +| Data | Source | +| --- | --- | +| Requests, tokens, cost, success rate, latency | Request logs and usage stats. | +| Account balance, quota, status messages | Provider `Fetch usage` configuration. | +| Client analysis, provider analysis, model distribution | Client, provider, model, and token data from request logs. | +| Agent analysis data | Agent observability settings and agent execution traces. | diff --git a/docs/src/content/docs/en/configuration/providers.md b/docs/src/content/docs/en/configuration/providers.md index 4a7830ba..2a6716ca 100644 --- a/docs/src/content/docs/en/configuration/providers.md +++ b/docs/src/content/docs/en/configuration/providers.md @@ -7,20 +7,130 @@ lead: Configure upstream model services, credentials, protocols, base URLs, and ## Basic Concept -A provider is an upstream model service. CCR needs at least one provider with a valid protocol, Base URL, model list, and credential. +A provider is an upstream model service. One provider config describes the upstream address, protocol capabilities, model list, authentication, optional multi-key rotation, and optional account usage fetching. + +Each provider needs at least a name, API endpoint, usable protocol, model list, and one valid credential. The add/edit dialog changes which fields are visible depending on preset providers, custom endpoints, local agent login import, and advanced settings. + +Preset providers fill common endpoints, protocols, models, and usage-fetching settings, so they are the recommended starting point. For custom providers, enter the endpoint manually. CCR uses the endpoint and API key to probe protocol compatibility and help identify whether the upstream works with OpenAI Chat, OpenAI Responses, Anthropic Messages, or Gemini Generate. + +## Main Fields + +| Field | Capability | +| --- | --- | +| Select preset provider | Applies a built-in provider template, including default endpoint, supported protocols, default models, icon, provider website, and sometimes account usage settings. Choose `Other / custom API endpoint` for any OpenAI, Anthropic, or Gemini compatible upstream. | +| Import local agent login | Appears while adding a provider if CCR finds usable Claude Code, Codex, or ZCode login state on this computer. Importing creates a provider and provider plugin that reuse the local login credential instead of a normal pasted API key. | +| Name | Internal CCR display name. It is also used by routing, model selectors, logs, and config references. Names must be unique. | +| API endpoint | Upstream API base URL. It controls where requests are sent, and is also used for protocol probing, model discovery, icon detection, and safety checks. Preset providers hide it by default while adding, but it can be overridden in Advanced settings. Custom providers must provide it. | +| API key | Default provider credential. When the credential pool is empty, model requests use this key. Protocol probing, model discovery, connection checks, and default usage fetching also use it. Only use a key issued for the selected endpoint. | +| Models | Model IDs exposed by CCR. Routing rules, profile model selectors, the model catalog, and client `/models` responses all use this list. | +| Search models / All / Clear | When CCR can discover models from the upstream or catalog, you can search, select all, clear, and choose models. Selected models are saved to the provider. | +| Custom models | Manually adds model IDs that discovery did not return. Use this when the provider lacks a `/models` endpoint or a new model is not in the catalog yet. | +| Check Connection | Sends real test requests with the current endpoint, API key, protocol, and selected models. It verifies key, model name, and protocol usability. | +| Models to check | Model selection inside the connection-check confirmation dialog. Use it to test only some models. | +| Check results | Shows whether each model is available, which protocol matched, and the upstream diagnostic message. Passing results do not automatically add models; the main model selection remains authoritative. | + +## Connectivity Checks + +`Check Connection` sends real model requests for the models you select. It verifies whether the endpoint, API key, protocol, and model IDs are usable. The check limits generated output, but it can still create extra token usage or count against provider-side request limits. + +If the provider bills by request, input tokens, or output tokens, select only the models you need to verify instead of checking every model at once. Check results are diagnostic only; they do not automatically change the model list or usage-fetching settings. ## Credentials -Credentials store API keys. Multiple credentials can rotate by priority and weight, and can switch when a key hits a limit or fails. +`API key` is the simplest single-key setup. For multiple upstream keys, expand `Credential pool` in Advanced settings. -Use recognizable labels so failed keys are easy to identify in Logs. - -## Provider Options - -| Field | Description | +| Field | Capability | | --- | --- | -| Name | Internal display name in CCR; keep it short and recognizable | -| Base URL | Upstream service address; custom providers should include the correct API path | -| Protocol | OpenAI, Anthropic, Gemini, or compatible protocol | -| Models | Model list exposed to CCR selectors | -| Request headers | Extra headers required by some compatible services | +| Show credential settings | Expands or collapses credential pool editing. Collapsing does not remove saved credentials. | +| Import JSON | Imports credentials from a JSON file. CCR accepts a top-level array, or an object with a `credentials`, `keys`, or `apiKeys` array. | +| Add key | Adds one upstream API key row. | +| Enable | Controls whether this credential participates in request forwarding and usage fetching. Disabled credentials are kept but not selected. | +| Name | Display name for the credential. It appears in account usage, logs, and diagnostics, so use a recognizable purpose or quota source. | +| API key | The actual key sent to the upstream for this credential. When a credential pool is configured, CCR expands enabled credentials into internal upstream targets and prefers the pool over the main form API key for model requests. | +| Remove | Deletes the credential row. | +| Advanced key options | Expands per-key scheduling and limit fields. | +| Priority | Credential priority. Lower numbers are tried first. If omitted, the row order is used. | +| Weight | Tie-break weight among credentials with the same priority and similar usage. Higher numbers are preferred. Defaults to `1`. | +| Limits JSON | Local limit rules for this key. CCR tracks request, token, or image usage windows and skips a key once it would exceed its limit, then tries another key on the same provider. | + +Common `Limits JSON` fields: + +| Field | Meaning | +| --- | --- | +| `rpm` / `rph` / `rpd` | Max requests per minute / hour / day | +| `tpm` / `tph` / `tpd` | Max tokens per minute / hour / day | +| `ipm` / `iph` / `ipd` | Max images per minute / hour / day | +| `maxRequests` + `windowMs` | Max requests in a custom time window | +| `maxTokens` + `quotaWindowMs` | Max tokens in a custom time window | + +Example: + +```json +{ + "rpm": 60, + "tpm": 100000 +} +``` + +The credential pool is an upstream provider key pool. It is separate from the client access keys configured on the API Keys page. + +## Usage Fetching + +`Fetch usage` lets CCR show balance, subscription quota, status, and messages in the provider list, tray, and account panels. It does not affect whether models can be requested. + +| Field | Capability | +| --- | --- | +| Fetch usage | Enables or disables account usage fetching for this provider. | +| Usage mode | Usage connector mode. `Standard usage endpoint` uses CCR standard account endpoints; `HTTP JSON request` maps a custom JSON endpoint; `Raw connector JSON` edits the connector array directly. | +| Refresh interval ms | Usage refresh interval in milliseconds. Empty uses the default interval. The minimum effective interval is 30000ms. | + +### Standard Usage Endpoint + +This mode tries provider-hosted CCR account endpoints such as `/.well-known/ccr/account` and `/v1/account/limits`. It is best for providers or presets that already implement CCR's standard account format. + +### HTTP JSON Request + +Use this mode when the provider has a balance or quota JSON endpoint that does not match CCR's standard account format. + +| Field | Capability | +| --- | --- | +| Method | Usage request method, `GET` or `POST`. | +| Usage request URL | Usage endpoint URL. It can be a full URL. The request includes the provider API key unless changed through raw connector JSON. | +| Headers | Extra headers for the usage endpoint. Avoid hard-coding sensitive auth headers here; prefer provider API key auth. | +| Body | `POST` request body. Must be valid JSON. | +| Balance remaining field | JSON path for remaining balance. | +| Balance total field | JSON path for total balance or total credits. | +| Balance used field | JSON path for used balance. | +| Balance unit | Balance unit, such as `USD`, `CNY`, or `%`. | +| Subscription remaining field | JSON path for remaining subscription, token, quota, or package amount. | +| Subscription limit field | JSON path for subscription, token, quota, or package limit. | +| Subscription reset field | JSON path for reset time. It may resolve to an ISO string, seconds timestamp, or milliseconds timestamp. | +| Subscription unit | Subscription unit, such as `tokens`, `requests`, or `hours`. | +| Status field | JSON path for account status. Supported values are `ok`, `warning`, `critical`, `error`, and `unsupported`. | +| Message field | JSON path for account message. Useful for provider errors, plan notes, or risk-control messages. | +| Test usage request | Requests and parses the usage endpoint before saving. | +| Response fields | Lists selectable paths from the response. Buttons such as `Balance rem`, `Balance total`, `Balance used`, `Sub rem`, `Sub limit`, and `Reset` fill the matching field. | + +Field paths use CCR's lightweight JSONPath syntax: + +| Syntax | Meaning | +| --- | --- | +| `$` | Whole response object | +| `$.balance.remaining` | Object field | +| `$.items[0].value` | Array index | +| `$["weird-key"]` | Field name with special characters | +| `$.limits[?(@.type=="TOKENS")].remaining` | First array item matching simple equality filters | +| `100 - $.data.percentage` | Numeric subtraction expression, often used to convert used percent into remaining percent | + +### Raw Connector JSON + +`Connectors JSON` edits the `account.connectors` array directly for more complex provider setups. + +| Connector type | Capability | +| --- | --- | +| `standard` | Uses CCR standard account endpoints. | +| `http-json` | Requests a JSON endpoint and maps balance, subscription, status, and message fields. | +| `plugin` | Calls an account usage connector registered by an installed plugin. | +| `local-estimate` | Shows estimated quota from local time-window config without a remote request. | + +`Insert example` fills an example connector array containing `standard`, `http-json`, `plugin`, and `local-estimate` connectors. diff --git a/docs/src/content/docs/en/configuration/server.md b/docs/src/content/docs/en/configuration/server.md new file mode 100644 index 00000000..8742de93 --- /dev/null +++ b/docs/src/content/docs/en/configuration/server.md @@ -0,0 +1,32 @@ +--- +title: Server +pageTitle: Server +eyebrow: Detailed Configuration +lead: Configure the CCR gateway host, port, and Proxy mode for MITM interception and proxying into CCR. +--- + +## Basic Concept + +The Server page controls how the local CCR gateway listens for requests. Normal model requests usually need only `Host` and `Port`. + +## Main Fields + +| Field | Capability | +| --- | --- | +| Host | Host address the CCR gateway listens on. Common values are `127.0.0.1` and `0.0.0.0`. | +| Port | Gateway listening port. Clients should point their API base URL to this port. | + +## Proxy Mode + +Proxy mode is the local proxy capability. When enabled, clients can send HTTP/HTTPS traffic to CCR. CCR uses MITM interception to identify and decrypt HTTPS requests, then proxies supported model requests into the CCR gateway path. + +| Field | Capability | +| --- | --- | +| Proxy mode | Enables Proxy mode. CCR can receive client traffic as an HTTP/HTTPS proxy and use MITM interception to proxy model requests into CCR. | +| System proxy | Points the system proxy at CCR so apps that honor system proxy settings can go through CCR automatically. | +| Capture network | Stores network requests that pass through proxy mode so the Networking page can show request and response details. | +| CA certificate | Trust status of the current proxy CA certificate. | +| Install CA | Installs the CCR proxy CA into the system or user trust store. Installation differs by OS. | +| Check Trust | Checks again whether the proxy CA is trusted by the system. | +| Proxy status | Shows whether the proxy service is running. | +| Restart Proxy | Restarts the proxy service when proxy mode is enabled. | diff --git a/docs/src/content/docs/en/configuration/tray.md b/docs/src/content/docs/en/configuration/tray.md new file mode 100644 index 00000000..c8566660 --- /dev/null +++ b/docs/src/content/docs/en/configuration/tray.md @@ -0,0 +1,45 @@ +--- +title: Tray Configuration +pageTitle: Tray Configuration +eyebrow: Detailed Configuration +lead: Configure the CCR system tray icon, balance progress, and tray window widgets. +--- + +## Basic Concept + +Tray settings live under Settings. They control the system tray icon and the tray window. The tray window can show providers, account balance, token trends, activity, metrics, and model share so you can check CCR status without opening the main window. + +## Top Fields + +| Field | Capability | +| --- | --- | +| Tray mascot | Selects the tray icon style. Options include `Random`, `Auralis`, `Solara`, `Vesper`, and `Balance progress`. | +| Balance progress | Uses provider account usage as tray icon progress. Requires `Fetch usage` on a provider first. | +| Account | Selects the provider account used for balance progress. | +| Data | Selects the balance, subscription, or quota meter used as the progress source. | + +If no account data is available, the page shows `No account data is available. Enable account monitoring on a provider first.` This usually means no provider has `Fetch usage` enabled, or usage fetching has not succeeded yet. + +## Tray Window Layout + +| Area | Capability | +| --- | --- | +| Components | Left-side component palette for adding or enabling tray window widgets. | +| Preview | Middle preview area showing the current tray window layout. Widgets can be dragged to reorder. | +| Component properties | Right-side editor for the selected widget's `Style`, or for removing the widget. | + +## Component Types + +| Component | Capability | +| --- | --- | +| Provider component | Shows `Provider tabs` for switching provider data in the tray window. It is a singleton component and can be enabled only once. | +| Header component | Shows `Title and status`. It is a singleton component and can be enabled only once. | +| Account component | Shows `Account balance`. Multiple account components can be added with different styles. | +| Trend component | Shows `Token flow chart`. | +| Activity component | Shows `Token activity`. | +| Metric component | Shows `Token stats`. | +| Breakdown component | Shows `Token mix`, `Circular metrics`, or `Model share`. | + +## Styles + +Different components support different `Style` options. Common styles include `Cards`, `Compact`, `List`, `Pills`, `Line`, `Area`, `Bar`, `Ring`, `Donut`, `Gauges`, `Sparkline`, and `Stacked`. Style changes only affect the tray display; they do not change routing, providers, or usage stats. diff --git a/docs/src/content/docs/en/index.md b/docs/src/content/docs/en/index.md index a6284322..97ac4036 100644 --- a/docs/src/content/docs/en/index.md +++ b/docs/src/content/docs/en/index.md @@ -26,7 +26,7 @@ The top navigation is split into four standalone pages: | --- | --- | | [Documentation](./) | Product positioning, architecture overview, and reading path | | [Quick Start](guides/) | From installation and provider setup to connecting an agent | -| [Detailed Configuration](configuration/) | Providers, routing, Agent Config, Fusion, Bots, and config database location | +| [Detailed Configuration](configuration/providers/) | Overview dashboard, API keys, server, providers, routing, Agent Config, Fusion, Bots, tray, and config database location | | [Q&A](troubleshooting/) | Request logs, observability panel, and common questions | Bot platform guides are child pages under Detailed Configuration. Each platform has its own page so platform dashboard fields, callback URLs, signatures, and FAQs can be expanded independently. @@ -37,5 +37,5 @@ If this is your first time using CCR: 1. Start with [Quick Start](guides/) to connect a provider and Agent Config. 2. Use the app's request logs to confirm whether requests are passing through CCR. -3. Open [Detailed Configuration](configuration/) for vision, web search, MCP tools, and IM relay. +3. Open [Detailed Configuration](configuration/providers/) for the overview dashboard, API keys, server, providers, vision, web search, MCP tools, tray, and IM relay. 4. Use [Q&A](troubleshooting/) for 401, 404, timeout, wrong-routing, or Bot delivery questions. diff --git a/docs/src/content/docs/zh/configuration.md b/docs/src/content/docs/zh/configuration.md index 8cc3c8e2..26df10a5 100644 --- a/docs/src/content/docs/zh/configuration.md +++ b/docs/src/content/docs/zh/configuration.md @@ -2,7 +2,7 @@ title: Claude Code Router 详细配置 pageTitle: 详细配置 eyebrow: 详细配置 -lead: 深入配置供应商、路由、Agent配置、Fusion、Bot 和配置数据库位置。这里是按功能查字段和扩展能力的地方。 +lead: 深入配置概览仪表盘、API 密钥、服务、供应商、路由、Agent配置、Fusion、Bot、托盘和配置数据库位置。这里是按功能查字段和扩展能力的地方。 --- ## 页面结构 @@ -11,6 +11,9 @@ lead: 深入配置供应商、路由、Agent配置、Fusion、Bot 和配置数 | 页面 | 内容 | | --- | --- | +| 概览仪表盘 | 系统状态、账户余额、用量组件、布局编辑和分享卡片 | +| API 密钥 | 客户端访问 Key、过期时间和本地限额 | +| 服务配置 | Host、Port、代理模式、系统代理、网络捕获和 CA 证书 | | 供应商配置 | 上游服务、协议、基础 URL、模型列表和凭据 | | 一键导入供应商 | Provider deeplink 协议、Manifest 导入、一键导入按钮和安全边界 | | 路由配置 | 默认路由、条件规则、fallback 和请求改写 | @@ -19,8 +22,9 @@ lead: 深入配置供应商、路由、Agent配置、Fusion、Bot 和配置数 | Agent配置 | Agent 启动方式、模型、作用范围、多开和 Bot 绑定 | | 扩展机制 | Wrapper plugin、Core gateway plugin、自定义扩展创建和调试 | | Bot 与 IM 接力 Agent | Bot 转发、接力模式和平台页面 | +| 托盘配置 | 托盘图标、余额进度条和托盘窗口组件 | | 配置数据库位置 | 桌面 App 维护的 SQLite 配置数据库位置 | ## 内容关系 -供应商配置和一键导入供应商页面覆盖上游模型服务如何进入 CCR;路由决定模型请求的上游去向;Agent配置页面覆盖 Claude Code、Codex 和 ZCode 的启动、多开与模型选择;Fusion 页面覆盖图像、搜索和 MCP 工具;扩展机制页面覆盖本地插件的创建、安装和调试;Bot 页面覆盖 IM 平台接力。 +概览仪表盘用于查看系统状态和用量;API 密钥控制客户端访问 CCR;服务配置控制本地网关监听和代理能力;供应商配置和一键导入供应商页面覆盖上游模型服务如何进入 CCR;路由决定模型请求的上游去向;Agent配置页面覆盖 Claude Code、Codex 和 ZCode 的启动、多开与模型选择;Fusion 页面覆盖图像、搜索和 MCP 工具;扩展机制页面覆盖本地插件的创建、安装和调试;Bot 页面覆盖 IM 平台接力;托盘配置覆盖菜单栏图标和托盘窗口。 diff --git a/docs/src/content/docs/zh/configuration/api-keys.md b/docs/src/content/docs/zh/configuration/api-keys.md new file mode 100644 index 00000000..70e61ffa --- /dev/null +++ b/docs/src/content/docs/zh/configuration/api-keys.md @@ -0,0 +1,52 @@ +--- +title: API 密钥 +pageTitle: API 密钥 +eyebrow: 详细配置 +lead: 管理客户端访问 CCR 网关时使用的 API Key,并为每个 Key 设置过期时间和本地限额。 +--- + +## 基本概念 + +“API 密钥”页面管理的是客户端访问 CCR 时使用的访问 Key。它不同于供应商配置里的 `API 密钥` 或 `凭据池`:这里的 Key 用来控制谁能调用 CCR;供应商 Key 用来控制 CCR 调用上游供应商。 + +如果配置了 API Key,客户端请求需要带 `Authorization: Bearer ` 或 `x-api-key: `。 + +## 列表字段 + +| 字段 | 代表的能力 | +| --- | --- | +| 搜索 API 密钥 | 按名称或 Key 内容过滤列表。 | +| 添加 API 密钥 | 打开创建弹窗,生成新的客户端访问 Key。 | +| 名称 | API Key 的显示名,用于区分客户端、团队、用途或自动化来源。 | +| Key | 脱敏后的访问 Key。可以点击 `复制 API 密钥` 复制完整 Key。 | +| 过期 | 当前 Key 的过期时间。过期后客户端不能继续使用这个 Key 访问 CCR。 | +| 限制 | 当前 Key 的本地限额摘要。没有配置限额时显示“未配置限制”。 | +| 编辑 API 密钥 | 修改过期时间和限额。出于安全原因,已创建的 Key 本身不会重新明文展示。 | +| 移除 API 密钥 | 删除当前客户端访问 Key。删除后立即不能再用于请求。 | + +## 创建和编辑 + +| 字段 | 代表的能力 | +| --- | --- | +| 名称 | 新 Key 的显示名。建议写成客户端或用途,例如 `Claude Code - laptop`、`CI` 或团队名。 | +| 过期时间 | 选择 Key 的有效期:`永不`、`7 天`、`30 天`、`90 天` 或 `自定义`。 | +| 过期于 | 选择 `自定义` 时出现,用于填写精确的过期日期和时间。 | +| API 密钥已创建 | 创建成功后的确认弹窗。这里会显示完整 Key。 | +| 请现在复制保存这个密钥,之后可能不会再次完整显示。 | 提醒你立即复制 Key。关闭弹窗后,CCR 不会再次展示完整 Key。 | + +## 高级设置 + +`高级设置` 用于给单个客户端 Key 添加本地限额。限额命中后,使用这个 Key 的客户端请求会被拒绝或限制;它不会修改供应商侧额度。 + +| 字段 | 代表的能力 | +| --- | --- | +| 高级设置 | 展开或收起限额编辑区。 | +| 未配置限制 | 当前 Key 没有任何本地限额。 | +| 请求 | 按请求次数限制。 | +| 令牌 | 按 token 数量限制。 | +| 图片 | 按图片数量限制。 | +| 每分钟 | 限额窗口为 1 分钟。 | +| 每小时 | 限额窗口为 1 小时。 | +| 每天 | 限额窗口为 1 天。 | +| 添加限制 | 新增一条限额规则。 | +| 移除限制 | 删除当前限额规则。 | diff --git a/docs/src/content/docs/zh/configuration/overview.md b/docs/src/content/docs/zh/configuration/overview.md new file mode 100644 index 00000000..24a188b3 --- /dev/null +++ b/docs/src/content/docs/zh/configuration/overview.md @@ -0,0 +1,59 @@ +--- +title: 概览仪表盘 +pageTitle: 概览仪表盘 +eyebrow: 详细配置 +lead: 自定义 CCR 首页组件,查看系统状态、账户余额、请求量、tokens、成本、模型分布和可分享卡片。 +--- + +## 基本概念 + +“概览”是 CCR 的仪表盘页面。它把网关运行状态、供应商账户、请求用量和分析结果做成可拖拽组件。你可以切换时间范围、编辑组件、调整大小、切换样式,也可以把部分数据生成分享卡片。 + +概览依赖请求日志、用量统计和供应商账户用量。某些组件需要先在“设置”里开启请求日志或 Agent 观测,账户余额组件需要在供应商配置中开启“获取用量”。 + +## 顶部控件 + +| 字段 | 代表的能力 | +| --- | --- | +| 按时间查看用量 | 切换仪表盘使用的统计时间范围。 | +| 今天 / 24 小时 / 7 天 / 30 天 | 可选统计窗口。不同组件会根据这个窗口重新计算请求、tokens、成本和趋势。 | +| 编辑组件 | 进入布局编辑模式。 | +| 重置布局 | 恢复默认概览布局。 | +| 完成 | 退出布局编辑模式并保留当前组件配置。 | + +## 组件区 + +编辑模式下,左侧“组件”用于添加组件,中间“预览”展示当前布局,右侧“组件属性”编辑选中组件。 + +| 字段 | 代表的能力 | +| --- | --- | +| 组件 | 可添加组件列表。 | +| 预览 | 当前仪表盘布局。组件可以拖拽排序。 | +| 组件属性 | 当前选中组件的配置区域。 | +| 组件类型 | 切换组件大类,例如状态、账户、指标、趋势、活跃度、构成、分析或分享卡片。 | +| 数据 | 选择组件展示的数据,例如请求数、tokens、成本、账户、客户端分析或供应商分析。 | +| 组件大小 | 控制组件占用的网格宽高。 | +| 样式 | 切换组件展示样式,例如卡片、紧凑、柱状图、折线图、圆环等。 | +| 移除组件 | 从概览中移除当前组件。 | + +## 组件类型 + +| 组件 | 代表的能力 | +| --- | --- | +| 状态组件 | 展示系统状态时间线,帮助判断网关近期是否正常。 | +| 账户组件 | 展示供应商账户余额、套餐额度或用量。需要供应商开启“获取用量”。 | +| 指标组件 | 展示请求数、总 tokens、输入 tokens、输出 tokens、缓存 tokens、缓存比例、估算成本、成功率、错误数或平均延迟。 | +| 趋势组件 | 展示按时间聚合的用量趋势。 | +| 活跃度组件 | 展示 token 活跃度热力图。 | +| 构成组件 | 展示 Token 构成或模型分布。 | +| 分析组件 | 展示客户端分析或供应商分析。 | +| 分享卡片 | 生成适合分享的 PNG 卡片,例如 AI Usage Wrapped、CCR Route Map、Model Leaderboard、AI Fuel Cockpit、Token Calendar Poster 和 Spend Receipt。 | + +## 数据来源 + +| 数据 | 来源 | +| --- | --- | +| 请求数、tokens、成本、成功率、延迟 | 请求日志和用量统计。 | +| 账户余额、套餐额度、状态消息 | 供应商“获取用量”配置。 | +| 客户端分析、供应商分析、模型分布 | 请求日志中的客户端、供应商、模型和 token 信息。 | +| Agent 分析相关数据 | 设置中的“Agent 观测”和 Agent 执行链路数据。 | diff --git a/docs/src/content/docs/zh/configuration/provider.md b/docs/src/content/docs/zh/configuration/provider.md index ded9a4b3..af3cbdbb 100644 --- a/docs/src/content/docs/zh/configuration/provider.md +++ b/docs/src/content/docs/zh/configuration/provider.md @@ -7,20 +7,130 @@ lead: 配置 CCR 的上游模型服务,包括协议、基础 URL、模型列 ## 基本概念 -供应商是 CCR 转发请求的上游模型服务。每个供应商至少需要协议、基础 URL、模型列表和一条可用凭据。 +供应商是 CCR 转发请求的上游模型服务。一个供应商配置同时描述了上游地址、协议能力、模型列表、认证方式、可选的多 Key 轮换,以及可选的账号用量读取能力。 + +每个供应商至少需要名称、API 地址、可用协议、模型列表和一条可用凭据。添加或编辑供应商时,弹窗中的字段会根据“预设供应商 / 自定义 API 地址 / 本机 Agent 登录态导入 / 高级设置”动态显示。 + +预设供应商会自动填入常见 API 地址、协议、模型和用量读取配置,适合优先使用。自定义供应商需要手动填写 API 地址,CCR 会根据 API 地址和 API 密钥做协议探测,帮助判断当前上游是否兼容 OpenAI Chat、OpenAI Responses、Anthropic Messages 或 Gemini Generate。 + +## 主字段 + +| 字段 | 代表的能力 | +| --- | --- | +| 选择 预设供应商 | 套用 CCR 内置供应商模板,包括默认 API 地址、可用协议、默认模型、图标、官网链接和部分供应商的用量读取配置。选择 `其他 / 自定义 API 地址` 时,可以接入任意兼容 OpenAI、Anthropic 或 Gemini 协议的上游服务。 | +| 导入本机 Agent 登录态 | 添加供应商时,如果 CCR 在本机发现 Claude Code、Codex 或 ZCode 的可用登录状态,会显示导入入口。导入后 CCR 会生成供应商和对应 provider plugin,用本机已有登录凭据访问上游,不需要手动粘贴常规 API Key。 | +| 名称 | CCR 内部显示名,也是路由、模型选择、日志和配置中识别供应商的名字。名称必须唯一,建议短且稳定。 | +| API 地址 | 上游 API Base URL。它决定请求实际发往哪里,也用于协议探测、模型列表探测、图标探测和安全校验。预设供应商添加时默认隐藏该字段,可在高级设置里覆盖。自定义供应商必须填写。 | +| API 密钥 | 默认供应商凭据。没有配置凭据池时,模型请求会使用这条 Key;协议探测、模型探测、连通性检测和默认用量读取也会使用它。只填写由当前 API 地址对应供应商签发的 Key。 | +| 模型 | 暴露给 CCR 的模型 ID 列表。路由规则、Profile 模型选择、模型目录和客户端 `/models` 响应都会基于这里的模型。 | +| 搜索模型 / 全部 / 清除 | 当 CCR 能从上游或模型目录拿到模型列表时,可以搜索、全选、清除并勾选模型。勾选结果会保存到供应商的模型列表。 | +| 自定义模型 | 手动添加没有被探测出来的模型 ID。适合供应商没有 `/models` 接口,或新模型还未进入模型目录的情况。 | +| 检测连通性 | 用当前 API 地址、API 密钥、协议和所选模型发送真实测试请求。它可以验证 Key、模型名和协议是否真的可调用。 | +| 要检测的模型 | 连接检查确认弹窗中的模型选择。用于控制只测试部分模型,避免一次性检查全部模型造成额外消耗。 | +| 检测结果 | 展示每个模型是否可用、命中的协议和上游返回的诊断信息。可用结果不会自动增加模型,仍以弹窗主表单中的模型选择为准。 | + +## 连通性检测 + +`检测连通性` 会对你选择的模型发送真实的模型请求,用来确认 API 地址、API 密钥、协议和模型 ID 是否可用。检测请求会限制输出长度,但仍然可能产生额外 token 消耗或计入供应商侧请求次数。 + +如果供应商按请求、输入 token 或输出 token 计费,建议只勾选需要确认的模型,不要一次性检查全部模型。检测结果只用于诊断连通性,不会自动修改模型列表或用量读取配置。 ## 凭据 -凭据用来保存 API Key。多条凭据可以按优先级和权重轮换,也可以在某条 Key 触发限额或失败时自动切换。 +`API 密钥` 是最简单的单 Key 配置。需要管理多条上游 Key 时,展开“高级设置”中的“凭据池”。 -建议给每条 Key 设置容易识别的名称,方便在请求日志里定位问题。 - -## 供应商选项 - -| 字段 | 说明 | +| 字段 | 代表的能力 | | --- | --- | -| 名称 | CCR 内部显示名,建议短且可识别 | -| 基础 URL | 上游服务地址,自定义供应商要确认包含正确 API 路径 | -| 协议 | OpenAI / Anthropic / Gemini 等协议 | -| 模型 | 暴露给 CCR 的模型列表 | -| 请求头 | 少数兼容服务需要的额外请求头 | +| 显示凭据配置 | 展开或收起凭据池配置。未展开不影响已保存的凭据,只是隐藏编辑区域。 | +| 导入 JSON | 从 JSON 文件批量导入凭据。支持顶层数组,或对象中的 `credentials`、`keys`、`apiKeys` 数组。 | +| 添加 Key | 新增一条上游 API Key。 | +| 启用 | 控制单条凭据是否参与请求转发和用量读取。关闭后保留配置,但不会被选中。 | +| 名称 | 单条凭据的显示名。会出现在账号用量、日志和内部诊断里,建议写成可识别的用途或额度来源。 | +| API 密钥 | 该凭据实际发送给上游的 Key。配置了凭据池后,CCR 会把启用的凭据展开成多个内部上游目标,并优先使用凭据池,而不是主表单的默认 `API 密钥`。 | +| 移除 | 删除当前凭据行。 | +| Key 高级选项 | 展开单条凭据的调度和限额字段。 | +| 优先级 | 凭据优先级,数字越小越优先。未填写时按凭据行顺序作为优先级。 | +| 权重 | 同优先级、相近使用率下的排序权重,数字越大越优先。未填写时为 `1`。 | +| 限制 JSON | 该 Key 的本地限额规则。CCR 会按请求、tokens 或图片数量统计窗口使用量,达到上限后自动跳过该 Key,尝试同供应商的其他可用 Key。 | + +`限制 JSON` 支持的常用字段: + +| 字段 | 含义 | +| --- | --- | +| `rpm` / `rph` / `rpd` | 每分钟 / 每小时 / 每天最多请求数 | +| `tpm` / `tph` / `tpd` | 每分钟 / 每小时 / 每天最多 tokens | +| `ipm` / `iph` / `ipd` | 每分钟 / 每小时 / 每天最多图片数 | +| `maxRequests` + `windowMs` | 自定义时间窗口内最多请求数 | +| `maxTokens` + `quotaWindowMs` | 自定义时间窗口内最多 tokens | + +示例: + +```json +{ + "rpm": 60, + "tpm": 100000 +} +``` + +凭据池的作用是“上游 Key 池”,不同于“API 密钥”页面里的 CCR 客户端访问 Key。前者控制 CCR 调用供应商时使用哪个 Key,后者控制客户端访问 CCR 时使用哪个 Key。 + +## 用量读取 + +“获取用量”用于让 CCR 在供应商列表、托盘或账号面板中展示余额、套餐额度、状态和错误信息。它不会影响模型是否能请求,只影响账号用量展示。 + +| 字段 | 代表的能力 | +| --- | --- | +| 获取用量 | 启用或关闭该供应商的账号用量读取。关闭后不请求用量接口。 | +| 用量模式 | 用量读取方式。`标准用量端点` 使用 CCR 标准账号端点;`HTTP JSON 请求` 手动配置一个 JSON 接口;`原始连接器 JSON` 直接编辑 connector 数组。 | +| 刷新间隔(毫秒) | 用量刷新间隔,单位毫秒。未填写时使用默认刷新间隔,最小有效间隔为 30000ms。 | + +### 标准用量端点 + +该模式会尝试供应商侧的 CCR 标准账号端点,例如 `/.well-known/ccr/account` 和 `/v1/account/limits`。适合已经适配 CCR 标准格式的供应商或内置预设。 + +### HTTP JSON 请求 + +该模式适合供应商已有自己的余额或额度接口,但返回格式不是 CCR 标准格式的情况。 + +| 字段 | 代表的能力 | +| --- | --- | +| 方法 | 用量请求方法,支持 `GET` 或 `POST`。 | +| 用量请求 URL | 用量接口地址。可以是完整 URL。请求会附带供应商 API Key,除非在 raw connector 中改成其他认证方式。 | +| 请求头 | 用量接口需要的额外请求头。不要在这里写固定的敏感认证头,优先使用供应商 API Key 认证。 | +| 请求体 | `POST` 请求体,必须是合法 JSON。 | +| 余额剩余字段 | 余额剩余值在响应 JSON 中的路径。 | +| 余额总额字段 | 余额总量或充值总额在响应 JSON 中的路径。 | +| 余额已用字段 | 已用余额在响应 JSON 中的路径。 | +| 余额单位 | 余额单位,例如 `USD`、`CNY` 或 `%`。 | +| 订阅剩余字段 | 套餐、订阅、tokens 或配额剩余量路径。 | +| 订阅上限字段 | 套餐、订阅、tokens 或配额总量路径。 | +| 订阅重置字段 | 套餐重置时间路径。可以返回 ISO 时间,也可以返回秒级或毫秒级时间戳。 | +| 订阅单位 | 套餐单位,例如 `tokens`、`requests`、`hours`。 | +| 状态字段 | 账号状态路径。支持 `ok`、`warning`、`critical`、`error`、`unsupported`。 | +| 消息字段 | 账号提示信息路径。适合展示供应商返回的错误、套餐说明或风控提示。 | +| 测试用量请求 | 立即请求用量接口并解析映射结果,方便在保存前验证字段路径。 | +| 响应字段 | 测试后列出响应 JSON 中可选字段。点击 `余额剩余`、`余额总额`、`余额已用`、`订阅剩余`、`订阅上限`、`重置时间` 可以把该路径快速填入对应字段。 | + +字段路径支持 CCR 的轻量 JSONPath 语法: + +| 写法 | 说明 | +| --- | --- | +| `$` | 整个响应对象 | +| `$.balance.remaining` | 读取对象字段 | +| `$.items[0].value` | 读取数组下标 | +| `$["weird-key"]` | 读取包含特殊字符的字段名 | +| `$.limits[?(@.type=="TOKENS")].remaining` | 在数组中查找第一个满足简单等值条件的对象 | +| `100 - $.data.percentage` | 数值字段支持简单减法表达式,常用于把“已用百分比”转换成“剩余百分比” | + +### 原始连接器 JSON + +`连接器 JSON` 允许直接编辑 `account.connectors` 数组,适合需要更复杂能力的供应商。 + +| 连接器类型 | 能力 | +| --- | --- | +| `standard` | 使用 CCR 标准账号端点。 | +| `http-json` | 请求一个 JSON 接口,并用 mapping 字段映射余额、套餐、状态和消息。 | +| `plugin` | 调用已安装插件注册的账号用量 connector。 | +| `local-estimate` | 不请求远程接口,基于本地窗口配置展示估算额度。 | + +点击 `插入示例` 会填入一个包含 `standard`、`http-json`、`plugin` 和 `local-estimate` 的示例 connector 数组。 diff --git a/docs/src/content/docs/zh/configuration/server.md b/docs/src/content/docs/zh/configuration/server.md new file mode 100644 index 00000000..3ec3d25a --- /dev/null +++ b/docs/src/content/docs/zh/configuration/server.md @@ -0,0 +1,32 @@ +--- +title: 服务配置 +pageTitle: 服务配置 +eyebrow: 详细配置 +lead: 配置 CCR 网关监听地址、端口,以及通过代理模式进行 MITM 劫持并代理到 CCR 的能力。 +--- + +## 基本概念 + +“服务”页面控制 CCR 本地网关如何监听请求。普通模型请求通常只需要配置 `Host` 和 `Port`。 + +## 主字段 + +| 字段 | 代表的能力 | +| --- | --- | +| Host | CCR 网关监听的主机地址。常见值是 `127.0.0.1` 或 `0.0.0.0`。 | +| Port | CCR 网关监听端口。客户端需要把 API Base URL 指向这个端口。 | + +## 代理模式 + +代理模式是本地代理能力。开启后,客户端可以把 HTTP/HTTPS 流量交给 CCR;CCR 会通过 MITM 劫持识别和解密 HTTPS 请求,并把可处理的模型请求代理到 CCR 网关链路。 + +| 字段 | 代表的能力 | +| --- | --- | +| 代理模式 | 启用本地代理能力。开启后 CCR 可以作为 HTTP/HTTPS 代理接收客户端流量,并通过 MITM 劫持把模型请求代理到 CCR。 | +| 系统代理 | 将系统代理指向 CCR。适合让支持系统代理的应用自动经过 CCR。 | +| 捕获网络 | 保存代理模式下经过 CCR 的网络请求,用于“网络”页面查看请求和响应详情。 | +| CA 证书 | 当前代理 CA 证书的信任状态。 | +| 安装 CA | 将 CCR 代理 CA 安装到系统或当前用户信任存储中。不同系统的安装方式不同。 | +| 检查信任 | 重新检测代理 CA 是否已被系统信任。 | +| 代理状态 | 显示代理服务当前是否运行。 | +| 重启代理 | 代理模式开启时,重新启动代理服务。 | diff --git a/docs/src/content/docs/zh/configuration/tray.md b/docs/src/content/docs/zh/configuration/tray.md new file mode 100644 index 00000000..f2bc0c1b --- /dev/null +++ b/docs/src/content/docs/zh/configuration/tray.md @@ -0,0 +1,45 @@ +--- +title: 托盘配置 +pageTitle: 托盘配置 +eyebrow: 详细配置 +lead: 配置 CCR 系统托盘图标、余额进度条和托盘窗口组件。 +--- + +## 基本概念 + +“托盘”位于“设置”里,用于配置系统托盘图标和托盘窗口。托盘窗口可以展示供应商、账户余额、token 趋势、活跃度、指标和模型占比等信息,适合在不打开主窗口时快速查看 CCR 状态。 + +## 顶部字段 + +| 字段 | 代表的能力 | +| --- | --- | +| 托盘小精灵 | 选择托盘图标样式。可选“随机”“晴岚”“暖阳”“星澜”和“余额进度条”。 | +| 余额进度条 | 使用供应商账户用量作为托盘图标进度。需要先为供应商启用“获取用量”。 | +| 账户 | 选择用于余额进度条的供应商账户。 | +| 数据 | 选择账户里的余额、套餐或额度数据作为进度来源。 | + +如果没有可用账户数据,页面会提示“暂无可用账户数据,请先为供应商启用账户监控。”这通常意味着还没有供应商开启“获取用量”,或用量读取尚未成功。 + +## 托盘窗口布局 + +| 区域 | 代表的能力 | +| --- | --- | +| 组件区 | 左侧组件库,用于添加或启用托盘窗口组件。 | +| 预览 | 中间预览区,展示当前托盘窗口布局。组件可以拖拽排序。 | +| 组件属性 | 右侧配置区,用于调整选中组件的“样式”,或移除当前组件。 | + +## 组件类型 + +| 组件 | 代表的能力 | +| --- | --- | +| 供应商组件 | 显示“供应商切换”,用于在托盘窗口中按供应商查看数据。该组件是单例组件,只能启用一次。 | +| 标题组件 | 显示“标题和状态”。该组件是单例组件,只能启用一次。 | +| 账户组件 | 显示“账户余额”。可以添加多个账户组件,并选择不同样式。 | +| 趋势组件 | 显示“Token 趋势图”。 | +| 活跃度组件 | 显示“Token 活跃度”。 | +| 指标组件 | 显示“Token 指标”。 | +| 构成组件 | 显示“Token 构成”“环形指标”或“模型占比”。 | + +## 样式 + +不同组件支持不同“样式”。常见样式包括“卡片”“紧凑”“列表”“胶囊”“折线图”“面积图”“柱状图”“圆环”“环形图”“仪表盘”“迷你折线”“堆叠”等。样式只影响托盘窗口展示方式,不改变请求路由、供应商配置或用量统计。 diff --git a/docs/src/content/docs/zh/index.md b/docs/src/content/docs/zh/index.md index 00aef301..7ea35a15 100644 --- a/docs/src/content/docs/zh/index.md +++ b/docs/src/content/docs/zh/index.md @@ -26,7 +26,7 @@ CCR 默认监听本机地址 `http://localhost:8080`。Agent 只要指向这个 | --- | --- | | [文档](./) | 产品定位、架构概览、阅读路径 | | [快速开始](guides/) | 从安装、接供应商,到接入 Agent 的上手流程 | -| [详细配置](configuration/) | 供应商、路由、配置、Fusion、Bot 和配置数据库位置 | +| [详细配置](configuration/provider/) | 概览仪表盘、API 密钥、服务、供应商、路由、Agent配置、Fusion、Bot、托盘和配置数据库位置 | | [Q&A](troubleshooting/) | 请求日志、观测面板和常见问题 | Bot 平台教程是「详细配置」分类下的子页面,每个平台有独立页面,方便逐步补齐平台后台字段、回调 URL、签名和 FAQ。 @@ -37,7 +37,7 @@ Bot 平台教程是「详细配置」分类下的子页面,每个平台有独 1. [快速开始](guides/) 覆盖供应商接入和 Agent配置。 2. App 的请求日志页面展示请求是否经过 CCR。 -3. [详细配置](configuration/) 覆盖图像、联网搜索、MCP 工具和 IM 接力。 +3. [详细配置](configuration/provider/) 覆盖概览仪表盘、API 密钥、服务、供应商、图像、联网搜索、MCP 工具、托盘和 IM 接力。 4. [Q&A](troubleshooting/) 覆盖 401、404、超时、路由不对或 Bot 收不到消息等常见问题。 这样文档不会挤在一个长页面里,后续也能按顶部分类逐步扩展。 diff --git a/docs/src/i18n/content.ts b/docs/src/i18n/content.ts index be1739bc..731f8685 100644 --- a/docs/src/i18n/content.ts +++ b/docs/src/i18n/content.ts @@ -15,7 +15,7 @@ export const docsContent = { navItems: [ { label: "文档", href: "/", pageKey: "documentation" }, { label: "快速开始", href: "/guides/", pageKey: "guides" }, - { label: "详细配置", href: "/configuration/", pageKey: "configuration" }, + { label: "详细配置", href: "/configuration/provider/", pageKey: "configuration" }, { label: "Q&A", href: "/troubleshooting/", pageKey: "troubleshooting" }, ], pages: { @@ -63,12 +63,16 @@ export const docsContent = { label: "详细配置", icon: "wand", items: [ + "概览仪表盘", "供应商配置", "一键导入供应商", "路由配置", "日志&观测", "Fusion 组合模型", "Agent配置", + "API 密钥", + "服务配置", + "托盘配置", "扩展机制", "Bot 与 IM 接力 Agent", "配置数据库位置", @@ -92,6 +96,7 @@ export const docsContent = { ], }, sidebarLinks: { + 概览仪表盘: "/configuration/overview/", 供应商配置: "/configuration/provider/", "一键导入供应商": "/configuration/provider-deeplink/", 路由配置: "/configuration/routing/", @@ -101,6 +106,9 @@ export const docsContent = { 内置联网搜索: "/configuration/fusion-web-search/", "自定义 MCP 工具": "/configuration/fusion-mcp-tool/", Agent配置: "/configuration/profile/", + "API 密钥": "/configuration/api-keys/", + 服务配置: "/configuration/server/", + 托盘配置: "/configuration/tray/", 扩展机制: "/configuration/extensions/", "Bot 与 IM 接力 Agent": "/configuration/bot-relay/", 配置步骤: "/configuration/bot-setup/", @@ -155,7 +163,7 @@ export const docsContent = { navItems: [ { label: "Documentation", href: "/en/", pageKey: "documentation" }, { label: "Quick Start", href: "/en/guides/", pageKey: "guides" }, - { label: "Detailed Configuration", href: "/en/configuration/", pageKey: "configuration" }, + { label: "Detailed Configuration", href: "/en/configuration/providers/", pageKey: "configuration" }, { label: "Q&A", href: "/en/troubleshooting/", pageKey: "troubleshooting" }, ], pages: { @@ -203,12 +211,16 @@ export const docsContent = { label: "Detailed Configuration", icon: "wand", items: [ + "Overview Dashboard", "Provider Config", "One click import", "Routing Config", "Logs & Observability", "Fusion Models", "Agent Config", + "API Keys", + "Server", + "Tray Configuration", "Extension Mechanism", "Bots And IM Agent Relay", "Config Database Location", @@ -222,6 +234,7 @@ export const docsContent = { "Bots And IM Agent Relay": ["Setup", "Slack", "Discord", "Telegram", "LINE", "Weixin", "WeCom", "Feishu", "DingTalk"], }, sidebarLinks: { + "Overview Dashboard": "/en/configuration/overview/", "Provider Config": "/en/configuration/providers/", "One click import": "/en/configuration/provider-deeplink/", "Routing Config": "/en/configuration/routing/", @@ -231,6 +244,9 @@ export const docsContent = { "Built-In Web Search": "/en/configuration/fusion-web-search/", "Custom MCP Tool": "/en/configuration/fusion-mcp-tool/", "Agent Config": "/en/configuration/profiles/", + "API Keys": "/en/configuration/api-keys/", + Server: "/en/configuration/server/", + "Tray Configuration": "/en/configuration/tray/", "Extension Mechanism": "/en/configuration/extensions/", "Bots And IM Agent Relay": "/en/configuration/bots/", Setup: "/en/configuration/bot-setup/", diff --git a/docs/src/pages/configuration.astro b/docs/src/pages/configuration.astro index e241173b..1ad9fba3 100644 --- a/docs/src/pages/configuration.astro +++ b/docs/src/pages/configuration.astro @@ -1,6 +1,17 @@ --- -import DocPage from "../components/DocPage.astro"; -import * as doc from "../content/docs/zh/configuration.md"; +const target = "/configuration/provider/"; --- - + + + + + + + + + 供应商配置 + + diff --git a/docs/src/pages/configuration/[slug].astro b/docs/src/pages/configuration/[slug].astro index 92538646..3dda58c2 100644 --- a/docs/src/pages/configuration/[slug].astro +++ b/docs/src/pages/configuration/[slug].astro @@ -4,6 +4,8 @@ import { configurationSlugFromPath, zhConfigurationDocs } from "../../configurat export function getStaticPaths() { const activeLabels: Record = { + "api-keys": "API 密钥", + overview: "概览仪表盘", provider: "供应商配置", "provider-deeplink": "一键导入供应商", routing: "路由配置", @@ -14,6 +16,8 @@ export function getStaticPaths() { "fusion-web-search": "内置联网搜索", "fusion-mcp-tool": "自定义 MCP 工具", extensions: "扩展机制", + server: "服务配置", + tray: "托盘配置", "bot-relay": "Bot 与 IM 接力 Agent", "bot-setup": "配置步骤", "config-file": "配置数据库位置", diff --git a/docs/src/pages/en/configuration.astro b/docs/src/pages/en/configuration.astro index c2ce75bf..01088a9c 100644 --- a/docs/src/pages/en/configuration.astro +++ b/docs/src/pages/en/configuration.astro @@ -1,6 +1,17 @@ --- -import DocPage from "../../components/DocPage.astro"; -import * as doc from "../../content/docs/en/configuration.md"; +const target = "/en/configuration/providers/"; --- - + + + + + + + + + Provider Config + + diff --git a/docs/src/pages/en/configuration/[slug].astro b/docs/src/pages/en/configuration/[slug].astro index 4cd93246..cc2fc900 100644 --- a/docs/src/pages/en/configuration/[slug].astro +++ b/docs/src/pages/en/configuration/[slug].astro @@ -4,6 +4,8 @@ import { configurationSlugFromPath, enConfigurationDocs } from "../../../configu export function getStaticPaths() { const activeLabels: Record = { + "api-keys": "API Keys", + overview: "Overview Dashboard", providers: "Provider Config", "provider-deeplink": "One click import", routing: "Routing Config", @@ -14,6 +16,8 @@ export function getStaticPaths() { "fusion-web-search": "Built-In Web Search", "fusion-mcp-tool": "Custom MCP Tool", extensions: "Extension Mechanism", + server: "Server", + tray: "Tray Configuration", bots: "Bots And IM Agent Relay", "bot-setup": "Setup", "configuration-file": "Config Database Location", diff --git a/src/renderer/pages/home/components/providers.tsx b/src/renderer/pages/home/components/providers.tsx index fa2ee33b..200701e2 100644 --- a/src/renderer/pages/home/components/providers.tsx +++ b/src/renderer/pages/home/components/providers.tsx @@ -1364,7 +1364,7 @@ export function AddProviderForm({ )} - + onChange({ name: event.target.value })} /> {showBaseUrl ? ( diff --git a/src/renderer/pages/home/components/virtual-models.tsx b/src/renderer/pages/home/components/virtual-models.tsx index ee75dfff..453a9572 100644 --- a/src/renderer/pages/home/components/virtual-models.tsx +++ b/src/renderer/pages/home/components/virtual-models.tsx @@ -3,11 +3,11 @@ import { Card, CardContent, CardHeader, CardTitle, Check, ChevronDown, ChevronRight, cn, createMcpServerDraftFromConfig, createRouteModelOptions, defaultFusionWebSearchProvider, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, ExtensionInstallDraft, Field, FolderOpen, formatPluginDependencies, - createFusionWebSearchEnvRows, customFusionToolName, fusionToolExecutionFlags, fusionToolOptions, - fusionWebSearchProviderOptions, GatewayMcpServerConfig, GatewayMcpToolInfo, GatewayProviderConfig, Input, KeyValueRowsControl, LoaderCircle, + createFusionWebSearchEnvRows, customFusionToolName, fusionToolExecutionFlagsFromTools, fusionToolOptions, + fusionWebSearchProviderOptions, GatewayMcpServerConfig, GatewayMcpToolInfo, GatewayProviderConfig, Input, isBuiltInFusionToolName, isFusionVisionToolName, isFusionWebSearchToolName, KeyValueRowsControl, LoaderCircle, mcpServerConfigFromDraft, mcpServerEndpointSummary, mcpServerTransportOptions, mcpStdioMessageModeOptions, motion, normalizeFusionToolName, Pencil, - PluginMarketplaceEntry, Plus, PopoverContent, RouteTargetControl, Search, selectedFusionToolName, + PluginMarketplaceEntry, Plus, PopoverContent, RouteTargetControl, Search, selectedFusionToolNames, SelectControl, Toggle, Trash2, translateOptions, useAppErrorText, useAppText, useEffect, useLayoutEffect, useMemo, useRef, useState, validateMcpServerDraft, virtualModelBaseModelSummary, VirtualModelDraft, virtualModelMatchesQuery, virtualModelMatchSummary, VirtualModelProfileConfig, virtualModelToolSummary, X @@ -16,6 +16,25 @@ import { const virtualModelTableGridClass = "grid-cols-[minmax(180px,0.9fr)_minmax(220px,1.1fr)_minmax(220px,1.1fr)_minmax(170px,0.85fr)_112px_96px]"; const virtualModelTableMinWidthClass = "min-w-[1100px]"; +function uniqueFusionTools(tools: string[]): string[] { + const seen = new Set(); + const values: string[] = []; + for (const tool of tools) { + const normalized = normalizeFusionToolName(tool); + if (!normalized || seen.has(normalized)) { + continue; + } + values.push(normalized); + seen.add(normalized); + } + return values; +} + +function visibleFusionToolOption(toolName: string, currentValue: string, excludedValues: Set): boolean { + const normalized = normalizeFusionToolName(toolName); + return Boolean(normalized) && (normalized === currentValue || !excludedValues.has(normalized)); +} + export function VirtualModelsView({ addVirtualModel, editVirtualModel, @@ -157,11 +176,11 @@ export function VirtualModelDialog({ const t = useAppText(); const formatError = useAppErrorText(); const modelOptions = useMemo(() => createRouteModelOptions(providers), [providers]); - const selectedTool = selectedFusionToolName(draft.toolsText); - const selectedToolFlags = fusionToolExecutionFlags(selectedTool); + const selectedTools = selectedFusionToolNames(draft.toolsText); const [customMcpDialogOpen, setCustomMcpDialogOpen] = useState(false); const [customMcpDialogDraft, setCustomMcpDialogDraft] = useState(draft.customMcpServer); const [customMcpDialogError, setCustomMcpDialogError] = useState(""); + const [addingFusionTool, setAddingFusionTool] = useState(false); const [mcpToolStateByServer, setMcpToolStateByServer] = useState isBuiltInFusionToolName(tool) || tool === selectedCustomTool) + : nextTools + ); + const flags = fusionToolExecutionFlagsFromTools(normalizedTools); + const customTool = normalizedTools.find((tool) => !isBuiltInFusionToolName(tool)); onChange({ ...(flags.matchWebSearch && draft.webSearchEnvRows.length === 0 ? { webSearchEnvRows: createFusionWebSearchEnvRows(draft.webSearchProvider) } : {}), - ...(!flags.matchMultimodal && !flags.matchWebSearch ? { + ...(customTool ? { ...(server ? { customMcpServer: createMcpServerDraftFromConfig(server) } : {}), - customToolName: nextTool || draft.customToolName || customFusionToolName + customToolName: customTool || draft.customToolName || customFusionToolName } : {}), - toolsText: nextTool, + toolsText: normalizedTools.join(", "), ...flags }); } + function appendFusionTool(toolName: string, server?: GatewayMcpServerConfig) { + const nextTool = normalizeFusionToolName(toolName); + if (!nextTool) { + return; + } + applyFusionTools([...selectedFusionToolNames(draft.toolsText), nextTool], server, server ? nextTool : undefined); + setAddingFusionTool(false); + } + + function updateFusionTool(index: number, toolName: string, server?: GatewayMcpServerConfig) { + const nextTool = normalizeFusionToolName(toolName); + if (!nextTool) { + return; + } + const currentTools = selectedFusionToolNames(draft.toolsText); + const nextTools = currentTools.map((tool, toolIndex) => toolIndex === index ? nextTool : tool); + applyFusionTools(nextTools, server, server ? nextTool : undefined); + } + + function removeFusionTool(index: number) { + applyFusionTools(selectedFusionToolNames(draft.toolsText).filter((_, toolIndex) => toolIndex !== index)); + } + function openCustomMcpDialog() { setCustomMcpDialogDraft(draft.customMcpServer); setCustomMcpDialogError(""); @@ -289,12 +337,9 @@ export function VirtualModelDialog({ const tools = await discoverMcpServerTools(server, true); const nextTool = normalizeFusionToolName(tools[0]?.name || ""); if (nextTool) { - onChange({ - customMcpServer: createMcpServerDraftFromConfig(server), - customToolName: nextTool, - toolsText: nextTool, - ...fusionToolExecutionFlags(nextTool) - }); + const currentTools = selectedFusionToolNames(draft.toolsText); + applyFusionTools(currentTools.includes(nextTool) ? currentTools : [...currentTools, nextTool], server, nextTool); + setAddingFusionTool(false); } } @@ -322,11 +367,18 @@ export function VirtualModelDialog({
+
- setAddingFusionTool(true)} + onAppendTool={appendFusionTool} + onCancelAddTool={() => setAddingFusionTool(false)} + onChange={onChange} + onChangeTool={updateFusionTool} onDiscoverMcpTools={(server, force) => { if (server) { void discoverMcpServerTools(server, force); @@ -334,28 +386,13 @@ export function VirtualModelDialog({ } discoverVisibleMcpServers(); }} + onRemoveTool={removeFusionTool} selectedMcpServerName={draft.customMcpServer.name} - value={selectedTool} + values={selectedTools} /> - {selectedToolFlags.matchMultimodal ? ( -
-
-
{t("Vision tool configuration")}
-
{t("Choose a configured gateway model for image understanding.")}
-
- - onChange({ visionModel })} value={draft.visionModel} /> - -
- ) : null} - - {selectedToolFlags.matchWebSearch ? ( - - ) : null} - {error ? (
{t(error)}
) : null} @@ -412,9 +449,6 @@ function WebSearchToolConfigurationPanel({ return (
-
-
{t("Web search configuration")}
-
@@ -549,7 +583,166 @@ function CustomMcpToolDialog({ ); } +function FusionToolConfigurationPanel({ + draft, + modelOptions, + onChange, + toolName +}: { + draft: VirtualModelDraft; + modelOptions: ReturnType; + onChange: (patch: Partial) => void; + toolName: string; +}) { + if (isFusionVisionToolName(toolName)) { + return ; + } + if (isFusionWebSearchToolName(toolName)) { + return ; + } + return null; +} + +function VisionToolConfigurationPanel({ + draft, + modelOptions, + onChange +}: { + draft: VirtualModelDraft; + modelOptions: ReturnType; + onChange: (patch: Partial) => void; +}) { + const t = useAppText(); + + return ( +
+ + onChange({ visionModel })} value={draft.visionModel} /> + +
+ ); +} + +function FusionToolsListControl({ + adding, + draft, + mcpServers, + mcpToolStateByServer, + modelOptions, + onAddCustomMcpTool, + onAddTool, + onAppendTool, + onCancelAddTool, + onChange, + onChangeTool, + onDiscoverMcpTools, + onRemoveTool, + selectedMcpServerName, + values +}: { + adding: boolean; + draft: VirtualModelDraft; + mcpServers: GatewayMcpServerConfig[]; + mcpToolStateByServer: Record; + modelOptions: ReturnType; + onAddCustomMcpTool: () => void; + onAddTool: () => void; + onAppendTool: (value: string, server?: GatewayMcpServerConfig) => void; + onCancelAddTool: () => void; + onChange: (patch: Partial) => void; + onChangeTool: (index: number, value: string, server?: GatewayMcpServerConfig) => void; + onDiscoverMcpTools: (server?: GatewayMcpServerConfig, force?: boolean) => void; + onRemoveTool: (index: number) => void; + selectedMcpServerName: string; + values: string[]; +}) { + const t = useAppText(); + const selectedToolValues = values.map(normalizeFusionToolName).filter(Boolean); + + return ( +
+ {values.map((value, index) => ( +
+
+
+ toolIndex !== index)} + mcpServers={mcpServers} + mcpToolStateByServer={mcpToolStateByServer} + onAddCustomMcpTool={onAddCustomMcpTool} + onChange={(toolName, server) => onChangeTool(index, toolName, server)} + onDiscoverMcpTools={onDiscoverMcpTools} + selectedMcpServerName={selectedMcpServerName} + value={value} + /> +
+ +
+ +
+ ))} + + {adding ? ( +
+
+ +
+ +
+ ) : null} + + +
+ ); +} + function FusionToolSelectControl({ + excludedValues, mcpServers, mcpToolStateByServer, onAddCustomMcpTool, @@ -558,6 +751,7 @@ function FusionToolSelectControl({ selectedMcpServerName, value }: { + excludedValues?: string[]; mcpServers: GatewayMcpServerConfig[]; mcpToolStateByServer: Record(); const rootRef = useRef(null); const normalizedValue = normalizeFusionToolName(value); + const excludedValueSet = new Set((excludedValues ?? []).map(normalizeFusionToolName).filter(Boolean)); const selected = fusionToolOptions.find((option) => option.value === normalizedValue); const selectedServer = selectedMcpServerName ? mcpServers.find((server) => server.name === selectedMcpServerName) @@ -703,7 +898,7 @@ function FusionToolSelectControl({ role="listbox" style={{ maxHeight: `${popoverLayout?.maxHeight ?? 360}px` }} > - {fusionToolOptions.map((option) => { + {fusionToolOptions.filter((option) => visibleFusionToolOption(option.value, normalizedValue, excludedValueSet)).map((option) => { const selectedOption = option.value === selected?.value; return (