@omnicross/subscriptions 0.1.0 → 0.1.3
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/dist/chunk-IXGHVMZB.js +365 -0
- package/dist/chunk-TPW5Q25Y.cjs +365 -0
- package/dist/index.cjs +508 -662
- package/dist/index.d.cts +154 -670
- package/dist/index.d.ts +154 -670
- package/dist/index.js +408 -522
- package/dist/oauth.cjs +4 -390
- package/dist/oauth.d.cts +3 -4
- package/dist/oauth.d.ts +3 -4
- package/dist/oauth.js +5 -358
- package/package.json +2 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { AccountTokensConfig } from '@omnicross/contracts/account-tokens-types';
|
|
2
|
-
import { SubscriptionProviderId, SubscriptionStatusEntry, SubscriptionListEntry, OpenCodeGoTokenConfig
|
|
2
|
+
import { SubscriptionProviderId, SubscriptionStatusEntry, SubscriptionListEntry, OpenCodeGoTokenConfig } from '@omnicross/contracts/subscription-types';
|
|
3
|
+
import { AuthStrategy } from '@omnicross/core/pipeline/SubscriptionAuthStrategy';
|
|
4
|
+
export { AuthApplyHints, AuthStrategy } from '@omnicross/core/pipeline/SubscriptionAuthStrategy';
|
|
5
|
+
import { SubscriptionDispatchProfile } from '@omnicross/core/provider-proxy/types';
|
|
6
|
+
export { SubscriptionDispatchProfile, SubscriptionRequestSummary } from '@omnicross/core/provider-proxy/types';
|
|
3
7
|
import http from 'node:http';
|
|
4
|
-
|
|
8
|
+
import { TransformerChainExecutor } from '@omnicross/core/transformer/TransformerChainExecutor';
|
|
9
|
+
import { TransformerService } from '@omnicross/core/transformer/TransformerService';
|
|
10
|
+
import { Transformer } from '@omnicross/core/transformer/types';
|
|
11
|
+
export { FetchLike } from '@omnicross/core/auth/GeminiCodeAssistProjectResolver';
|
|
12
|
+
export { claudeOAuth, codexOAuth, geminiOAuth } from './oauth.cjs';
|
|
5
13
|
|
|
6
14
|
/**
|
|
7
15
|
* SubscriptionCredentialStore — the credential port the subscription block
|
|
@@ -19,7 +27,15 @@ export { FetchLike, claudeOAuth, codexOAuth, geminiOAuth } from './oauth.cjs';
|
|
|
19
27
|
* subscriptions layer).
|
|
20
28
|
*/
|
|
21
29
|
|
|
22
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* The credential surface the subscription block consumes from the host store.
|
|
32
|
+
*
|
|
33
|
+
* The six ORIGINAL methods (active-account getters + refreshers) are REQUIRED;
|
|
34
|
+
* the three by-id methods (subscription-account-scheduling, design D6) are
|
|
35
|
+
* OPTIONAL and feature-detected so every existing lightweight test double that
|
|
36
|
+
* implements only the six keeps compiling and the single-account active path is
|
|
37
|
+
* untouched.
|
|
38
|
+
*/
|
|
23
39
|
interface SubscriptionCredentialStore {
|
|
24
40
|
/** Full decrypted account-tokens config (all subscription providers). */
|
|
25
41
|
getFullConfig(): Promise<AccountTokensConfig>;
|
|
@@ -33,64 +49,124 @@ interface SubscriptionCredentialStore {
|
|
|
33
49
|
refreshGeminiToken(): Promise<boolean>;
|
|
34
50
|
/** Current valid OpenCodeGo static API key; `null` if none. */
|
|
35
51
|
getValidOpenCodeGoApiKey(): Promise<string | null>;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a SPECIFIC account's access token by id (refreshing a near-expiry
|
|
54
|
+
* OAuth token for that account, mirroring the active getter's per-provider
|
|
55
|
+
* refresh policy). `null` when the account is unknown/expired/tokenless.
|
|
56
|
+
*/
|
|
57
|
+
getAccessTokenForAccount?(providerId: SubscriptionProviderId, accountId: string): Promise<string | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Force a refresh of a SPECIFIC account's OAuth token by id; `true` on success.
|
|
60
|
+
* Static-key providers (opencodego) return `false` — they don't refresh.
|
|
61
|
+
*/
|
|
62
|
+
refreshAccountToken?(providerId: SubscriptionProviderId, accountId: string): Promise<boolean>;
|
|
63
|
+
/**
|
|
64
|
+
* Best-effort record of a selection's time onto the account's `lastUsedAt`
|
|
65
|
+
* (throttled by the selector so the hot path does not rewrite the store every
|
|
66
|
+
* request). Durability only — never affects which credential is valid.
|
|
67
|
+
*/
|
|
68
|
+
touchAccountLastUsed?(providerId: SubscriptionProviderId, accountId: string, iso: string): Promise<void>;
|
|
36
69
|
}
|
|
37
70
|
|
|
38
71
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
72
|
+
* SubscriptionAccountSelector — the pure, in-memory account scheduler
|
|
73
|
+
* (subscription-account-scheduling, design D3).
|
|
74
|
+
*
|
|
75
|
+
* Given a provider's account list (+ an optional session key) it decides WHICH
|
|
76
|
+
* account of the pool serves the outbound request:
|
|
41
77
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* `
|
|
45
|
-
*
|
|
78
|
+
* filter `schedulable !== false`
|
|
79
|
+
* → session-affinity short-circuit (sticky `sessionKey → accountId`, TTL 1h)
|
|
80
|
+
* → sort by `priority` asc → effective `lastUsedAt` asc (LRU) → `createdAt` asc
|
|
81
|
+
* → `[0]`.
|
|
46
82
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
* (
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
83
|
+
* A faithful port of CRS `sortAccountsByPriority` + `unifiedClaudeScheduler`
|
|
84
|
+
* session mapping. The class holds process-lived state — the affinity map and an
|
|
85
|
+
* in-memory `lastUsedAt` overlay (the authoritative live tie-break value, seeded
|
|
86
|
+
* from the persisted field and advanced to `now` on each selection so repeated
|
|
87
|
+
* selections round-robin fairly even before any durable persist). ONE instance is
|
|
88
|
+
* constructed at bootstrap and SHARED by all three auth strategies (each scopes
|
|
89
|
+
* its calls by `providerId`), mirroring the single long-lived CRS scheduler.
|
|
53
90
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
91
|
+
* ZERO-REGRESSION CARRIER: `select()` returns `null` when the schedulable account
|
|
92
|
+
* count is ≤ 1. Callers treat `null` (and an `isActive` result) as "use the
|
|
93
|
+
* existing active-mirror path", so a single-account provider exercises NO new
|
|
94
|
+
* code and its token read is byte-identical to before this change.
|
|
58
95
|
*
|
|
59
|
-
* @module
|
|
96
|
+
* @module scheduler/SubscriptionAccountSelector
|
|
60
97
|
*/
|
|
61
98
|
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
*
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
99
|
+
/** Sticky session→account affinity TTL (CRS parity: 1 hour). */
|
|
100
|
+
declare const SESSION_AFFINITY_TTL_MS = 3600000;
|
|
101
|
+
/** Min gap between best-effort `lastUsedAt` durable persists, per account. */
|
|
102
|
+
declare const LAST_USED_PERSIST_THROTTLE_MS = 60000;
|
|
103
|
+
/** Precedence assumed for an account with no `priority` (CRS `|| 50`). */
|
|
104
|
+
declare const DEFAULT_ACCOUNT_PRIORITY = 50;
|
|
105
|
+
/** One schedulable candidate — the scheduling projection of an account entry. */
|
|
106
|
+
interface SchedulableAccount {
|
|
107
|
+
id: string;
|
|
108
|
+
/** Default `50` (lower = higher precedence). */
|
|
109
|
+
priority?: number;
|
|
110
|
+
/** ISO — LRU tie-break; absent ⇒ treated as least-recently-used (`0`). */
|
|
111
|
+
lastUsedAt?: string;
|
|
112
|
+
/** ISO — final tie-break; absent ⇒ oldest (`0`). */
|
|
113
|
+
createdAt?: string;
|
|
114
|
+
/** Default `true`; child #2 (account health) sets `false` for an unhealthy
|
|
115
|
+
* account and the selector skips it. */
|
|
116
|
+
schedulable?: boolean;
|
|
117
|
+
}
|
|
118
|
+
interface SelectInput {
|
|
119
|
+
providerId: SubscriptionProviderId;
|
|
120
|
+
accounts: readonly SchedulableAccount[];
|
|
121
|
+
/** The persistent active-account pointer (for the `isActive` discriminant). */
|
|
122
|
+
activeAccountId?: string;
|
|
123
|
+
/** Stable per-conversation key for session affinity; absent ⇒ pure priority/LRU. */
|
|
124
|
+
sessionKey?: string;
|
|
125
|
+
/** Injectable clock for tests (default `Date.now()`). */
|
|
126
|
+
now?: number;
|
|
127
|
+
}
|
|
128
|
+
interface SelectResult {
|
|
129
|
+
accountId: string;
|
|
130
|
+
/** `true` when the chosen account is the active one — the caller then runs the
|
|
131
|
+
* existing active-mirror getter verbatim (no by-id read). */
|
|
132
|
+
isActive: boolean;
|
|
133
|
+
}
|
|
134
|
+
declare class SubscriptionAccountSelector {
|
|
135
|
+
/** `providerId\0accountId → live lastUsedAt ms` (authoritative tie-break). */
|
|
136
|
+
private readonly lastUsedOverlay;
|
|
137
|
+
/** `providerId\0sessionKey → { accountId, expiresAt }`. */
|
|
138
|
+
private readonly affinity;
|
|
139
|
+
/** `providerId\0accountId → last durable-persist ms` (throttle state). */
|
|
140
|
+
private readonly lastPersist;
|
|
141
|
+
/**
|
|
142
|
+
* Choose the account to serve this request, or `null` when there are ≤ 1
|
|
143
|
+
* schedulable accounts (the zero-regression signal — caller uses the active
|
|
144
|
+
* account). Updates the live `lastUsedAt` overlay for the chosen account and,
|
|
145
|
+
* when a `sessionKey` is given, records/extends the affinity mapping.
|
|
146
|
+
*/
|
|
147
|
+
select(input: SelectInput): SelectResult | null;
|
|
148
|
+
/**
|
|
149
|
+
* Drop every session-affinity mapping bound to this account (subscription-account-
|
|
150
|
+
* health, task 4.1). Called when a selected account's by-id token turns out
|
|
151
|
+
* null/invalid or an affinity-bound account becomes unhealthy, so the next
|
|
152
|
+
* selection for those sessions picks a fresh account instead of re-sticking to
|
|
153
|
+
* the bad one. O(affinity entries) — the map is tiny (one entry per live
|
|
154
|
+
* conversation).
|
|
155
|
+
*/
|
|
156
|
+
evictAffinity(providerId: SubscriptionProviderId, accountId: string): void;
|
|
157
|
+
/**
|
|
158
|
+
* Whether a best-effort `lastUsedAt` durable persist is DUE for this account
|
|
159
|
+
* (≥ `LAST_USED_PERSIST_THROTTLE_MS` since the last one). Records the persist
|
|
160
|
+
* time when it returns `true`, so the strategy calls `touchAccountLastUsed`
|
|
161
|
+
* sparingly and the request hot path does not rewrite the store every request.
|
|
162
|
+
*/
|
|
163
|
+
duePersist(providerId: SubscriptionProviderId, accountId: string, now?: number): boolean;
|
|
164
|
+
/** Sort by `priority` asc → effective `lastUsedAt` asc → `createdAt` asc → `[0]`. */
|
|
165
|
+
private pickOrdered;
|
|
166
|
+
/** The live tie-break value: the in-memory overlay when set, else the persisted
|
|
167
|
+
* `lastUsedAt` (0 when absent). */
|
|
168
|
+
private effectiveLastUsed;
|
|
169
|
+
private markUsed;
|
|
94
170
|
}
|
|
95
171
|
|
|
96
172
|
/**
|
|
@@ -107,6 +183,9 @@ interface AuthStrategy {
|
|
|
107
183
|
|
|
108
184
|
declare class SubscriptionAccountService {
|
|
109
185
|
private readonly mutex;
|
|
186
|
+
/** ONE account-pool scheduler (subscription-account-scheduling) shared by all
|
|
187
|
+
* four strategies so they share the affinity map + the `lastUsedAt` overlay. */
|
|
188
|
+
private readonly selector;
|
|
110
189
|
private readonly strategies;
|
|
111
190
|
constructor(tokens: SubscriptionCredentialStore);
|
|
112
191
|
/** Returns the strategy bound to a subscription provider, or `null` for unknown ids. */
|
|
@@ -122,622 +201,6 @@ declare function setSubscriptionAccountService(svc: SubscriptionAccountService):
|
|
|
122
201
|
* may run before main wiring on early-boot diagnostics). */
|
|
123
202
|
declare function getSubscriptionAccountService(): SubscriptionAccountService | null;
|
|
124
203
|
|
|
125
|
-
/**
|
|
126
|
-
* TransformerService Types
|
|
127
|
-
*
|
|
128
|
-
* Type definitions for the Transformer system, providing unified
|
|
129
|
-
* request/response formats and transformer chain configuration.
|
|
130
|
-
*
|
|
131
|
-
* @module transformer/types
|
|
132
|
-
*/
|
|
133
|
-
/**
|
|
134
|
-
* Thinking effort level for reasoning models
|
|
135
|
-
*/
|
|
136
|
-
type ThinkLevel = 'none' | 'low' | 'medium' | 'high';
|
|
137
|
-
/**
|
|
138
|
-
* Thinking content with optional signature for extended context
|
|
139
|
-
*/
|
|
140
|
-
interface ThinkingContent {
|
|
141
|
-
content: string;
|
|
142
|
-
signature?: string;
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Reasoning configuration for request
|
|
146
|
-
*/
|
|
147
|
-
interface ReasoningConfig {
|
|
148
|
-
/** OpenAI-style effort level */
|
|
149
|
-
effort?: ThinkLevel;
|
|
150
|
-
/** Anthropic-style max tokens for thinking */
|
|
151
|
-
max_tokens?: number;
|
|
152
|
-
/** Whether reasoning is enabled */
|
|
153
|
-
enabled?: boolean;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Text content block
|
|
157
|
-
*/
|
|
158
|
-
interface TextContent {
|
|
159
|
-
type: 'text';
|
|
160
|
-
text: string;
|
|
161
|
-
cache_control?: {
|
|
162
|
-
type?: string;
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Image content block
|
|
167
|
-
*/
|
|
168
|
-
interface ImageContent {
|
|
169
|
-
type: 'image_url';
|
|
170
|
-
image_url: {
|
|
171
|
-
url: string;
|
|
172
|
-
};
|
|
173
|
-
media_type?: string;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Union of all content types
|
|
177
|
-
*/
|
|
178
|
-
type MessageContent = TextContent | ImageContent;
|
|
179
|
-
/**
|
|
180
|
-
* Tool call definition
|
|
181
|
-
*/
|
|
182
|
-
interface ToolCall {
|
|
183
|
-
id: string;
|
|
184
|
-
type: 'function';
|
|
185
|
-
function: {
|
|
186
|
-
name: string;
|
|
187
|
-
arguments: string;
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Unified message format that works across all providers
|
|
192
|
-
*/
|
|
193
|
-
interface UnifiedMessage {
|
|
194
|
-
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
195
|
-
content: string | null | MessageContent[];
|
|
196
|
-
tool_calls?: ToolCall[];
|
|
197
|
-
tool_call_id?: string;
|
|
198
|
-
cache_control?: {
|
|
199
|
-
type?: string;
|
|
200
|
-
};
|
|
201
|
-
thinking?: ThinkingContent;
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Tool parameter schema
|
|
205
|
-
*/
|
|
206
|
-
interface ToolParameterSchema {
|
|
207
|
-
type: 'object';
|
|
208
|
-
properties: Record<string, unknown>;
|
|
209
|
-
required?: string[];
|
|
210
|
-
additionalProperties?: boolean;
|
|
211
|
-
$schema?: string;
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Unified tool definition
|
|
215
|
-
*/
|
|
216
|
-
interface UnifiedTool {
|
|
217
|
-
type: 'function';
|
|
218
|
-
function: {
|
|
219
|
-
name: string;
|
|
220
|
-
description: string;
|
|
221
|
-
parameters: ToolParameterSchema;
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Tool choice configuration
|
|
226
|
-
*/
|
|
227
|
-
type ToolChoice = 'auto' | 'none' | 'required' | string | {
|
|
228
|
-
type: 'function';
|
|
229
|
-
function: {
|
|
230
|
-
name: string;
|
|
231
|
-
};
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Unified chat request format
|
|
235
|
-
*/
|
|
236
|
-
interface UnifiedChatRequest {
|
|
237
|
-
messages: UnifiedMessage[];
|
|
238
|
-
model: string;
|
|
239
|
-
max_tokens?: number;
|
|
240
|
-
temperature?: number;
|
|
241
|
-
stream?: boolean;
|
|
242
|
-
tools?: UnifiedTool[];
|
|
243
|
-
tool_choice?: ToolChoice;
|
|
244
|
-
reasoning?: ReasoningConfig;
|
|
245
|
-
/**
|
|
246
|
-
* Internal-only routing metadata. Populated by callers (CompletionService /
|
|
247
|
-
* the host's engine adapters and proxy servers) so the usage-capture hook can attribute
|
|
248
|
-
* the recorded event to a chat message, session, engine origin, and api key.
|
|
249
|
-
*
|
|
250
|
-
* **Must not be serialised into the outbound HTTP body.** The transformer chain
|
|
251
|
-
* passes this object alongside the request internally; transformers that build
|
|
252
|
-
* provider request payloads must drop `meta` from their output.
|
|
253
|
-
*/
|
|
254
|
-
meta?: UnifiedChatRequestMeta;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Routing metadata threaded through the transformer chain so the usage-capture
|
|
258
|
-
* hook can identify which chat message / session / api key produced the call.
|
|
259
|
-
* See `UnifiedChatRequest.meta`.
|
|
260
|
-
*/
|
|
261
|
-
interface UnifiedChatRequestMeta {
|
|
262
|
-
/** Host message id of the assistant message being produced, when known. */
|
|
263
|
-
messageId?: string | null;
|
|
264
|
-
/** Parent assistant message id (for subagent dispatches that have a parent). */
|
|
265
|
-
parentMessageId?: string | null;
|
|
266
|
-
/** Host session id, when applicable. */
|
|
267
|
-
sessionId?: string | null;
|
|
268
|
-
/** Which engine path is making the call. See `UsageEngineOrigin`. */
|
|
269
|
-
engineOrigin?: 'completion' | 'claude-sdk' | 'claude-sdk-direct' | 'codex-ingress' | (string & {});
|
|
270
|
-
/** The api-key-pool entry id selected for this request. */
|
|
271
|
-
apiKeyId?: string | null;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* LLM Provider configuration (runtime format)
|
|
275
|
-
*/
|
|
276
|
-
interface LLMProvider {
|
|
277
|
-
name: string;
|
|
278
|
-
baseUrl: string;
|
|
279
|
-
apiKey: string;
|
|
280
|
-
models: string[];
|
|
281
|
-
transformer?: TransformerChainConfig;
|
|
282
|
-
/**
|
|
283
|
-
* Resolved Google **Code Assist** project id, threaded onto the transformer
|
|
284
|
-
* provider object by the subscription dispatch seam (SubscriptionDispatcher /
|
|
285
|
-
* openaiResponsesIngress) so `GeminiCodeAssistTransformer.transformRequestIn`
|
|
286
|
-
* can embed it in the top-level envelope. `undefined` is the valid fresh
|
|
287
|
-
* free-tier value (sending a project on free/legacy-tier → Precondition
|
|
288
|
-
* Failed). Only ever set for the gemini subscription profile; inert otherwise.
|
|
289
|
-
*/
|
|
290
|
-
geminiProject?: string;
|
|
291
|
-
}
|
|
292
|
-
/**
|
|
293
|
-
* Transformer options passed during instantiation
|
|
294
|
-
*/
|
|
295
|
-
interface TransformerOptions {
|
|
296
|
-
[key: string]: unknown;
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Context passed through transformer chain
|
|
300
|
-
*/
|
|
301
|
-
interface TransformerContext {
|
|
302
|
-
/** Original request object */
|
|
303
|
-
req?: unknown;
|
|
304
|
-
/** Logger instance */
|
|
305
|
-
logger?: TransformerLogger;
|
|
306
|
-
/** Provider name */
|
|
307
|
-
providerName?: string;
|
|
308
|
-
/** Additional context data */
|
|
309
|
-
[key: string]: unknown;
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Logger interface for transformers
|
|
313
|
-
*/
|
|
314
|
-
interface TransformerLogger {
|
|
315
|
-
debug(message: string, ...args: unknown[]): void;
|
|
316
|
-
info(message: string, ...args: unknown[]): void;
|
|
317
|
-
warn(message: string, ...args: unknown[]): void;
|
|
318
|
-
error(message: string, ...args: unknown[]): void;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* Transformer interface - defines the contract for all transformers
|
|
322
|
-
*/
|
|
323
|
-
interface Transformer {
|
|
324
|
-
/** Unique name for the transformer */
|
|
325
|
-
name?: string;
|
|
326
|
-
/** API endpoint path (e.g., '/v1/chat/completions') */
|
|
327
|
-
endPoint?: string;
|
|
328
|
-
/** Logger instance */
|
|
329
|
-
logger?: TransformerLogger;
|
|
330
|
-
/**
|
|
331
|
-
* Transform incoming request (provider-specific → unified format)
|
|
332
|
-
* Called when request enters the transformer chain
|
|
333
|
-
*/
|
|
334
|
-
transformRequestIn?: (request: UnifiedChatRequest, provider: LLMProvider, context: TransformerContext) => Promise<Record<string, unknown>>;
|
|
335
|
-
/**
|
|
336
|
-
* Transform outgoing request (unified → provider-specific format)
|
|
337
|
-
* Called before sending to LLM provider
|
|
338
|
-
*/
|
|
339
|
-
transformRequestOut?: (request: unknown, context: TransformerContext) => Promise<UnifiedChatRequest>;
|
|
340
|
-
/**
|
|
341
|
-
* Transform incoming response (provider-specific → unified format)
|
|
342
|
-
* Called after receiving response from provider
|
|
343
|
-
*/
|
|
344
|
-
transformResponseIn?: (response: Response, context?: TransformerContext) => Promise<Response>;
|
|
345
|
-
/**
|
|
346
|
-
* Transform outgoing response (unified → client format)
|
|
347
|
-
* Called before returning response to client
|
|
348
|
-
*/
|
|
349
|
-
transformResponseOut?: (response: Response, context: TransformerContext) => Promise<Response>;
|
|
350
|
-
/**
|
|
351
|
-
* Handle authentication for the request
|
|
352
|
-
*/
|
|
353
|
-
auth?: (request: unknown, provider: LLMProvider, context: TransformerContext) => Promise<unknown>;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Transformer constructor interface
|
|
357
|
-
*/
|
|
358
|
-
interface TransformerConstructor {
|
|
359
|
-
new (options?: TransformerOptions): Transformer;
|
|
360
|
-
TransformerName?: string;
|
|
361
|
-
}
|
|
362
|
-
/**
|
|
363
|
-
* Individual transformer reference in chain
|
|
364
|
-
* Can be a string name or [name, options] tuple
|
|
365
|
-
*/
|
|
366
|
-
type TransformerReference = string | [string, TransformerOptions];
|
|
367
|
-
/**
|
|
368
|
-
* Model-specific transformer configuration
|
|
369
|
-
*/
|
|
370
|
-
interface ModelTransformerConfig {
|
|
371
|
-
use?: TransformerReference[];
|
|
372
|
-
}
|
|
373
|
-
/**
|
|
374
|
-
* Transformer chain configuration for a provider
|
|
375
|
-
*/
|
|
376
|
-
interface TransformerChainConfig {
|
|
377
|
-
/** Provider-level transformers applied to all models */
|
|
378
|
-
use?: TransformerReference[];
|
|
379
|
-
/** Model-specific transformer overrides */
|
|
380
|
-
[modelName: string]: ModelTransformerConfig | TransformerReference[] | undefined;
|
|
381
|
-
}
|
|
382
|
-
/**
|
|
383
|
-
* Resolved transformer chain (instances ready to execute)
|
|
384
|
-
*/
|
|
385
|
-
interface ResolvedTransformerChain {
|
|
386
|
-
/** Provider-level transformer instances */
|
|
387
|
-
providerTransformers: Transformer[];
|
|
388
|
-
/** Model-specific transformer instances */
|
|
389
|
-
modelTransformers: Transformer[];
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Result of request transformation
|
|
393
|
-
*/
|
|
394
|
-
interface TransformRequestResult {
|
|
395
|
-
/** Transformed request body */
|
|
396
|
-
requestBody: unknown;
|
|
397
|
-
/** Additional request configuration */
|
|
398
|
-
config: RequestConfig;
|
|
399
|
-
/** Whether to bypass further transformations */
|
|
400
|
-
bypass: boolean;
|
|
401
|
-
}
|
|
402
|
-
/**
|
|
403
|
-
* Request configuration for HTTP call
|
|
404
|
-
*/
|
|
405
|
-
interface RequestConfig {
|
|
406
|
-
/** Request URL */
|
|
407
|
-
url?: URL | string;
|
|
408
|
-
/** Request headers */
|
|
409
|
-
headers?: Record<string, string>;
|
|
410
|
-
/** Additional fetch options */
|
|
411
|
-
[key: string]: unknown;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* TransformerChainExecutor - Executes transformer chains for requests and responses
|
|
416
|
-
*
|
|
417
|
-
* Implements the transformer pipeline:
|
|
418
|
-
* Request: transformRequestOut 鈫?Provider transformers 鈫?Model transformers 鈫?HTTP
|
|
419
|
-
* Response: Model transformers (reverse) 鈫?Provider transformers (reverse) 鈫?transformResponseIn
|
|
420
|
-
*
|
|
421
|
-
* @module transformer/TransformerChainExecutor
|
|
422
|
-
*/
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Options for chain execution
|
|
426
|
-
*/
|
|
427
|
-
interface ChainExecutionOptions {
|
|
428
|
-
/** The primary/endpoint transformer */
|
|
429
|
-
endpointTransformer?: Transformer;
|
|
430
|
-
/** Request headers */
|
|
431
|
-
headers?: Record<string, string> | Headers;
|
|
432
|
-
/** Logger instance */
|
|
433
|
-
logger?: TransformerLogger;
|
|
434
|
-
/**
|
|
435
|
-
* 1M-context opt-in. When `enabled` is true and the post-chain request body
|
|
436
|
-
* looks Anthropic-shaped (has a `messages` array), the executor injects
|
|
437
|
-
* `'context-1m-2025-08-07'` into `body.anthropic_beta`. Capability gating
|
|
438
|
-
* (model id allowlist) lives inside `injectExtendedContextBeta` itself.
|
|
439
|
-
*/
|
|
440
|
-
extendedContext?: {
|
|
441
|
-
enabled: boolean;
|
|
442
|
-
model: string;
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
/**
|
|
446
|
-
* TransformerChainExecutor handles the execution of transformer chains.
|
|
447
|
-
*
|
|
448
|
-
* The execution flow follows the llms project pattern:
|
|
449
|
-
*
|
|
450
|
-
* Request Phase:
|
|
451
|
-
* 1. transformRequestOut (endpoint transformer) - Convert to unified format
|
|
452
|
-
* 2. Provider transformers [].transformRequestIn (forward order)
|
|
453
|
-
* 3. Model transformers [].transformRequestIn (forward order)
|
|
454
|
-
*
|
|
455
|
-
* Response Phase:
|
|
456
|
-
* 4. Model transformers [].transformResponseOut (reverse order)
|
|
457
|
-
* 5. Provider transformers [].transformResponseOut (reverse order)
|
|
458
|
-
* 6. transformResponseIn (endpoint transformer) - Convert to client format
|
|
459
|
-
*/
|
|
460
|
-
declare class TransformerChainExecutor {
|
|
461
|
-
private logger;
|
|
462
|
-
constructor(logger?: TransformerLogger);
|
|
463
|
-
/**
|
|
464
|
-
* Execute the request transformation chain
|
|
465
|
-
*
|
|
466
|
-
* @param request - Original request body
|
|
467
|
-
* @param provider - LLM provider configuration
|
|
468
|
-
* @param chain - Resolved transformer chain
|
|
469
|
-
* @param options - Execution options
|
|
470
|
-
* @returns Transformed request result
|
|
471
|
-
*/
|
|
472
|
-
executeRequestChain(request: unknown, provider: LLMProvider, chain: ResolvedTransformerChain, options?: ChainExecutionOptions): Promise<TransformRequestResult>;
|
|
473
|
-
/**
|
|
474
|
-
* Execute the response transformation chain
|
|
475
|
-
*
|
|
476
|
-
* @param request - Original request (for context)
|
|
477
|
-
* @param response - Response from provider
|
|
478
|
-
* @param provider - LLM provider configuration
|
|
479
|
-
* @param chain - Resolved transformer chain
|
|
480
|
-
* @param options - Execution options
|
|
481
|
-
* @returns Transformed response
|
|
482
|
-
*/
|
|
483
|
-
executeResponseChain(request: UnifiedChatRequest, response: Response, provider: LLMProvider, chain: ResolvedTransformerChain, options?: ChainExecutionOptions): Promise<Response>;
|
|
484
|
-
/**
|
|
485
|
-
* Execute authentication handler if available
|
|
486
|
-
*
|
|
487
|
-
* @param request - Request body
|
|
488
|
-
* @param provider - LLM provider
|
|
489
|
-
* @param endpointTransformer - Endpoint transformer with auth handler
|
|
490
|
-
* @param context - Transformer context
|
|
491
|
-
* @returns Auth result with potentially modified request and config
|
|
492
|
-
*/
|
|
493
|
-
executeAuth(request: unknown, provider: LLMProvider, endpointTransformer: Transformer | undefined, context: TransformerContext): Promise<{
|
|
494
|
-
requestBody: unknown;
|
|
495
|
-
config: RequestConfig;
|
|
496
|
-
}>;
|
|
497
|
-
/**
|
|
498
|
-
* Check if transformers should be bypassed (optimization)
|
|
499
|
-
*
|
|
500
|
-
* Bypass is enabled when:
|
|
501
|
-
* - Provider has only one transformer that matches the endpoint transformer
|
|
502
|
-
* - Model has no specific transformers or only the same endpoint transformer
|
|
503
|
-
*/
|
|
504
|
-
private shouldBypassTransformers;
|
|
505
|
-
/**
|
|
506
|
-
* Clean headers for pass-through
|
|
507
|
-
*/
|
|
508
|
-
private cleanHeaders;
|
|
509
|
-
/**
|
|
510
|
-
* Get error message from unknown error
|
|
511
|
-
*/
|
|
512
|
-
private getErrorMessage;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* TransformerService - Core service for managing transformer lifecycle
|
|
517
|
-
*
|
|
518
|
-
* Handles transformer registration, retrieval, and initialization.
|
|
519
|
-
*
|
|
520
|
-
* Adapted from the `musistudio/llms` project (MIT, © 2025 musistudio) — the
|
|
521
|
-
* transformer IR upstream — for the Electron environment. See the package
|
|
522
|
-
* `NOTICE` for full third-party attribution.
|
|
523
|
-
*
|
|
524
|
-
* @module transformer/TransformerService
|
|
525
|
-
*/
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* TransformerService manages the lifecycle of all transformers.
|
|
529
|
-
*
|
|
530
|
-
* Features:
|
|
531
|
-
* - Register transformers by name
|
|
532
|
-
* - Get transformer by name
|
|
533
|
-
* - Initialize default transformers
|
|
534
|
-
* - Resolve transformer chains from configuration
|
|
535
|
-
*/
|
|
536
|
-
declare class TransformerService {
|
|
537
|
-
private transformers;
|
|
538
|
-
private logger;
|
|
539
|
-
private instanceCache;
|
|
540
|
-
private endpointTransformersCache;
|
|
541
|
-
private noEndpointTransformersCache;
|
|
542
|
-
constructor(logger?: TransformerLogger);
|
|
543
|
-
/**
|
|
544
|
-
* Clear instance caches
|
|
545
|
-
*/
|
|
546
|
-
clearInstanceCache(): void;
|
|
547
|
-
/**
|
|
548
|
-
* Get cache statistics for diagnostics
|
|
549
|
-
*/
|
|
550
|
-
getCacheStats(): {
|
|
551
|
-
instanceCacheSize: number;
|
|
552
|
-
hasEndpointCache: boolean;
|
|
553
|
-
};
|
|
554
|
-
/**
|
|
555
|
-
* Register a transformer by name
|
|
556
|
-
* @param name - Unique transformer name
|
|
557
|
-
* @param transformer - Transformer instance or constructor
|
|
558
|
-
*/
|
|
559
|
-
registerTransformer(name: string, transformer: Transformer | TransformerConstructor): void;
|
|
560
|
-
/**
|
|
561
|
-
* Get a transformer by name
|
|
562
|
-
* @param name - Transformer name
|
|
563
|
-
* @returns Transformer instance/constructor or undefined
|
|
564
|
-
*/
|
|
565
|
-
getTransformer(name: string): Transformer | TransformerConstructor | undefined;
|
|
566
|
-
/**
|
|
567
|
-
* Get all registered transformers
|
|
568
|
-
* @returns Map of all transformers
|
|
569
|
-
*/
|
|
570
|
-
getAllTransformers(): Map<string, Transformer | TransformerConstructor>;
|
|
571
|
-
/**
|
|
572
|
-
* Get transformers that have an endpoint defined
|
|
573
|
-
* Uses cache to avoid redundant traversal
|
|
574
|
-
* @returns Array of transformers with endpoints
|
|
575
|
-
*/
|
|
576
|
-
getTransformersWithEndpoint(): {
|
|
577
|
-
name: string;
|
|
578
|
-
transformer: Transformer;
|
|
579
|
-
}[];
|
|
580
|
-
/**
|
|
581
|
-
* Get transformers without endpoints
|
|
582
|
-
* Uses cache to avoid redundant traversal
|
|
583
|
-
* @returns Array of transformers without endpoints
|
|
584
|
-
*/
|
|
585
|
-
getTransformersWithoutEndpoint(): {
|
|
586
|
-
name: string;
|
|
587
|
-
transformer: Transformer;
|
|
588
|
-
}[];
|
|
589
|
-
/**
|
|
590
|
-
* Remove a transformer by name
|
|
591
|
-
* @param name - Transformer name
|
|
592
|
-
* @returns true if removed, false if not found
|
|
593
|
-
*/
|
|
594
|
-
removeTransformer(name: string): boolean;
|
|
595
|
-
/**
|
|
596
|
-
* Check if a transformer is registered
|
|
597
|
-
* @param name - Transformer name
|
|
598
|
-
* @returns true if registered
|
|
599
|
-
*/
|
|
600
|
-
hasTransformer(name: string): boolean;
|
|
601
|
-
/**
|
|
602
|
-
* Initialize the service with default transformers
|
|
603
|
-
* @param defaultTransformers - Map or object of default transformers
|
|
604
|
-
*/
|
|
605
|
-
initialize(defaultTransformers?: Record<string, Transformer | TransformerConstructor>): Promise<void>;
|
|
606
|
-
/**
|
|
607
|
-
* Register default transformers from a map
|
|
608
|
-
* @param transformers - Map of transformer name to transformer
|
|
609
|
-
*/
|
|
610
|
-
private registerDefaultTransformers;
|
|
611
|
-
/**
|
|
612
|
-
* Resolve a transformer chain configuration to actual transformer instances
|
|
613
|
-
* @param chainConfig - Transformer chain configuration
|
|
614
|
-
* @param modelName - Model name for model-specific transformers
|
|
615
|
-
* @returns Resolved transformer chain with instances
|
|
616
|
-
*/
|
|
617
|
-
resolveTransformerChain(chainConfig: TransformerChainConfig | undefined, modelName?: string): ResolvedTransformerChain;
|
|
618
|
-
/**
|
|
619
|
-
* Resolve an array of transformer references to instances
|
|
620
|
-
* @param refs - Array of transformer references
|
|
621
|
-
* @returns Array of transformer instances
|
|
622
|
-
*/
|
|
623
|
-
resolveTransformerReferences(refs: TransformerReference[]): Transformer[];
|
|
624
|
-
/**
|
|
625
|
-
* Instantiate a transformer if it's a constructor
|
|
626
|
-
* Uses instance cache to avoid redundant instantiation
|
|
627
|
-
*
|
|
628
|
-
* @param transformer - Transformer instance or constructor
|
|
629
|
-
* @param options - Options to pass to constructor
|
|
630
|
-
* @returns Transformer instance
|
|
631
|
-
*/
|
|
632
|
-
private instantiateIfNeeded;
|
|
633
|
-
/**
|
|
634
|
-
* Check if a value is a transformer constructor
|
|
635
|
-
* @param value - Value to check
|
|
636
|
-
* @returns true if it's a constructor
|
|
637
|
-
*/
|
|
638
|
-
private isTransformerConstructor;
|
|
639
|
-
/**
|
|
640
|
-
* Get list of all registered transformer names
|
|
641
|
-
* @returns Array of transformer names
|
|
642
|
-
*/
|
|
643
|
-
getTransformerNames(): string[];
|
|
644
|
-
/**
|
|
645
|
-
* Clear all registered transformers
|
|
646
|
-
*/
|
|
647
|
-
clear(): void;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* Shared contract types for the resident `ProviderProxy`.
|
|
652
|
-
*
|
|
653
|
-
* The `ProviderProxy` (OpenSpec `engine-provider-decouple`, design D0/D3/D7/D9)
|
|
654
|
-
* is the single resident `127.0.0.1` listener that subsumes both of the
|
|
655
|
-
* host's per-session proxies (Anthropic Messages ingress and OpenAI Responses
|
|
656
|
-
* ingress). Per-run state lives in a `Map<token, RouteContext>`
|
|
657
|
-
* minted at run start and reaped at run end / on idle TTL.
|
|
658
|
-
*
|
|
659
|
-
* These types are kept in their own module so the server, route map, router,
|
|
660
|
-
* and the two ingress parsers can share shapes without importing one another
|
|
661
|
-
* for type-only purposes.
|
|
662
|
-
*
|
|
663
|
-
* @module provider-proxy/types
|
|
664
|
-
*/
|
|
665
|
-
|
|
666
|
-
/** Lightweight summary derived from the inbound Anthropic request body —
|
|
667
|
-
* consumed by `modelMapper` (scenario routing) without full body access. */
|
|
668
|
-
interface SubscriptionRequestSummary {
|
|
669
|
-
messageCount: number;
|
|
670
|
-
/** cl100k_base-estimated token count of system + messages (no tools). */
|
|
671
|
-
estimatedInputTokens: number;
|
|
672
|
-
/**
|
|
673
|
-
* OPTIONAL bounded per-message text slice (system prompt + the most recent
|
|
674
|
-
* user/system messages, each per-message-capped) consumed ONLY by the
|
|
675
|
-
* OpenCodeGo keyword matcher in `@omnicross/subscriptions`
|
|
676
|
-
* (`resolveOpenCodeGoScenario`). Core only WRITES this `string[]`; it never
|
|
677
|
-
* reads it and never names the matcher — keeping the cross-layer litmus at 0
|
|
678
|
-
* (no `@omnicross/core` → `@omnicross/subscriptions` edge). Optional so callers
|
|
679
|
-
* that omit it (legacy/tests) compile and degrade to the token-threshold +
|
|
680
|
-
* `default` routing.
|
|
681
|
-
*/
|
|
682
|
-
matchText?: string[];
|
|
683
|
-
}
|
|
684
|
-
interface SubscriptionDispatchProfile {
|
|
685
|
-
readonly providerId: SubscriptionProviderId;
|
|
686
|
-
readonly displayName: string;
|
|
687
|
-
readonly authStrategy: AuthStrategy;
|
|
688
|
-
/** Pass-through providers (Claude) skip the transformer chain entirely.
|
|
689
|
-
* Transformer providers use the chain below + the proxy's existing
|
|
690
|
-
* `AnthropicTransformer` endpoint reverse-decoder. */
|
|
691
|
-
readonly mode: 'pass-through' | 'transformer';
|
|
692
|
-
/** Resolve the upstream URL for a given resolved model id. Required for
|
|
693
|
-
* `mode === 'transformer'`; unused for pass-through (proxy hard-codes
|
|
694
|
-
* `api.anthropic.com`). The OPTIONAL 2nd `config` arg lets the opencodego
|
|
695
|
-
* profile honor a per-account `baseUrl` override (D1) — additive, so existing
|
|
696
|
-
* one-arg callers compile unchanged. */
|
|
697
|
-
readonly resolveUpstreamUrl?: (resolvedModel: string, config?: OpenCodeGoTokenConfig) => string;
|
|
698
|
-
/** Names of transformers (registered in `TransformerService`) to run on the
|
|
699
|
-
* provider chain. The proxy adds `AnthropicTransformer` as the endpoint
|
|
700
|
-
* reverse-decoder. */
|
|
701
|
-
readonly providerTransformerNames?: readonly string[];
|
|
702
|
-
readonly modelTransformerNames?: readonly string[];
|
|
703
|
-
/**
|
|
704
|
-
* OPTIONAL shape-aware provider transformer-name resolver (opencodego zen).
|
|
705
|
-
* Parallel to `resolveUpstreamUrl(model, config)`: lets a profile vary its
|
|
706
|
-
* provider chain by the RESOLVED model's wire shape (e.g. zen `responses` ⇒
|
|
707
|
-
* `['openai-response']`, `gemini` ⇒ `['gemini']`). `config` is `unknown` on the
|
|
708
|
-
* core side (opaque-config discipline — core never names
|
|
709
|
-
* `OpenCodeGoTokenConfig` from `@omnicross/subscriptions`); the subscriptions
|
|
710
|
-
* implementation narrows it. When ABSENT, both ingress paths fall back to the
|
|
711
|
-
* static `providerTransformerNames` — BYTE-IDENTICAL for claude / codex / gemini
|
|
712
|
-
* (which leave this unset). Purely additive (optional).
|
|
713
|
-
*/
|
|
714
|
-
readonly resolveProviderTransformerNames?: (model: string, config?: unknown) => readonly string[];
|
|
715
|
-
/** Optional model placeholder rewriter — only set for OpenCodeGo. */
|
|
716
|
-
readonly modelMapper?: (sdkModel: string, summary: SubscriptionRequestSummary, config: OpenCodeGoTokenConfig | undefined) => {
|
|
717
|
-
resolvedModel: string;
|
|
718
|
-
scenario: OpenCodeGoScenario;
|
|
719
|
-
};
|
|
720
|
-
/** Optional fallback resolver — for OpenCodeGo, picks the next model after
|
|
721
|
-
* an unrecoverable error. Returns `null` when exhausted. Cap = 3. The
|
|
722
|
-
* opencodego implementation ALSO consults the circuit breaker (D5): it skips
|
|
723
|
-
* models whose circuit is open. */
|
|
724
|
-
readonly nextFallback?: (scenario: OpenCodeGoScenario, attempted: readonly string[], config: OpenCodeGoTokenConfig | undefined) => OpenCodeGoModelEntry | null;
|
|
725
|
-
/** Optional circuit-breaker admission gate for the PRIMARY (mapped) model
|
|
726
|
-
* (D5 primary-gating). Only set for OpenCodeGo. Returns whether `modelId`'s
|
|
727
|
-
* circuit currently admits a request (side-effecting: flips an `open` model
|
|
728
|
-
* to `half-open` once its window elapses, exactly like `nextFallback`'s
|
|
729
|
-
* internal consult). `nextFallback` covers the FALLBACKS; this covers the
|
|
730
|
-
* primary the loop already holds. Absent/undefined ⇒ the loop treats the
|
|
731
|
-
* primary as always admitted (claude / codex / gemini have no breaker). */
|
|
732
|
-
readonly allowModel?: (modelId: string) => boolean;
|
|
733
|
-
/** Optional record-outcome callback (D5 record seam). Only set for OpenCodeGo.
|
|
734
|
-
* Both fallback loops invoke it after each attempt: `ok: true` on a `2xx`,
|
|
735
|
-
* `ok: false` on a thrown/network error / `5xx` / `429`; a non-429 `4xx` is
|
|
736
|
-
* NEUTRAL and the loops MUST NOT call it. Drives the per-model breaker.
|
|
737
|
-
* Absent/undefined for claude / codex / gemini ⇒ a no-op (no breaker). */
|
|
738
|
-
readonly recordModelOutcome?: (modelId: string, ok: boolean) => void;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
204
|
/**
|
|
742
205
|
* SubscriptionProviderRegistry — fixed catalog of subscription dispatch profiles.
|
|
743
206
|
*
|
|
@@ -802,7 +265,17 @@ interface DispatcherHooks {
|
|
|
802
265
|
readonly executor: TransformerChainExecutor;
|
|
803
266
|
/** Shared transformer service registry — looks up transformer-by-name. */
|
|
804
267
|
readonly transformerService: TransformerService;
|
|
805
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Fetch + retry helper from the proxy (semaphore, 429/5xx loop). On a non-ok
|
|
270
|
+
* upstream it throws a `ProviderApiError`-shaped error carrying `.status`.
|
|
271
|
+
*
|
|
272
|
+
* ACCOUNT-HEALTH CONTRACT (subscription-account-health): for the daemon-path
|
|
273
|
+
* 429-reset cooldown + 403-ban sniff to function, the thrown error SHOULD also
|
|
274
|
+
* carry the upstream response `headers` (a `Headers` or a plain record) and, on
|
|
275
|
+
* a 403, a bounded `bodyText`/`body` string. The dispatcher reads them
|
|
276
|
+
* STRUCTURALLY (`errHeaders`/`errBodyText`) — absent ⇒ the account-health mark
|
|
277
|
+
* gracefully degrades to a bare-429 (unmarked, lazy re-probe), never an error.
|
|
278
|
+
*/
|
|
806
279
|
fetchWithRetry(url: string, headers: Record<string, string>, body: unknown, model: string): Promise<Response>;
|
|
807
280
|
/** Forward the upstream response to the SDK + tap usage. */
|
|
808
281
|
writeProxyResponse(res: http.ServerResponse, providerResponse: Response, isStream: boolean, reqId?: number): Promise<void>;
|
|
@@ -851,6 +324,17 @@ declare class SubscriptionDispatcher {
|
|
|
851
324
|
*/
|
|
852
325
|
private maybeRetryAfterError;
|
|
853
326
|
private applyHeadersWithRetry;
|
|
327
|
+
/**
|
|
328
|
+
* Mark the served account's health against ONE attempt's outcome
|
|
329
|
+
* (subscription-account-health, task 3.4). No-op when no account was reported
|
|
330
|
+
* (non-pooled / single-account) or on a session-cancel (status 0). On a caught
|
|
331
|
+
* error `err` is passed so the 429-reset / 403-ban drivers are read STRUCTURALLY
|
|
332
|
+
* from the error's upstream `headers` + `bodyText` (the `fetchWithRetry`
|
|
333
|
+
* contract) — so daemon-path 429 cooldown + ban blocking function for
|
|
334
|
+
* multi-account codex/gemini/opencodego pools; absent headers ⇒ a bare-429
|
|
335
|
+
* (unmarked, lazy re-probe). Success (2xx) clears; 401/5xx/thrown → transient.
|
|
336
|
+
*/
|
|
337
|
+
private markHealth;
|
|
854
338
|
/**
|
|
855
339
|
* Resolve the Code Assist project for the gemini subscription profile. Pulls
|
|
856
340
|
* the Bearer the bound `AuthStrategy` would inject (so the strategy stays the
|
|
@@ -865,4 +349,4 @@ declare class SubscriptionDispatcher {
|
|
|
865
349
|
private buildRequestSummary;
|
|
866
350
|
}
|
|
867
351
|
|
|
868
|
-
export { type
|
|
352
|
+
export { DEFAULT_ACCOUNT_PRIORITY, type DispatchRequest, type DispatcherHooks, LAST_USED_PERSIST_THROTTLE_MS, SESSION_AFFINITY_TTL_MS, type SchedulableAccount, type SelectInput, type SelectResult, SubscriptionAccountSelector, SubscriptionAccountService, type SubscriptionCredentialStore, SubscriptionDispatcher, SubscriptionProviderRegistry, getSubscriptionAccountService, getSubscriptionProviderRegistry, setSubscriptionAccountService, setSubscriptionProviderRegistry };
|