pi-ccswitch-auto-switch 0.1.6 → 0.1.7
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/classify.ts +3 -1
- package/index.ts +10 -2
- package/package.json +1 -1
package/classify.ts
CHANGED
|
@@ -17,7 +17,9 @@ export function classifyFailure(observation: FailureObservation): Classification
|
|
|
17
17
|
const status = observation.status
|
|
18
18
|
if (observation.aborted && !observation.watchdog) return { kind: 'unknown', roundOnly: true }
|
|
19
19
|
if (observation.watchdog) return { kind: 'timeout', scope: 'endpoint', roundOnly: false }
|
|
20
|
-
|
|
20
|
+
// 内容审查/敏感拦截属于该模型的失败:按 model 级记录并与冷却(2min×2ⁿ 上限 30min),
|
|
21
|
+
// chooseCandidate 会排除后自动切换到其他模型,而不是同一内容原样重试到本轮上限。
|
|
22
|
+
if (content.test(text)) return { kind: 'content_policy', scope: 'model', roundOnly: false }
|
|
21
23
|
if (context.test(text)) return { kind: 'context_overflow', roundOnly: true }
|
|
22
24
|
if (status === 429) return { kind: 'rate_limit', scope: 'provider', roundOnly: false, retryAfterMs: observation.retryAfterMs }
|
|
23
25
|
if (status === 401 || status === 403) return { kind: 'auth', scope: 'provider', roundOnly: false }
|
package/index.ts
CHANGED
|
@@ -32,6 +32,8 @@ interface Round {
|
|
|
32
32
|
observation?: FailureObservation
|
|
33
33
|
model?: ModelRef
|
|
34
34
|
endpointFails?: EndpointFailTracker
|
|
35
|
+
/** 本轮内最后一次成功切换的时间;用于刷新 ROUND_LIMIT 窗口,避免供应商内部重试耗时导致误判“达到上限” */
|
|
36
|
+
lastSwitchAt?: number
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
function key(model: ModelRef | undefined): string | undefined { return model && modelKey(model) }
|
|
@@ -69,9 +71,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
69
71
|
const activeModel = round?.model ?? ctx.model
|
|
70
72
|
// 恒显完整状态:健康/总数 · 冷却 · 禁用 · 本session切换 · 当前模型(均为 0 时也显示,便于确认扩展在监控中)
|
|
71
73
|
const plain = round?.phase === 'switching' ? `CCS ↻${round.attempts}/${MAX_ATTEMPTS} ${modelTag(round.model)}` :
|
|
74
|
+
round?.phase === 'exhausted' ? `CCS ⏸切换停止 ${modelTag(round.model ?? ctx.model)}` :
|
|
72
75
|
`CCS ✓${counts.healthy}/${counts.total} · ⏳${counts.cooling} · ⛔${counts.disabled}${switchSuffix()} · ${modelTag(activeModel)}`
|
|
73
76
|
const theme = ctx.ui.theme
|
|
74
|
-
|
|
77
|
+
const tone = round?.phase === 'exhausted' ? 'error' : counts.cooling || counts.disabled ? 'warning' : 'success'
|
|
78
|
+
ctx.ui.setStatus('ccswitch-ha', theme ? theme.fg(tone, plain) : plain)
|
|
75
79
|
}
|
|
76
80
|
// 本次 session 成功切换计数:始终显示 🔄N(N=0 也显示,用于确认扩展在监控中);累计切换数在面板/自检中可见
|
|
77
81
|
const switchSuffix = () => ` · 🔄${sessionSwitches}`
|
|
@@ -140,7 +144,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
140
144
|
}
|
|
141
145
|
const failover = async (ctx: ExtensionContext) => {
|
|
142
146
|
if (!round || !round.observation || !round.model || !canRetry(ctx)) return
|
|
143
|
-
|
|
147
|
+
// 窗口从上一次成功切换(或本轮开始)起算:供应商内部重试耗时不应消耗整轮限额
|
|
148
|
+
const windowStart = Math.max(round.startedAt, round.lastSwitchAt ?? 0)
|
|
149
|
+
if (round.attempts >= MAX_ATTEMPTS || Date.now() - windowStart >= ROUND_LIMIT) return exhaust(ctx, '达到本轮切换上限')
|
|
144
150
|
const classification = classifyFailure(round.observation)
|
|
145
151
|
if (round.observation.aborted && !round.observation.watchdog) { round.phase = 'idle'; clearWatchdog(); status(ctx); return }
|
|
146
152
|
round.phase = 'switching'
|
|
@@ -173,6 +179,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
173
179
|
}
|
|
174
180
|
round.model = next
|
|
175
181
|
round.phase = 'redispatching'
|
|
182
|
+
// 刷新本轮切换时间窗:成功切换后重新起算 ROUND_LIMIT,避免长重试轮被误判为“达到上限”
|
|
183
|
+
round.lastSwitchAt = Date.now()
|
|
176
184
|
// 本次 session 成功切换计数 + 持久化累计/日志(衡量扩展有效程度)
|
|
177
185
|
sessionSwitches += 1
|
|
178
186
|
const fromKey = key(round.model ?? ctx.model)
|