@wengine-ai/llms 2.3.2415 → 2.3.2416
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 +1 -0
- package/dist/api/empty-answer-guard.d.ts +66 -0
- package/dist/ccr/models.d.ts +9 -1
- package/dist/cjs/server.cjs +199 -198
- package/dist/cjs/server.cjs.map +4 -4
- package/dist/esm/server.mjs +191 -190
- package/dist/esm/server.mjs.map +4 -4
- package/dist/provider-plugins/types.d.ts +54 -0
- package/dist/services/active-probe.d.ts +44 -3
- package/dist/services/provider-health.d.ts +17 -0
- package/package.json +2 -2
|
@@ -56,6 +56,30 @@ export interface PluginDispatchInput {
|
|
|
56
56
|
* spreads) for per-request wrapper state. */
|
|
57
57
|
req?: any;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Outcome of a level-1 account-state check.
|
|
61
|
+
*
|
|
62
|
+
* `available: false` parks the provider without a network call; `parkedUntil`
|
|
63
|
+
* lets the plugin tell the core when the account frees up (e.g. a quota reset
|
|
64
|
+
* epoch), so the probe does not re-check before then.
|
|
65
|
+
*/
|
|
66
|
+
export interface ManagedProbeVerdict {
|
|
67
|
+
available: boolean;
|
|
68
|
+
/** Epoch ms after which the account may be usable again. */
|
|
69
|
+
parkedUntil?: number;
|
|
70
|
+
/** Stable reason used for logging only — never shown to a client. */
|
|
71
|
+
reason?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Input for a runtime-owned liveness probe. */
|
|
74
|
+
export interface ManagedProbeInput {
|
|
75
|
+
/** One ordinary core dispatch attempt (same seam as `PluginDispatchInput.attempt`). */
|
|
76
|
+
attempt(): Promise<Response>;
|
|
77
|
+
/** Model to probe with (the first circuit-open model of the provider). */
|
|
78
|
+
model: string;
|
|
79
|
+
provider: LLMProvider;
|
|
80
|
+
/** Per-attempt config; the core sets `TIMEOUT` so a probe cannot outlive its budget. */
|
|
81
|
+
config: any;
|
|
82
|
+
}
|
|
59
83
|
/**
|
|
60
84
|
* Managed-subscription semantics for one provider family. Everything the data
|
|
61
85
|
* plane needs to talk to a subscription upstream without the core knowing it:
|
|
@@ -109,6 +133,36 @@ export interface ManagedRuntime {
|
|
|
109
133
|
* hard attempt bound and must never swallow client aborts.
|
|
110
134
|
*/
|
|
111
135
|
dispatchRequest?(input: PluginDispatchInput): Promise<Response>;
|
|
136
|
+
/**
|
|
137
|
+
* Cheap account-state check used by the background recovery probe.
|
|
138
|
+
*
|
|
139
|
+
* Two-level probing exists because account state and reachability fail
|
|
140
|
+
* independently: a parked/over-quota account must NOT spend a network call
|
|
141
|
+
* (the Gemini lesson), while a healthy-but-unreachable account must not be
|
|
142
|
+
* restored to the model list on the strength of its state alone. The core
|
|
143
|
+
* calls this FIRST and only issues the (expensive) real request when it
|
|
144
|
+
* resolves.
|
|
145
|
+
*
|
|
146
|
+
* Resolve to use the `available` hint semantics below; throw a classified
|
|
147
|
+
* error (e.g. `*_account_cooling`) to report the account as unusable. When
|
|
148
|
+
* absent, the core falls back to `ensureUsable()` — which is the same check
|
|
149
|
+
* every real request already performs — so plugins that only implement the
|
|
150
|
+
* circuit breaker still work.
|
|
151
|
+
*/
|
|
152
|
+
probeAccountState?(): Promise<ManagedProbeVerdict>;
|
|
153
|
+
/**
|
|
154
|
+
* Optional runtime-owned liveness probe (level 2).
|
|
155
|
+
*
|
|
156
|
+
* Called only after `probeAccountState`/`ensureUsable` reported the account as
|
|
157
|
+
* usable. Implementations should make the cheapest request that still proves
|
|
158
|
+
* the upstream answers for THIS account (a quota/status endpoint is ideal,
|
|
159
|
+
* otherwise a 1-token chat). Must honour the supplied signal/timeout and must
|
|
160
|
+
* not persist cooldowns that a probe is not allowed to set.
|
|
161
|
+
*
|
|
162
|
+
* When absent the core performs a generic 1-token request through
|
|
163
|
+
* `dispatchRequest` (see `PluginDispatchInput`).
|
|
164
|
+
*/
|
|
165
|
+
probeLiveness?(input: ManagedProbeInput): Promise<Response>;
|
|
112
166
|
/**
|
|
113
167
|
* Opt-in 401 handling: when set, the core performs ONE forced refresh and
|
|
114
168
|
* re-dispatch on 401 before classifying. `refresh` must persist rotated
|
|
@@ -57,9 +57,13 @@ export declare class ActiveProbeService {
|
|
|
57
57
|
private resolveProxyUrl?;
|
|
58
58
|
private logger?;
|
|
59
59
|
private getConfig?;
|
|
60
|
+
/** Resolves the installed plugin runtime that owns a managed provider. */
|
|
61
|
+
private resolveManagedRuntime?;
|
|
62
|
+
/** Periodic timer for managed-subscription recovery probing. */
|
|
63
|
+
private managedProbeTimer?;
|
|
60
64
|
private running;
|
|
61
65
|
private probeTelemetry;
|
|
62
|
-
constructor(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any);
|
|
66
|
+
constructor(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any, resolveManagedRuntime?: (provider: LLMProvider) => any);
|
|
63
67
|
/**
|
|
64
68
|
* Record the latest reachability probe result for a provider.
|
|
65
69
|
* Only /models-style reachability probes (health, manual, rate-limit header
|
|
@@ -102,6 +106,43 @@ export declare class ActiveProbeService {
|
|
|
102
106
|
* Rate-limited models are NOT probed by runHealthProbe — they have a separate timer
|
|
103
107
|
* so they can be checked more frequently (every 2 minutes) without affecting normal probes.
|
|
104
108
|
*/
|
|
109
|
+
/**
|
|
110
|
+
* Recover circuit-open MANAGED (subscription) providers with one real request.
|
|
111
|
+
*
|
|
112
|
+
* runHealthProbe deliberately skips managed providers: their credentials are
|
|
113
|
+
* plugin-owned, so an unauthenticated GET /v1/models would fail for reasons
|
|
114
|
+
* unrelated to health. The consequence was that a subscription provider whose
|
|
115
|
+
* circuit opened (exhausted quota, revoked token, upstream outage) had NO
|
|
116
|
+
* background path back to healthy — it stayed circuit-open and the only way it
|
|
117
|
+
* ever recovered was a real user request hitting it again, which is exactly the
|
|
118
|
+
* "keeps failing and keeps being called" behaviour.
|
|
119
|
+
*
|
|
120
|
+
* This closes that loop: for each managed provider with a circuit-open model
|
|
121
|
+
* whose probe interval has elapsed, issue one minimal request through the
|
|
122
|
+
* plugin's own dispatcher (so token refresh, account rotation and the plugin's
|
|
123
|
+
* error taxonomy all apply) and restore its models only when the upstream
|
|
124
|
+
* actually answered.
|
|
125
|
+
*/
|
|
126
|
+
runManagedRecoveryProbe(): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Level 1 of the managed recovery probe: is the ACCOUNT usable at all?
|
|
129
|
+
*
|
|
130
|
+
* Returns false when the account is parked (quota exhausted / verification
|
|
131
|
+
* needed / risk-blocked), in which case the caller must skip the liveness call
|
|
132
|
+
* entirely — testing the network for an account that cannot answer is pure
|
|
133
|
+
* waste and, for subscription providers, a rate-limit risk.
|
|
134
|
+
*/
|
|
135
|
+
private probeManagedAccountState;
|
|
136
|
+
/**
|
|
137
|
+
* Level 2 of the managed recovery probe: does the upstream actually answer?
|
|
138
|
+
*
|
|
139
|
+
* Uses a runtime-owned `probeLiveness` when the plugin provides one (a quota or
|
|
140
|
+
* status endpoint costs no chat quota), otherwise performs a generic 1-token
|
|
141
|
+
* request through the runtime's dispatcher. The dispatcher input carries a real
|
|
142
|
+
* `attempt()` and a per-attempt `config` — both are REQUIRED by
|
|
143
|
+
* `PluginDispatchInput`, and omitting them made wrappers fail unconditionally.
|
|
144
|
+
*/
|
|
145
|
+
private probeManagedLiveness;
|
|
105
146
|
private runRateLimitProbe;
|
|
106
147
|
/**
|
|
107
148
|
* Run scheduled wake-up for configured providers
|
|
@@ -122,11 +163,11 @@ export declare class ActiveProbeService {
|
|
|
122
163
|
/**
|
|
123
164
|
* Initialize and get the active probe service
|
|
124
165
|
*/
|
|
125
|
-
export declare function getActiveProbeService(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any): ActiveProbeService;
|
|
166
|
+
export declare function getActiveProbeService(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any, resolveManagedRuntime?: (provider: LLMProvider) => any): ActiveProbeService;
|
|
126
167
|
/**
|
|
127
168
|
* Start the active probe service (convenience function)
|
|
128
169
|
*/
|
|
129
|
-
export declare function startActiveProbe(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any): ActiveProbeService;
|
|
170
|
+
export declare function startActiveProbe(getProviders: () => LLMProvider[], config?: ActiveProbeConfig, resolveProxyUrl?: (provider: LLMProvider) => string | undefined, logger?: any, getConfig?: (key: string) => any, resolveManagedRuntime?: (provider: LLMProvider) => any): ActiveProbeService;
|
|
130
171
|
/**
|
|
131
172
|
* Stop the active probe service
|
|
132
173
|
*/
|
|
@@ -76,6 +76,23 @@ export declare class ProviderHealthStore {
|
|
|
76
76
|
* Get all models in fail pool (open status)
|
|
77
77
|
*/
|
|
78
78
|
getFailPoolModels(): string[];
|
|
79
|
+
/**
|
|
80
|
+
* Stamp a background probe attempt without changing circuit state.
|
|
81
|
+
*
|
|
82
|
+
* Recovery probes need this: a failed probe must keep the model circuit-open
|
|
83
|
+
* but move `lastProbeTime` forward, otherwise the interval gate in
|
|
84
|
+
* isAvailable()/the probe loop would re-probe on every tick.
|
|
85
|
+
*/
|
|
86
|
+
recordProbeAttempt(provider: string, model: string): void;
|
|
87
|
+
/**
|
|
88
|
+
* Park a model until the account's own reset epoch.
|
|
89
|
+
*
|
|
90
|
+
* A plugin that reports its quota window (e.g. `resets_at`) knows better than
|
|
91
|
+
* a fixed probe interval when the account can answer again. Setting
|
|
92
|
+
* `rateLimitUntil` keeps the model hidden from the list AND stops the recovery
|
|
93
|
+
* probe from spending network calls on a known-parked account.
|
|
94
|
+
*/
|
|
95
|
+
markParkedUntil(provider: string, model: string, until: number): void;
|
|
79
96
|
/**
|
|
80
97
|
* Get all models in half-open state
|
|
81
98
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wengine-ai/llms",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2416",
|
|
4
4
|
"description": "A universal LLM API transformation server",
|
|
5
5
|
"main": "dist/cjs/server.cjs",
|
|
6
6
|
"module": "dist/esm/server.mjs",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"uuid": "^11.1.0",
|
|
65
65
|
"@fastify/multipart": "^9.0.0",
|
|
66
66
|
"@fastify/static": "^8.2.0",
|
|
67
|
-
"@wengine-ai/claude-code-router-shared": "^2.3.
|
|
67
|
+
"@wengine-ai/claude-code-router-shared": "^2.3.2416",
|
|
68
68
|
"adm-zip": "^0.5.16",
|
|
69
69
|
"better-sqlite3": "^12.10.0",
|
|
70
70
|
"rotating-file-stream": "^3.2.7"
|