@goodandready/dsh-clinebot 0.5.7 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +29 -16
- package/README.ru.md +29 -16
- package/README.zh.md +29 -16
- package/lib/account-pool.js +7 -5
- package/lib/client.js +189 -78
- package/lib/cline-client.js +46 -6
- package/lib/index.js +43 -32
- package/lib/models.js +35 -9
- package/lib/provider-sync.js +21 -8
- package/lib/routes/models.js +4 -4
- package/lib/routes/proxy.js +51 -12
- package/lib/slash-command.js +4 -3
- package/lib/updater.js +83 -30
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to `@goodandready/dsh-clinebot` will be documented in this f
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.9] - 2026-10-01
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Updater Timeout Exit & SIGKILL Escalation (Issue #172)**: Ensured `installExact` child process cleanup waits for the operating system process to fully terminate via `exit`/`close` events before releasing profile locks or rejecting update promises. On timeout, sends `SIGTERM`, waits for a grace period, and escalates to `SIGKILL` for stubborn subprocesses.
|
|
12
|
+
- **Proxy Client Disconnection SSE Abort Fixture (Issue #173)**: Validated client disconnection handling against a real Node.js loopback HTTP fixture with client TCP stream destruction, asserting upstream `reader.cancel()` and fetch `signal.aborted` without relying exclusively on synthetic mocks.
|
|
13
|
+
- **Dependency Manifest & Lockfile Synchronization (Issue #174)**: Regenerated `package-lock.json` via clean npm resolution for all 21 dependencies to ensure deterministic, clean `npm ci` builds across environments, while maintaining proper exclusion of the lockfile from package archives.
|
|
14
|
+
- **UI Locale Key Completeness & Reasoning/Quota Strings (Issue #175)**: Resolved missing locale keys across `en` and `zh` dictionaries for structured quota countdowns/warnings, reasoning tags and effort selectors, capability badges, smoke test diagnostic outputs, and ErrorBoundary alerts. Added regression test asserting 100% dictionary completeness and symmetry for client `t()` calls.
|
|
15
|
+
- **Update Check State Machine & Error Handling (Issue #176)**: Implemented explicit update state machine (`idle`, `checking`, `current`, `available`, `error`) in `UpdateBanner` and `settings-page.js`. Eliminated false "✓ Up to date" status indicators on failed network checks or when `latestCheckFailed: true`, and added retry action.
|
|
16
|
+
- **Documentation & Design Contract Modernization (Issue #177)**: Synchronized `README.md`, `README.ru.md`, `README.zh.md`, and `docs/design/DESIGN.md` with active runtime contracts: documented dynamic subscription catalog, custom models, active configuration schema (`disabledModels`, `proxyMode`, `accounts`), corrected route prefixes (`/dsh-clinebot/*`), and documented all 4 registered UI seats and release testing workflows.
|
|
17
|
+
|
|
18
|
+
## [0.5.8] - 2026-09-30
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- **Settings PUT Method & Form Error Recovery (Issue #156)**: Fixed `handleConfigPatch` in settings UI client to use `PUT /config` conforming to API routes and preserve unsaved form drafts on server errors.
|
|
22
|
+
- **Client Telemetry Wire Envelope Normalization (Issue #159)**: Fixed `statsSummary` in status payload to align with persistent storage format and accurately display model token consumption and totals.
|
|
23
|
+
- **Deduplication of Proxy & LLM Stream Telemetry (Issue #160)**: Avoided double-counting tokens and latency when requests pass through loopback proxy into `llm/stream`.
|
|
24
|
+
- **Proxy Error Mapping & 429 Header Preservation (Issue #166)**: Differentiated network unreachable/ECONNREFUSED errors as HTTP 502 Bad Gateway instead of false 429, and preserved upstream `Retry-After` headers.
|
|
25
|
+
- **Fetch Response Body Disposal Before Retry (Issue #167)**: Explicitly cancelled upstream HTTP response bodies before triggering retry or account failover on rate-limited or error attempts.
|
|
26
|
+
- **Dynamic Models Catalog Synchronization (Issue #168)**: Pruned deleted upstream models and reconciled metadata diffs on subscription plan updates using `isCatalogDifferent`.
|
|
27
|
+
- **Collision-Free Opaque Usage Cache Key (Issue #169)**: Replaced 8-character key suffix with SHA-256 hash of `baseUrl` and full API key to prevent cross-account cache collisions and protect key secrecy.
|
|
28
|
+
- **Custom Models Resolution Across Routes & Slash Commands (Issue #170)**: Forwarded user-defined custom models through catalog lookup, validation, `/cline test`, `/cline models`, and context configuration routes.
|
|
29
|
+
- **Local Proxy Bearer Token Redaction in Provider Settings (Issue #171)**: Omitted plaintext local proxy token from pi-ai provider descriptor and settings mutation payload, resolving authentication strictly through credential references.
|
|
30
|
+
|
|
8
31
|
## [0.5.7] - 2026-09-30
|
|
9
32
|
|
|
10
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ graph LR
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
subgraph PluginHost [dsh-clinebot Host Runtime]
|
|
77
|
-
HttpEndpoints["API: /
|
|
77
|
+
HttpEndpoints["API: /dsh-clinebot/*"]
|
|
78
78
|
ClientCore["lib/cline-client.js"]
|
|
79
79
|
ModelCatalog["lib/models.js (Curated + Dynamic Plan)"]
|
|
80
80
|
SlashCmd["Command: /cline"]
|
|
@@ -108,7 +108,7 @@ graph LR
|
|
|
108
108
|
## ✨ Features & Module Breakdown
|
|
109
109
|
|
|
110
110
|
* **`lib/models.js`**:
|
|
111
|
-
Manages the
|
|
111
|
+
Manages the dynamic subscription catalog and fallback models with full reasoning effort mappings (`off: null`, `low`, `medium`, `high`, `max`), upstream 200k context limit declarations, user-defined custom models, and dynamic subscription plan model parsing (`parsePlanIncludedModels`, `getAllModels`, `getDynamicModels`).
|
|
112
112
|
* **`lib/cline-client.js`**:
|
|
113
113
|
* `fetchUsageLimits`: queries `GET /users/me/plan/usage-limits`, `GET /users/me/plan`, and `GET /users/me` with in-memory caching.
|
|
114
114
|
* `sessionStats` / `recordSessionRequest`: in-memory telemetry recording requests count, tokens, latency, and timestamps.
|
|
@@ -163,29 +163,42 @@ dsh-clinebot:
|
|
|
163
163
|
enabled: true
|
|
164
164
|
baseUrl: https://api.cline.bot/api/v1
|
|
165
165
|
apiKeyEnv: CLINEBOT_API_KEY
|
|
166
|
-
defaultModel:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
166
|
+
defaultModel: your-default-model
|
|
167
|
+
proxyMode: true
|
|
168
|
+
disabledModels: []
|
|
169
|
+
customModels: []
|
|
170
|
+
modelReasoningDefaults:
|
|
171
|
+
your-reasoning-model: high
|
|
172
|
+
modelContextOverrides: []
|
|
173
|
+
statsPath: ~/.dsh/clinebot-stats.json
|
|
174
|
+
timeoutMs: 30000
|
|
175
|
+
smokeTimeoutMs: 60000
|
|
176
|
+
streamIdleTimeoutMs: 60000
|
|
177
|
+
accounts:
|
|
178
|
+
- label: Team Key
|
|
179
|
+
apiKeyEnv: CLINEBOT_API_KEY_2
|
|
175
180
|
```
|
|
176
181
|
|
|
177
182
|
### Configuration Parameters
|
|
178
183
|
|
|
179
184
|
| Parameter | Type | Default | Description |
|
|
180
185
|
|:---|:---|:---|:---|
|
|
181
|
-
| `enabled` | `boolean` | `true` | Enable or disable the ClineBot provider bridge |
|
|
186
|
+
| `enabled` | `boolean` | `true` | Enable or disable the ClineBot provider bridge in DSH |
|
|
182
187
|
| `baseUrl` | `string` | `"https://api.cline.bot/api/v1"` | ClinePass OpenAI-compatible base URL |
|
|
183
188
|
| `apiKeyEnv` | `string` | `"CLINEBOT_API_KEY"` | Environment variable / credentials key name |
|
|
184
|
-
| `defaultModel` | `string` | `"
|
|
189
|
+
| `defaultModel` | `string` | `"claude-3-7-sonnet"` | Default selected model ID for chat and smoke tests |
|
|
190
|
+
| `disabledModels` | `array` | `[]` | List of model IDs hidden from the DSH chat picker (new subscription models are auto-enabled) |
|
|
191
|
+
| `customModels` | `array` | `[]` | User-defined gateway models (`[{ id, name, contextLength, maxTokens, category, isReasoning }]`) |
|
|
192
|
+
| `modelReasoningDefaults` | `object` | `{}` | Configured default reasoning effort per model (`low`, `medium`, `high`, `max`) |
|
|
185
193
|
| `modelContextOverrides` | `array` | `[]` | User-defined model context length and max token overrides |
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
194
|
+
| `proxyMode` | `boolean` | `true` | Enable local transparent loopback proxy for sticky sessions and automatic 429 failover |
|
|
195
|
+
| `statsPath` | `string` | `"~/.dsh/clinebot-stats.json"` | Persistent on-disk path for token usage analytics |
|
|
196
|
+
| `accounts` | `array` | `[]` | Additional accounts for multi-account failover and quota rotation (`[{ label, apiKeyEnv }]`) |
|
|
197
|
+
| `activeAccount` | `string` | `""` | Manually pinned active account env name (empty for least-used auto routing) |
|
|
198
|
+
| `timeoutMs` | `number` | `30000` | HTTP probe timeout in milliseconds |
|
|
199
|
+
| `smokeTimeoutMs` | `number` | `60000` | Timeout for smoke test chat completions in milliseconds |
|
|
200
|
+
| `streamIdleTimeoutMs` | `number` | `60000` | Idle timeout between SSE stream chunks in milliseconds |
|
|
201
|
+
| `enabledModels` | `array` | *(deprecated)* | Read-only in public config; rejected on `PUT /config` in favor of `disabledModels` |
|
|
189
202
|
| `dynamicModels` | `array` | `[]` | Dynamic models automatically synced from the official plan |
|
|
190
203
|
|
|
191
204
|
---
|
package/README.ru.md
CHANGED
|
@@ -74,7 +74,7 @@ graph LR
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
subgraph PluginHost [Хост-часть dsh-clinebot]
|
|
77
|
-
HttpEndpoints["API: /
|
|
77
|
+
HttpEndpoints["API: /dsh-clinebot/*"]
|
|
78
78
|
ClientCore["lib/cline-client.js"]
|
|
79
79
|
ModelCatalog["lib/models.js (Встроенные + Динамические из плана)"]
|
|
80
80
|
SlashCmd["Слэш-команда: /cline"]
|
|
@@ -107,7 +107,7 @@ graph LR
|
|
|
107
107
|
|
|
108
108
|
## ✨ Структура модулей и возможности
|
|
109
109
|
|
|
110
|
-
* **`lib/models.js`**: каталог
|
|
110
|
+
* **`lib/models.js`**: динамический каталог моделей подписки и встроенных шаблонов с поддержкой уровней рассуждения (`Off` / `Low` / `Medium` / `High` / `Max`), контекстных лимитов, пользовательских моделей (`customModels`) и парсинга тарифа (`parsePlanIncludedModels`, `getAllModels`, `getDynamicModels`).
|
|
111
111
|
* **`lib/cline-client.js`**:
|
|
112
112
|
* `fetchUsageLimits`: параллельный опрос `GET /users/me/plan/usage-limits`, `GET /users/me/plan` и `GET /users/me` с кэшированием в памяти.
|
|
113
113
|
* `sessionStats` / `recordSessionRequest`: счетчики сессии (запросы, токены, задержка, время).
|
|
@@ -158,29 +158,42 @@ dsh-clinebot:
|
|
|
158
158
|
enabled: true
|
|
159
159
|
baseUrl: https://api.cline.bot/api/v1
|
|
160
160
|
apiKeyEnv: CLINEBOT_API_KEY
|
|
161
|
-
defaultModel:
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
defaultModel: your-default-model
|
|
162
|
+
proxyMode: true
|
|
163
|
+
disabledModels: []
|
|
164
|
+
customModels: []
|
|
165
|
+
modelReasoningDefaults:
|
|
166
|
+
your-reasoning-model: high
|
|
167
|
+
modelContextOverrides: []
|
|
168
|
+
statsPath: ~/.dsh/clinebot-stats.json
|
|
169
|
+
timeoutMs: 30000
|
|
170
|
+
smokeTimeoutMs: 60000
|
|
171
|
+
streamIdleTimeoutMs: 60000
|
|
172
|
+
accounts:
|
|
173
|
+
- label: Team Key
|
|
174
|
+
apiKeyEnv: CLINEBOT_API_KEY_2
|
|
170
175
|
```
|
|
171
176
|
|
|
172
177
|
### Параметры конфигурации
|
|
173
178
|
|
|
174
179
|
| Параметр | Тип | По умолчанию | Описание |
|
|
175
180
|
|:---|:---|:---|:---|
|
|
176
|
-
| `enabled` | `boolean` | `true` | Включение моста провайдера ClineBot |
|
|
181
|
+
| `enabled` | `boolean` | `true` | Включение моста провайдера ClineBot в DSH |
|
|
177
182
|
| `baseUrl` | `string` | `"https://api.cline.bot/api/v1"` | Базовый URL OpenAI-совместимого API ClinePass |
|
|
178
183
|
| `apiKeyEnv` | `string` | `"CLINEBOT_API_KEY"` | Имя переменной / ключа в хранилище credentials |
|
|
179
|
-
| `defaultModel` | `string` | `"
|
|
184
|
+
| `defaultModel` | `string` | `"claude-3-7-sonnet"` | Модель, выбираемая по умолчанию для чата и smoke-тестов |
|
|
185
|
+
| `disabledModels` | `array` | `[]` | Список отключённых моделей (новые модели подписки включаются автоматически) |
|
|
186
|
+
| `customModels` | `array` | `[]` | Пользовательские модели шлюза (`[{ id, name, contextLength, maxTokens, category, isReasoning }]`) |
|
|
187
|
+
| `modelReasoningDefaults` | `object` | `{}` | Значения thinking effort по умолчанию для моделей (`low`, `medium`, `high`, `max`) |
|
|
180
188
|
| `modelContextOverrides` | `array` | `[]` | Пользовательские переопределения размера контекста и лимита токенов |
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
189
|
+
| `proxyMode` | `boolean` | `true` | Включение локального прозрачного loopback-прокси с сессионным роутингом и failover |
|
|
190
|
+
| `statsPath` | `string` | `"~/.dsh/clinebot-stats.json"` | Путь к файлу персистентной аналитики использования токенов |
|
|
191
|
+
| `accounts` | `array` | `[]` | Дополнительные аккаунты для ротации квоты и failover (`[{ label, apiKeyEnv }]`) |
|
|
192
|
+
| `activeAccount` | `string` | `""` | Принудительно закреплённый аккаунт (пусто для автоматического выбора least-used) |
|
|
193
|
+
| `timeoutMs` | `number` | `30000` | Таймаут HTTP-запросов (мс) |
|
|
194
|
+
| `smokeTimeoutMs` | `number` | `60000` | Таймаут тестового пинга инференса (мс) |
|
|
195
|
+
| `streamIdleTimeoutMs` | `number` | `60000` | Таймаут ожидания между чанками SSE-потока (мс) |
|
|
196
|
+
| `enabledModels` | `array` | *(устарело)* | Только для чтения в public config; отклоняется при `PUT /config` в пользу `disabledModels` |
|
|
184
197
|
| `dynamicModels` | `array` | `[]` | Динамические модели, автоматически синхронизированные из тарифа |
|
|
185
198
|
|
|
186
199
|
---
|
package/README.zh.md
CHANGED
|
@@ -74,7 +74,7 @@ graph LR
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
subgraph PluginHost [dsh-clinebot 宿主运行环境]
|
|
77
|
-
HttpEndpoints["API 路由: /
|
|
77
|
+
HttpEndpoints["API 路由: /dsh-clinebot/*"]
|
|
78
78
|
ClientCore["lib/cline-client.js"]
|
|
79
79
|
ModelCatalog["lib/models.js (内置精选 + 动态订阅解析)"]
|
|
80
80
|
SlashCmd["斜杠指令: /cline"]
|
|
@@ -107,7 +107,7 @@ graph LR
|
|
|
107
107
|
|
|
108
108
|
## ✨ 核心模块与功能
|
|
109
109
|
|
|
110
|
-
* **`lib/models.js
|
|
110
|
+
* **`lib/models.js`**:管理动态订阅模型目录与内置精选模板(提供完整的 `Off` / `Low` / `Medium` / `High` / `Max` 思考强度映射、上游 200k 上下文容量标注、自定义模型支持)以及套餐模型动态解析器(`parsePlanIncludedModels`, `getAllModels`, `getDynamicModels`)。
|
|
111
111
|
* **`lib/cline-client.js`**:
|
|
112
112
|
* `fetchUsageLimits`:高效并发轮询 `GET /users/me/plan/usage-limits`、`GET /users/me/plan` 与 `GET /users/me` 并进行内存缓存。
|
|
113
113
|
* `sessionStats` / `recordSessionRequest`:内存级会话度量记录器(请求次数、Token 估算、延迟、时间戳)。
|
|
@@ -160,29 +160,42 @@ dsh-clinebot:
|
|
|
160
160
|
enabled: true
|
|
161
161
|
baseUrl: https://api.cline.bot/api/v1
|
|
162
162
|
apiKeyEnv: CLINEBOT_API_KEY
|
|
163
|
-
defaultModel:
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
163
|
+
defaultModel: your-default-model
|
|
164
|
+
proxyMode: true
|
|
165
|
+
disabledModels: []
|
|
166
|
+
customModels: []
|
|
167
|
+
modelReasoningDefaults:
|
|
168
|
+
your-reasoning-model: high
|
|
169
|
+
modelContextOverrides: []
|
|
170
|
+
statsPath: ~/.dsh/clinebot-stats.json
|
|
171
|
+
timeoutMs: 30000
|
|
172
|
+
smokeTimeoutMs: 60000
|
|
173
|
+
streamIdleTimeoutMs: 60000
|
|
174
|
+
accounts:
|
|
175
|
+
- label: Team Key
|
|
176
|
+
apiKeyEnv: CLINEBOT_API_KEY_2
|
|
172
177
|
```
|
|
173
178
|
|
|
174
179
|
### 配置参数说明
|
|
175
180
|
|
|
176
181
|
| 参数项 | 类型 | 默认值 | 说明 |
|
|
177
182
|
|:---|:---|:---|:---|
|
|
178
|
-
| `enabled` | `boolean` | `true` |
|
|
183
|
+
| `enabled` | `boolean` | `true` | 是否在 DSH 中启用 ClineBot 桥接插件 |
|
|
179
184
|
| `baseUrl` | `string` | `"https://api.cline.bot/api/v1"` | ClinePass OpenAI 兼容接口地址 |
|
|
180
185
|
| `apiKeyEnv` | `string` | `"CLINEBOT_API_KEY"` | 凭据管理系统中的密钥名称 |
|
|
181
|
-
| `defaultModel` | `string` | `"
|
|
186
|
+
| `defaultModel` | `string` | `"claude-3-7-sonnet"` | 默认选中的模型 ID(用于对话及探活) |
|
|
187
|
+
| `disabledModels` | `array` | `[]` | 在选择器中隐藏的模型 ID 列表(新订阅模型默认自动启用) |
|
|
188
|
+
| `customModels` | `array` | `[]` | 用户自定义网关模型 (`[{ id, name, contextLength, maxTokens, category, isReasoning }]`) |
|
|
189
|
+
| `modelReasoningDefaults` | `object` | `{}` | 各模型默认思考强度配置 (`low`, `medium`, `high`, `max`) |
|
|
182
190
|
| `modelContextOverrides` | `array` | `[]` | 用户自定义模型上下文窗口与最大 Token 数量覆盖 |
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
191
|
+
| `proxyMode` | `boolean` | `true` | 启用透明本地环回代理以支持会话粘性路由与 429 自动故障转移 |
|
|
192
|
+
| `statsPath` | `string` | `"~/.dsh/clinebot-stats.json"` | 本地持久化 Token 用量统计文件路径 |
|
|
193
|
+
| `accounts` | `array` | `[]` | 额外轮转账号池 (`[{ label, apiKeyEnv }]`) |
|
|
194
|
+
| `activeAccount` | `string` | `""` | 手动指定的主账号(为空时自动按最低配额消耗优先路由) |
|
|
195
|
+
| `timeoutMs` | `number` | `30000` | HTTP 请求探测超时时间(毫秒) |
|
|
196
|
+
| `smokeTimeoutMs` | `number` | `60000` | 探活测试超时时间(毫秒) |
|
|
197
|
+
| `streamIdleTimeoutMs` | `number` | `60000` | SSE 流式输出块间空闲超时时间(毫秒) |
|
|
198
|
+
| `enabledModels` | `array` | *(已废弃)* | 仅在 public config 中只读提供,`PUT /config` 时禁止写入并请使用 `disabledModels` |
|
|
186
199
|
| `dynamicModels` | `array` | `[]` | 从官方套餐中自动同步的动态模型列表 |
|
|
187
200
|
|
|
188
201
|
---
|
package/lib/account-pool.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveKeyValue, usageCache, clearUsageCache, clearProbeCache, DEFAULT_API_KEY_ENV } from './cline-client.js'
|
|
1
|
+
import { resolveKeyValue, usageCache, clearUsageCache, clearProbeCache, DEFAULT_API_KEY_ENV, DEFAULT_BASE_URL, buildUsageCacheKey } from './cline-client.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Resolve all accounts in pool with their status and keys.
|
|
@@ -32,9 +32,9 @@ function toPlainSnapshot(cfg) {
|
|
|
32
32
|
return out
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function getAccountQuotaSnapshot(accValue) {
|
|
35
|
+
export function getAccountQuotaSnapshot(accValue, baseUrl = DEFAULT_BASE_URL) {
|
|
36
36
|
if (!accValue || typeof accValue !== 'string') return null
|
|
37
|
-
const cacheKey =
|
|
37
|
+
const cacheKey = buildUsageCacheKey(baseUrl, accValue)
|
|
38
38
|
const cached = usageCache.get(cacheKey)?.data
|
|
39
39
|
if (!cached?.windows) return null
|
|
40
40
|
|
|
@@ -67,6 +67,7 @@ export function getAccountQuotaSnapshot(accValue) {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export async function resolveAccountPool(ctx, cfg) {
|
|
70
|
+
const baseUrl = textSetting(cfg?.baseUrl) || DEFAULT_BASE_URL
|
|
70
71
|
const apiKeyEnv = textSetting(cfg?.apiKeyEnv) || DEFAULT_API_KEY_ENV
|
|
71
72
|
const defaultSlot = {
|
|
72
73
|
id: 'default',
|
|
@@ -86,7 +87,7 @@ export async function resolveAccountPool(ctx, cfg) {
|
|
|
86
87
|
const isPinned = activeAccount === 'auto'
|
|
87
88
|
? false
|
|
88
89
|
: (activeAccount ? (activeAccount === envName || activeAccount === slotId) : i === 0)
|
|
89
|
-
const quota = keyInfo.value ? getAccountQuotaSnapshot(keyInfo.value) : null
|
|
90
|
+
const quota = keyInfo.value ? getAccountQuotaSnapshot(keyInfo.value, baseUrl) : null
|
|
90
91
|
resolved.push({
|
|
91
92
|
id: slotId,
|
|
92
93
|
label: textSetting(slot.label) || (i === 0 ? 'Default' : `Account ${i + 1}`),
|
|
@@ -128,6 +129,7 @@ export function isAccountQuotaExhausted(usage) {
|
|
|
128
129
|
* Prioritizes accounts with lowest percentUsed and respects resetsAt recovery.
|
|
129
130
|
*/
|
|
130
131
|
export async function rotateToNextAccount(ctx, cfg, reason = 'rate_limit', settingsApi = null) {
|
|
132
|
+
const baseUrl = textSetting(cfg?.baseUrl) || DEFAULT_BASE_URL
|
|
131
133
|
const pool = await resolveAccountPool(ctx, cfg)
|
|
132
134
|
const configured = pool.filter((acc) => acc.present && acc.value)
|
|
133
135
|
if (configured.length <= 1) {
|
|
@@ -148,7 +150,7 @@ export async function rotateToNextAccount(ctx, cfg, reason = 'rate_limit', setti
|
|
|
148
150
|
let lowestUsagePct = Infinity
|
|
149
151
|
|
|
150
152
|
for (const cand of candidates) {
|
|
151
|
-
const cacheKey =
|
|
153
|
+
const cacheKey = buildUsageCacheKey(baseUrl, cand.value)
|
|
152
154
|
const cached = usageCache.get(cacheKey)?.data
|
|
153
155
|
const isExhausted = isAccountQuotaExhausted(cached)
|
|
154
156
|
|