pi-ccswitch-auto-switch 0.3.1 → 0.3.2
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/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/health.ts +12 -2
- package/index.ts +11 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ The extension observes real Pi requests, records sanitized health signals, and
|
|
|
13
13
|
- Endpoint circuit breakers for DNS, connection, server, and streaming failures.
|
|
14
14
|
- Endpoint platform isolation: when several models on the same endpoint (same BaseURL/provider) fail within one round, the whole endpoint is isolated so sibling models from the same platform are not tried one by one.
|
|
15
15
|
- Model-only isolation for missing models and incompatible parameters.
|
|
16
|
-
- Learns model-family content-policy constraints from real failures (`glm-4.5` and `GLM-4.6`, for example, are both `glm`) and avoids the entire family during current
|
|
16
|
+
- Learns model-family content-policy constraints from real failures (`glm-4.5` and `GLM-4.6`, for example, are both `glm`) and avoids the entire family during the current content-policy failover chain. Evidence is session-scoped: it is cleared at `session_start`, because a new session may handle tasks that are not content-sensitive, so the family becomes eligible again until this session observes its own content-policy rejection.
|
|
17
17
|
- Applies hard health, failure-domain, policy-family, input-modality, and context filters before ranking candidates by provider diversity, model equivalence, capability compatibility, and historical reliability.
|
|
18
18
|
- Independent-provider semantics: a copied vendor (e.g. `my-provider-copy`) shares the BaseURL but is a distinct provider with its own endpoint key, so isolating one never blocks the other.
|
|
19
19
|
- 90-second first-response and 120-second streaming-idle watchdogs.
|
|
@@ -107,7 +107,7 @@ The state machine waits for Pi's native retry cycle to settle before switching.
|
|
|
107
107
|
| `429` | Provider | `Retry-After` when present; otherwise 5 minutes |
|
|
108
108
|
| DNS, network, `408`, `5xx`, interrupted stream | Endpoint | 2 minutes |
|
|
109
109
|
| `404`, invalid model, incompatible parameters | Model | 15 minutes |
|
|
110
|
-
| Content-policy or sensitive-content rejection | Current model + learned model-family constraint | 2-minute model cooldown;
|
|
110
|
+
| Content-policy or sensitive-content rejection | Current model + learned model-family constraint | 2-minute model cooldown; family evidence is session-scoped (cleared at `session_start`) |
|
|
111
111
|
| Context overflow | Current round only | None |
|
|
112
112
|
|
|
113
113
|
Cooldowns grow exponentially within bounded limits. Learned policy-constrained families are excluded only after a content-policy rejection; they remain eligible during ordinary rate-limit, network, and model-configuration failovers. Context-overflow retries only consider models with a larger context window, and image requests do not move to a model that explicitly supports text only. Unknown errors are isolated to the current model and still fail over normally. A user cancellation is the only aborted turn that does not trigger failover; watchdog cancellations are recorded as timeouts.
|
package/README.zh-CN.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- 对认证、额度、账单和限流实施 Provider 优先熔断。
|
|
13
13
|
- 对 DNS、连接、服务端和流中断实施端点熔断。
|
|
14
14
|
- 模型不存在或参数不兼容时仅隔离该模型。
|
|
15
|
-
- 内容审查失败会学习模型系列约束(例如 `glm-4.5`、`GLM-4.6` 同属 `glm
|
|
15
|
+
- 内容审查失败会学习模型系列约束(例如 `glm-4.5`、`GLM-4.6` 同属 `glm`),在本轮内容审查故障转移中避开整个受限系列。该约束按 session 隔离:`session_start` 时清除,因为新 session 处理的任务不一定涉及审查内容,模型系列恢复可用,直到本 session 再次观察到内容审查拒绝。
|
|
16
16
|
- 候选模型先经过健康、故障域、审查系列、输入模态和上下文窗口硬过滤,再按跨 Provider、模型等价性、能力兼容和历史稳定性排序。
|
|
17
17
|
- 首响应 90 秒、流式停滞 120 秒看门狗。
|
|
18
18
|
- 指数退避、`Retry-After` 支持和跨进程 half-open 单探针租约。
|
|
@@ -95,7 +95,7 @@ CCS v0.3.1 ✓70/131 · ⏳61 · ⛔0 · 🔄3 · provider/model-id
|
|
|
95
95
|
| `429` | Provider | 优先使用 `Retry-After`,否则 5 分钟 |
|
|
96
96
|
| DNS、网络、`408`、`5xx`、流中断 | 端点 | 2 分钟 |
|
|
97
97
|
| `404`、模型不存在、参数不兼容 | 模型 | 15 分钟 |
|
|
98
|
-
| 内容审查/敏感拦截 | 当前模型 + 模型系列约束 | 模型冷却 2
|
|
98
|
+
| 内容审查/敏感拦截 | 当前模型 + 模型系列约束 | 模型冷却 2 分钟;系列约束按 session 隔离(`session_start` 时清除) |
|
|
99
99
|
| 上下文溢出 | 仅本轮 | 无 |
|
|
100
100
|
|
|
101
101
|
冷却时间会指数增长但有上限。发生内容审查时,插件只在审查故障转移链中避开已标记系列,普通限流、网络或模型配置故障仍可选择这些模型。上下文溢出时只会选择上下文窗口更大的模型;带图片的请求不会切到明确仅支持文本的模型。无法归类的异常按单模型故障处理并正常切换。用户主动取消是唯一不会触发故障转移的异常终止;看门狗取消会记录为超时。
|
package/health.ts
CHANGED
|
@@ -158,8 +158,9 @@ export class HealthStore {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
161
|
+
* 内容审查约束是当前 session 的观测,按 session 隔离:新 session 可能处理
|
|
162
|
+
* 不涉及审查内容的任务,因此约束在 session_start 时清除,不跨 session 继承;
|
|
163
|
+
* 本 session 内再次观察到同系列审查会增加证据计数并刷新时间戳。
|
|
163
164
|
*/
|
|
164
165
|
recordContentPolicyConstraint(family: string, model: ModelRef, message?: string): void {
|
|
165
166
|
const constraints = this.state.contentPolicyFamilies ??= {}
|
|
@@ -235,6 +236,15 @@ export class HealthStore {
|
|
|
235
236
|
this.touch()
|
|
236
237
|
}
|
|
237
238
|
|
|
239
|
+
/**
|
|
240
|
+
* 清除已学习的模型系列内容审查约束。新 session 可能处理不同任务,不假设
|
|
241
|
+
* 对审查内容敏感,因此不在 session 间继承审查约束。
|
|
242
|
+
*/
|
|
243
|
+
clearContentPolicyConstraints(): void {
|
|
244
|
+
this.state.contentPolicyFamilies = {}
|
|
245
|
+
this.touch()
|
|
246
|
+
}
|
|
247
|
+
|
|
238
248
|
isBlocked(model: ModelRef, now = Date.now()): boolean {
|
|
239
249
|
return [this.state.models[modelKey(model)], this.state.providers[model.provider], this.state.endpoints[endpointKey(model)]]
|
|
240
250
|
.some(record => Boolean(record?.disabled || (record?.cooldownUntil && record.cooldownUntil > now) || (record?.leaseUntil && record.leaseUntil > now)))
|
package/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ const STREAM_IDLE_TIMEOUT = 120_000
|
|
|
8
8
|
const MAX_ATTEMPTS = 5
|
|
9
9
|
const ROUND_LIMIT = 8 * 60_000
|
|
10
10
|
const RPC_PROTOCOL_VERSION = 1
|
|
11
|
-
const EXTENSION_VERSION = '0.3.
|
|
11
|
+
const EXTENSION_VERSION = '0.3.2'
|
|
12
12
|
// 同端点(BaseURL 相同)连续失败达到该次数即隔离该端点,避免同一个平台的多个模型逐个试错耗尽本轮切换
|
|
13
13
|
const ENDPOINT_FAIL_THRESHOLD = 3
|
|
14
14
|
|
|
@@ -267,7 +267,16 @@ export default function (pi: ExtensionAPI) {
|
|
|
267
267
|
await exhaust(ctx, '没有健康的候选模型')
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
pi.on('session_start', async (_event, ctx) => {
|
|
270
|
+
pi.on('session_start', async (_event, ctx) => {
|
|
271
|
+
await health.load()
|
|
272
|
+
sessionSwitches = 0
|
|
273
|
+
// 新 session 可能处理不涉及审查内容的任务,上一 session 学到的模型系列审查约束
|
|
274
|
+
// 不跨 session 继承;若本 session 再次遇到 content_policy 失败会重新学习并在本轮避开。
|
|
275
|
+
health.clearContentPolicyConstraints()
|
|
276
|
+
await health.flush()
|
|
277
|
+
await refresh(ctx)
|
|
278
|
+
await health.log('extension started')
|
|
279
|
+
})
|
|
271
280
|
pi.on('session_shutdown', async (_event, ctx) => { clearWatchdog(); ctx.ui.setWorkingMessage(); if (sessionSwitches > 0) await health.log(`session ended with ${sessionSwitches} successful switches`); await health.flush() })
|
|
272
281
|
pi.on('input', (event, ctx) => {
|
|
273
282
|
if (event.source === 'extension') return { action: 'continue' }
|