@omnicross/core 0.1.0 → 0.1.1
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/ApiConverter.cjs +799 -0
- package/dist/ApiConverter.d.cts +82 -0
- package/dist/ApiConverter.d.ts +82 -0
- package/dist/ApiConverter.js +763 -0
- package/dist/BuiltinToolExecutor-BluWyeob.d.ts +81 -0
- package/dist/BuiltinToolExecutor-CS2WpXhM.d.cts +81 -0
- package/dist/CompletionService-7fCmKAP3.d.ts +212 -0
- package/dist/CompletionService-DtOF_War.d.cts +212 -0
- package/dist/{ProviderProxy-f_8ziIhW.d.cts → ProviderProxy-C-xqrkKi.d.ts} +7 -2
- package/dist/{ProviderProxy-vjt8sQQk.d.ts → ProviderProxy-CnMQYN59.d.cts} +7 -2
- package/dist/completion/BuiltinToolExecutor.cjs +327 -0
- package/dist/completion/BuiltinToolExecutor.d.cts +4 -0
- package/dist/completion/BuiltinToolExecutor.d.ts +4 -0
- package/dist/completion/BuiltinToolExecutor.js +296 -0
- package/dist/completion/CompletionService.cjs +3487 -0
- package/dist/completion/CompletionService.d.cts +21 -0
- package/dist/completion/CompletionService.d.ts +21 -0
- package/dist/completion/CompletionService.js +3461 -0
- package/dist/completion/NativeSearchInjector.cjs +196 -0
- package/dist/completion/NativeSearchInjector.d.cts +42 -0
- package/dist/completion/NativeSearchInjector.d.ts +42 -0
- package/dist/completion/NativeSearchInjector.js +167 -0
- package/dist/completion/ProviderSearchInjector.cjs +87 -0
- package/dist/completion/ProviderSearchInjector.d.cts +47 -0
- package/dist/completion/ProviderSearchInjector.d.ts +47 -0
- package/dist/completion/ProviderSearchInjector.js +60 -0
- package/dist/completion/native-search-types.cjs +67 -0
- package/dist/completion/native-search-types.d.cts +3 -0
- package/dist/completion/native-search-types.d.ts +3 -0
- package/dist/completion/native-search-types.js +38 -0
- package/dist/completion/openrouter-headers.cjs +72 -0
- package/dist/completion/openrouter-headers.d.cts +44 -0
- package/dist/completion/openrouter-headers.d.ts +44 -0
- package/dist/completion/openrouter-headers.js +42 -0
- package/dist/completion/openrouter-models.cjs +86 -0
- package/dist/completion/openrouter-models.d.cts +27 -0
- package/dist/completion/openrouter-models.d.ts +27 -0
- package/dist/completion/openrouter-models.js +59 -0
- package/dist/completion/types.cjs +18 -0
- package/dist/completion/types.d.cts +3 -0
- package/dist/completion/types.d.ts +3 -0
- package/dist/completion/types.js +0 -0
- package/dist/completion/url-builder.cjs +138 -0
- package/dist/completion/url-builder.d.cts +87 -0
- package/dist/completion/url-builder.d.ts +87 -0
- package/dist/completion/url-builder.js +104 -0
- package/dist/completion.d.cts +148 -7
- package/dist/completion.d.ts +148 -7
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +27 -90
- package/dist/index.d.ts +27 -90
- package/dist/index.js +1 -0
- package/dist/outbound-api/routeResolver.cjs +221 -0
- package/dist/outbound-api/routeResolver.d.cts +18 -0
- package/dist/outbound-api/routeResolver.d.ts +18 -0
- package/dist/outbound-api/routeResolver.js +192 -0
- package/dist/outbound-api/subscriptionRegistryPort.d.cts +5 -2
- package/dist/outbound-api/subscriptionRegistryPort.d.ts +5 -2
- package/dist/outbound-api/types.cjs +18 -0
- package/dist/{types-CbCN2NQP.d.ts → outbound-api/types.d.cts} +17 -3
- package/dist/{types-CGGrKqC_.d.cts → outbound-api/types.d.ts} +17 -3
- package/dist/outbound-api/types.js +0 -0
- package/dist/outbound-api.cjs +1 -0
- package/dist/outbound-api.d.cts +14 -87
- package/dist/outbound-api.d.ts +14 -87
- package/dist/outbound-api.js +1 -0
- package/dist/pipeline/AuthSource.cjs +18 -0
- package/dist/pipeline/AuthSource.d.cts +101 -0
- package/dist/pipeline/AuthSource.d.ts +101 -0
- package/dist/pipeline/AuthSource.js +0 -0
- package/dist/pipeline/LlmConfigProviderAuth.cjs +169 -0
- package/dist/pipeline/LlmConfigProviderAuth.d.cts +86 -0
- package/dist/pipeline/LlmConfigProviderAuth.d.ts +86 -0
- package/dist/pipeline/LlmConfigProviderAuth.js +142 -0
- package/dist/pipeline/SubscriptionAuthSource.d.cts +165 -3
- package/dist/pipeline/SubscriptionAuthSource.d.ts +165 -3
- package/dist/pipeline/executeProviderCall.cjs +70 -0
- package/dist/pipeline/executeProviderCall.d.cts +149 -0
- package/dist/pipeline/executeProviderCall.d.ts +149 -0
- package/dist/pipeline/executeProviderCall.js +45 -0
- package/dist/pipeline/resolveProviderChain.cjs +47 -0
- package/dist/pipeline/resolveProviderChain.d.cts +58 -0
- package/dist/pipeline/resolveProviderChain.d.ts +58 -0
- package/dist/pipeline/resolveProviderChain.js +22 -0
- package/dist/pipeline/resolveSubscriptionChain.cjs +68 -0
- package/dist/pipeline/resolveSubscriptionChain.d.cts +68 -0
- package/dist/pipeline/resolveSubscriptionChain.d.ts +68 -0
- package/dist/pipeline/resolveSubscriptionChain.js +43 -0
- package/dist/ports/provider-config-source.cjs +18 -0
- package/dist/ports/provider-config-source.d.cts +51 -0
- package/dist/ports/provider-config-source.d.ts +51 -0
- package/dist/ports/provider-config-source.js +0 -0
- package/dist/ports/web-search-backend.cjs +18 -0
- package/dist/ports/web-search-backend.d.cts +29 -0
- package/dist/ports/web-search-backend.d.ts +29 -0
- package/dist/ports/web-search-backend.js +0 -0
- package/dist/ports.d.cts +10 -7
- package/dist/ports.d.ts +10 -7
- package/dist/provider-proxy/ProviderProxy.cjs +4643 -0
- package/dist/provider-proxy/ProviderProxy.d.cts +16 -0
- package/dist/provider-proxy/ProviderProxy.d.ts +16 -0
- package/dist/provider-proxy/ProviderProxy.js +4618 -0
- package/dist/provider-proxy/ingress/providerProxyShared.d.cts +5 -2
- package/dist/provider-proxy/ingress/providerProxyShared.d.ts +5 -2
- package/dist/provider-proxy/types.d.cts +406 -8
- package/dist/provider-proxy/types.d.ts +406 -8
- package/dist/provider-proxy.cjs +1 -0
- package/dist/provider-proxy.d.cts +8 -5
- package/dist/provider-proxy.d.ts +8 -5
- package/dist/provider-proxy.js +1 -0
- package/dist/routeResolver-BrbK6ja9.d.cts +88 -0
- package/dist/routeResolver-HE-ZO0fO.d.ts +88 -0
- package/dist/transformer/anthropicBetaInject.cjs +51 -0
- package/dist/transformer/anthropicBetaInject.d.cts +20 -0
- package/dist/transformer/anthropicBetaInject.d.ts +20 -0
- package/dist/transformer/anthropicBetaInject.js +25 -0
- package/dist/transformer/transformers/AnthropicTransformer.cjs +1017 -0
- package/dist/transformer/transformers/AnthropicTransformer.d.cts +148 -0
- package/dist/transformer/transformers/AnthropicTransformer.d.ts +148 -0
- package/dist/transformer/transformers/AnthropicTransformer.js +990 -0
- package/dist/transformer/transformers/ReasoningTransformer.cjs +273 -0
- package/dist/transformer/transformers/ReasoningTransformer.d.cts +47 -0
- package/dist/transformer/transformers/ReasoningTransformer.d.ts +47 -0
- package/dist/transformer/transformers/ReasoningTransformer.js +253 -0
- package/dist/transformer/transformers.cjs +3206 -0
- package/dist/transformer/transformers.d.cts +100 -0
- package/dist/transformer/transformers.d.ts +100 -0
- package/dist/transformer/transformers.js +3174 -0
- package/dist/transformer.d.cts +8 -31
- package/dist/transformer.d.ts +8 -31
- package/dist/types-BScIHmPr.d.cts +153 -0
- package/dist/types-BScIHmPr.d.ts +153 -0
- package/package.json +3 -3
- package/dist/SubscriptionAuthSource-Cr4fVEYY.d.cts +0 -264
- package/dist/SubscriptionAuthSource-D89zmiSS.d.ts +0 -264
- package/dist/index-BTSmc9Sm.d.ts +0 -645
- package/dist/index-DXazdTzZ.d.cts +0 -645
- package/dist/types-DCzHkhJt.d.ts +0 -467
- package/dist/types-DZIQbgp0.d.cts +0 -467
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { LLMProvider } from '@omnicross/contracts/llm-config';
|
|
2
|
+
import { A as ApiKeyPoolService } from '../ApiKeyPoolService-BmMkau07.cjs';
|
|
3
|
+
import { AuthSource, AuthApplyHints, AuthResultOutcome } from './AuthSource.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* LlmConfigProviderAuth — `AuthSource` for LLM-config provider rows.
|
|
7
|
+
*
|
|
8
|
+
* Phase 2 of the `provider-request-pipeline` OpenSpec change (design D3, task 4.2).
|
|
9
|
+
*
|
|
10
|
+
* Wraps the two pieces that authenticate a normal (non-subscription) provider
|
|
11
|
+
* request today:
|
|
12
|
+
*
|
|
13
|
+
* - `getProviderHeaders(provider, apiKey)` — the format-specific auth
|
|
14
|
+
* headers (x-api-key / Authorization Bearer / x-goog-api-key / api-key)
|
|
15
|
+
* plus content-type and the OpenRouter app-attribution headers. `applyHeaders`
|
|
16
|
+
* merges these into the caller's header object VERBATIM (same output as a
|
|
17
|
+
* direct `getProviderHeaders` call).
|
|
18
|
+
* - `ApiKeyPoolService` — session-affine key selection + 429/529/401/403
|
|
19
|
+
* rotation. `onResult` reproduces the reportable-status branch of
|
|
20
|
+
* the host engine adapter's `callWithPoolReporting` (report → re-bind →
|
|
21
|
+
* return the new key) and the success branch (`reportSuccess`).
|
|
22
|
+
*
|
|
23
|
+
* IMPORTANT (Phase 2 scope): this class is DEFINED + unit-tested in isolation
|
|
24
|
+
* only. NO caller routes through it yet — `executeProviderCall` is unchanged
|
|
25
|
+
* and the rotation INTEGRATION is Phase 3 (D5). Do not wire `onResult` into a
|
|
26
|
+
* fetch loop in this phase.
|
|
27
|
+
*
|
|
28
|
+
* @module pipeline/LlmConfigProviderAuth
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
interface LlmConfigProviderAuthOptions {
|
|
32
|
+
/** Provider row whose auth format + key drives header assembly. */
|
|
33
|
+
provider: LLMProvider;
|
|
34
|
+
/** Resolved API key string to authenticate with (post env-ref resolution). */
|
|
35
|
+
apiKey: string;
|
|
36
|
+
/**
|
|
37
|
+
* Pool service for rotation, when this request is pool-backed. Omit (or pass
|
|
38
|
+
* `null`) for legacy single-key requests — `onResult` then never touches the
|
|
39
|
+
* pool (matching `fromPool === false`).
|
|
40
|
+
*/
|
|
41
|
+
apiKeyPool?: ApiKeyPoolService | null;
|
|
42
|
+
/** Provider id the pool should report/select against (the ACTUAL provider
|
|
43
|
+
* whose key was resolved, post-routing). Required for pool participation. */
|
|
44
|
+
providerId?: string;
|
|
45
|
+
/** Session id for pool affinity + rebind. Required for pool participation. */
|
|
46
|
+
sessionId?: string | null;
|
|
47
|
+
}
|
|
48
|
+
declare class LlmConfigProviderAuth implements AuthSource {
|
|
49
|
+
private readonly provider;
|
|
50
|
+
private readonly apiKeyPool;
|
|
51
|
+
private readonly providerId;
|
|
52
|
+
private readonly sessionId;
|
|
53
|
+
/**
|
|
54
|
+
* The current resolved key. Mutable so a Phase-3 caller can read the
|
|
55
|
+
* rotated key after `onResult`; this phase it is only set at construction
|
|
56
|
+
* and updated inside `onResult` (mirroring the inline re-point in
|
|
57
|
+
* `callWithPoolReporting`).
|
|
58
|
+
*/
|
|
59
|
+
apiKey: string;
|
|
60
|
+
constructor(opts: LlmConfigProviderAuthOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Merge the provider auth headers (and content-type / OpenRouter app
|
|
63
|
+
* headers) into `headers`, exactly as a direct `getProviderHeaders` call
|
|
64
|
+
* would produce them. `hints` are accepted for contract symmetry but the
|
|
65
|
+
* provider-key path does not vary headers by URL/model.
|
|
66
|
+
*/
|
|
67
|
+
applyHeaders(headers: Record<string, string>, _hints: AuthApplyHints): void;
|
|
68
|
+
/**
|
|
69
|
+
* React to the final HTTP status — the pool-rotation seam (design D5).
|
|
70
|
+
*
|
|
71
|
+
* Reproduces `callWithPoolReporting`'s reportable + success branches:
|
|
72
|
+
* - reportable status (429/529/401/403) on a pool-backed request →
|
|
73
|
+
* `reportError(providerId, sessionId, status)`; when it hands back a
|
|
74
|
+
* `newKey` the session was re-bound, so we adopt it (`this.apiKey`) and
|
|
75
|
+
* return `{ rebound: true, newKey }`. When no key is available it returns
|
|
76
|
+
* `{ rebound: false }` (the session is still cooled/disabled by the report).
|
|
77
|
+
* - success / any 2xx → `reportSuccess(sessionId)`; `{ rebound: false }`.
|
|
78
|
+
* - non-reportable, non-success, or non-pool request → no-op
|
|
79
|
+
* `{ rebound: false }`.
|
|
80
|
+
*
|
|
81
|
+
* NOTE: no caller invokes this in Phase 2; it is unit-tested in isolation.
|
|
82
|
+
*/
|
|
83
|
+
onResult(status: number | null): Promise<AuthResultOutcome>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { LlmConfigProviderAuth, type LlmConfigProviderAuthOptions };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { LLMProvider } from '@omnicross/contracts/llm-config';
|
|
2
|
+
import { A as ApiKeyPoolService } from '../ApiKeyPoolService-BmMkau07.js';
|
|
3
|
+
import { AuthSource, AuthApplyHints, AuthResultOutcome } from './AuthSource.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* LlmConfigProviderAuth — `AuthSource` for LLM-config provider rows.
|
|
7
|
+
*
|
|
8
|
+
* Phase 2 of the `provider-request-pipeline` OpenSpec change (design D3, task 4.2).
|
|
9
|
+
*
|
|
10
|
+
* Wraps the two pieces that authenticate a normal (non-subscription) provider
|
|
11
|
+
* request today:
|
|
12
|
+
*
|
|
13
|
+
* - `getProviderHeaders(provider, apiKey)` — the format-specific auth
|
|
14
|
+
* headers (x-api-key / Authorization Bearer / x-goog-api-key / api-key)
|
|
15
|
+
* plus content-type and the OpenRouter app-attribution headers. `applyHeaders`
|
|
16
|
+
* merges these into the caller's header object VERBATIM (same output as a
|
|
17
|
+
* direct `getProviderHeaders` call).
|
|
18
|
+
* - `ApiKeyPoolService` — session-affine key selection + 429/529/401/403
|
|
19
|
+
* rotation. `onResult` reproduces the reportable-status branch of
|
|
20
|
+
* the host engine adapter's `callWithPoolReporting` (report → re-bind →
|
|
21
|
+
* return the new key) and the success branch (`reportSuccess`).
|
|
22
|
+
*
|
|
23
|
+
* IMPORTANT (Phase 2 scope): this class is DEFINED + unit-tested in isolation
|
|
24
|
+
* only. NO caller routes through it yet — `executeProviderCall` is unchanged
|
|
25
|
+
* and the rotation INTEGRATION is Phase 3 (D5). Do not wire `onResult` into a
|
|
26
|
+
* fetch loop in this phase.
|
|
27
|
+
*
|
|
28
|
+
* @module pipeline/LlmConfigProviderAuth
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
interface LlmConfigProviderAuthOptions {
|
|
32
|
+
/** Provider row whose auth format + key drives header assembly. */
|
|
33
|
+
provider: LLMProvider;
|
|
34
|
+
/** Resolved API key string to authenticate with (post env-ref resolution). */
|
|
35
|
+
apiKey: string;
|
|
36
|
+
/**
|
|
37
|
+
* Pool service for rotation, when this request is pool-backed. Omit (or pass
|
|
38
|
+
* `null`) for legacy single-key requests — `onResult` then never touches the
|
|
39
|
+
* pool (matching `fromPool === false`).
|
|
40
|
+
*/
|
|
41
|
+
apiKeyPool?: ApiKeyPoolService | null;
|
|
42
|
+
/** Provider id the pool should report/select against (the ACTUAL provider
|
|
43
|
+
* whose key was resolved, post-routing). Required for pool participation. */
|
|
44
|
+
providerId?: string;
|
|
45
|
+
/** Session id for pool affinity + rebind. Required for pool participation. */
|
|
46
|
+
sessionId?: string | null;
|
|
47
|
+
}
|
|
48
|
+
declare class LlmConfigProviderAuth implements AuthSource {
|
|
49
|
+
private readonly provider;
|
|
50
|
+
private readonly apiKeyPool;
|
|
51
|
+
private readonly providerId;
|
|
52
|
+
private readonly sessionId;
|
|
53
|
+
/**
|
|
54
|
+
* The current resolved key. Mutable so a Phase-3 caller can read the
|
|
55
|
+
* rotated key after `onResult`; this phase it is only set at construction
|
|
56
|
+
* and updated inside `onResult` (mirroring the inline re-point in
|
|
57
|
+
* `callWithPoolReporting`).
|
|
58
|
+
*/
|
|
59
|
+
apiKey: string;
|
|
60
|
+
constructor(opts: LlmConfigProviderAuthOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Merge the provider auth headers (and content-type / OpenRouter app
|
|
63
|
+
* headers) into `headers`, exactly as a direct `getProviderHeaders` call
|
|
64
|
+
* would produce them. `hints` are accepted for contract symmetry but the
|
|
65
|
+
* provider-key path does not vary headers by URL/model.
|
|
66
|
+
*/
|
|
67
|
+
applyHeaders(headers: Record<string, string>, _hints: AuthApplyHints): void;
|
|
68
|
+
/**
|
|
69
|
+
* React to the final HTTP status — the pool-rotation seam (design D5).
|
|
70
|
+
*
|
|
71
|
+
* Reproduces `callWithPoolReporting`'s reportable + success branches:
|
|
72
|
+
* - reportable status (429/529/401/403) on a pool-backed request →
|
|
73
|
+
* `reportError(providerId, sessionId, status)`; when it hands back a
|
|
74
|
+
* `newKey` the session was re-bound, so we adopt it (`this.apiKey`) and
|
|
75
|
+
* return `{ rebound: true, newKey }`. When no key is available it returns
|
|
76
|
+
* `{ rebound: false }` (the session is still cooled/disabled by the report).
|
|
77
|
+
* - success / any 2xx → `reportSuccess(sessionId)`; `{ rebound: false }`.
|
|
78
|
+
* - non-reportable, non-success, or non-pool request → no-op
|
|
79
|
+
* `{ rebound: false }`.
|
|
80
|
+
*
|
|
81
|
+
* NOTE: no caller invokes this in Phase 2; it is unit-tested in isolation.
|
|
82
|
+
*/
|
|
83
|
+
onResult(status: number | null): Promise<AuthResultOutcome>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { LlmConfigProviderAuth, type LlmConfigProviderAuthOptions };
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// src/openrouter.ts
|
|
2
|
+
function isOpenRouterProvider(provider) {
|
|
3
|
+
const baseUrl = (provider.api_base_url || "").toLowerCase();
|
|
4
|
+
return baseUrl.includes("openrouter.ai");
|
|
5
|
+
}
|
|
6
|
+
var OPENROUTER_APP_HEADERS = {
|
|
7
|
+
"HTTP-Referer": "https://omnicross.dev",
|
|
8
|
+
"X-Title": "omnicross"
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/completion/url-builder.ts
|
|
12
|
+
import { resolveProviderEndpoint as resolveProviderEndpointShared } from "@omnicross/contracts/endpoint-resolver";
|
|
13
|
+
function resolveApiFormat(provider) {
|
|
14
|
+
if (provider.apiFormat) {
|
|
15
|
+
return provider.apiFormat;
|
|
16
|
+
}
|
|
17
|
+
if (provider.chatApiFormat) {
|
|
18
|
+
return provider.chatApiFormat;
|
|
19
|
+
}
|
|
20
|
+
if (provider.apiType === "claudecode" || provider.apiType === "anthropic") {
|
|
21
|
+
return "anthropic";
|
|
22
|
+
}
|
|
23
|
+
if (provider.apiType === "google") {
|
|
24
|
+
return "google";
|
|
25
|
+
}
|
|
26
|
+
return "openai";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/completion/header-builder.ts
|
|
30
|
+
function getProviderHeaders(provider, apiKey) {
|
|
31
|
+
const format = resolveApiFormat(provider);
|
|
32
|
+
let headers;
|
|
33
|
+
switch (format) {
|
|
34
|
+
case "anthropic":
|
|
35
|
+
headers = {
|
|
36
|
+
"Content-Type": "application/json",
|
|
37
|
+
"x-api-key": apiKey,
|
|
38
|
+
"anthropic-version": "2025-01-10"
|
|
39
|
+
// Required for extended thinking feature
|
|
40
|
+
};
|
|
41
|
+
break;
|
|
42
|
+
case "google":
|
|
43
|
+
headers = {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
"x-goog-api-key": apiKey
|
|
46
|
+
};
|
|
47
|
+
break;
|
|
48
|
+
case "azure-openai":
|
|
49
|
+
headers = {
|
|
50
|
+
"Content-Type": "application/json",
|
|
51
|
+
"api-key": apiKey
|
|
52
|
+
};
|
|
53
|
+
break;
|
|
54
|
+
case "openai":
|
|
55
|
+
case "openai-response":
|
|
56
|
+
default:
|
|
57
|
+
headers = {
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
"Authorization": `Bearer ${apiKey}`
|
|
60
|
+
};
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
if (isOpenRouterProvider(provider)) {
|
|
64
|
+
return { ...headers, ...OPENROUTER_APP_HEADERS };
|
|
65
|
+
}
|
|
66
|
+
return headers;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// src/pipeline/LlmConfigProviderAuth.ts
|
|
70
|
+
function isReportableStatus(status) {
|
|
71
|
+
return status === 429 || status === 529 || status === 401 || status === 403;
|
|
72
|
+
}
|
|
73
|
+
var LlmConfigProviderAuth = class {
|
|
74
|
+
provider;
|
|
75
|
+
apiKeyPool;
|
|
76
|
+
providerId;
|
|
77
|
+
sessionId;
|
|
78
|
+
/**
|
|
79
|
+
* The current resolved key. Mutable so a Phase-3 caller can read the
|
|
80
|
+
* rotated key after `onResult`; this phase it is only set at construction
|
|
81
|
+
* and updated inside `onResult` (mirroring the inline re-point in
|
|
82
|
+
* `callWithPoolReporting`).
|
|
83
|
+
*/
|
|
84
|
+
apiKey;
|
|
85
|
+
constructor(opts) {
|
|
86
|
+
this.provider = opts.provider;
|
|
87
|
+
this.apiKey = opts.apiKey;
|
|
88
|
+
this.apiKeyPool = opts.apiKeyPool ?? null;
|
|
89
|
+
this.providerId = opts.providerId;
|
|
90
|
+
this.sessionId = opts.sessionId;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Merge the provider auth headers (and content-type / OpenRouter app
|
|
94
|
+
* headers) into `headers`, exactly as a direct `getProviderHeaders` call
|
|
95
|
+
* would produce them. `hints` are accepted for contract symmetry but the
|
|
96
|
+
* provider-key path does not vary headers by URL/model.
|
|
97
|
+
*/
|
|
98
|
+
applyHeaders(headers, _hints) {
|
|
99
|
+
const authHeaders = getProviderHeaders(this.provider, this.apiKey);
|
|
100
|
+
for (const [k, v] of Object.entries(authHeaders)) {
|
|
101
|
+
headers[k] = v;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* React to the final HTTP status — the pool-rotation seam (design D5).
|
|
106
|
+
*
|
|
107
|
+
* Reproduces `callWithPoolReporting`'s reportable + success branches:
|
|
108
|
+
* - reportable status (429/529/401/403) on a pool-backed request →
|
|
109
|
+
* `reportError(providerId, sessionId, status)`; when it hands back a
|
|
110
|
+
* `newKey` the session was re-bound, so we adopt it (`this.apiKey`) and
|
|
111
|
+
* return `{ rebound: true, newKey }`. When no key is available it returns
|
|
112
|
+
* `{ rebound: false }` (the session is still cooled/disabled by the report).
|
|
113
|
+
* - success / any 2xx → `reportSuccess(sessionId)`; `{ rebound: false }`.
|
|
114
|
+
* - non-reportable, non-success, or non-pool request → no-op
|
|
115
|
+
* `{ rebound: false }`.
|
|
116
|
+
*
|
|
117
|
+
* NOTE: no caller invokes this in Phase 2; it is unit-tested in isolation.
|
|
118
|
+
*/
|
|
119
|
+
async onResult(status) {
|
|
120
|
+
const pool = this.apiKeyPool;
|
|
121
|
+
const providerId = this.providerId;
|
|
122
|
+
const sessionId = this.sessionId;
|
|
123
|
+
if (!pool || !providerId || !sessionId) {
|
|
124
|
+
return { rebound: false };
|
|
125
|
+
}
|
|
126
|
+
if (isReportableStatus(status)) {
|
|
127
|
+
const newKey = await pool.reportError(providerId, sessionId, status);
|
|
128
|
+
if (newKey) {
|
|
129
|
+
this.apiKey = newKey;
|
|
130
|
+
return { rebound: true, newKey };
|
|
131
|
+
}
|
|
132
|
+
return { rebound: false };
|
|
133
|
+
}
|
|
134
|
+
if (status !== null && status >= 200 && status < 300) {
|
|
135
|
+
pool.reportSuccess(sessionId);
|
|
136
|
+
}
|
|
137
|
+
return { rebound: false };
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
export {
|
|
141
|
+
LlmConfigProviderAuth
|
|
142
|
+
};
|
|
@@ -1,3 +1,165 @@
|
|
|
1
|
-
import '@omnicross/contracts/subscription-types';
|
|
2
|
-
|
|
3
|
-
import './SubscriptionAuthStrategy.cjs';
|
|
1
|
+
import { OpenCodeGoTokenConfig, OpenCodeGoScenario, OpenCodeGoModelEntry } from '@omnicross/contracts/subscription-types';
|
|
2
|
+
import { AuthSource, AuthApplyHints } from './AuthSource.cjs';
|
|
3
|
+
import { AuthStrategy } from './SubscriptionAuthStrategy.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SubscriptionAuthSource — `AuthSource` wrapping a subscription `AuthStrategy`.
|
|
7
|
+
*
|
|
8
|
+
* Phase 2 of the `provider-request-pipeline` OpenSpec change (design D3, task 4.3).
|
|
9
|
+
*
|
|
10
|
+
* Re-expresses the subscription auth used by `SubscriptionDispatcher` behind
|
|
11
|
+
* the unified `AuthSource` contract, delegating to the existing
|
|
12
|
+
* `AuthStrategy` so the OAuth refresh / token formatting logic is NOT
|
|
13
|
+
* rewritten:
|
|
14
|
+
*
|
|
15
|
+
* - `applyHeaders` → `stripAuthHeaders(headers)` then
|
|
16
|
+
* `authStrategy.applyHeaders(headers, { upstreamUrl, resolvedModel })`,
|
|
17
|
+
* wrapped in the same best-effort try/catch as
|
|
18
|
+
* `SubscriptionDispatcher.applyHeadersWithRetry` (a thrown
|
|
19
|
+
* `applyHeaders` is logged + swallowed, NOT propagated — preserved
|
|
20
|
+
* verbatim).
|
|
21
|
+
* - `onUnauthorized` → `authStrategy.onUnauthorized()`.
|
|
22
|
+
* - `resolveUpstreamUrl` → `profile.resolveUpstreamUrl?.(model)`.
|
|
23
|
+
*
|
|
24
|
+
* IMPORTANT (Phase 2 scope): this WRAPS the strategy + strip behavior but does
|
|
25
|
+
* NOT re-route `SubscriptionDispatcher` through it. The dispatcher's fragile
|
|
26
|
+
* 401-refresh + fallback loop is left UNCHANGED (task 4.5 deferred). This
|
|
27
|
+
* class is unit-tested in isolation only.
|
|
28
|
+
*
|
|
29
|
+
* @module pipeline/SubscriptionAuthSource
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Lightweight summary derived from the inbound request body — consumed by a
|
|
34
|
+
* profile's `modelMapper` (scenario routing). Structural mirror of
|
|
35
|
+
* `provider-proxy/types.ts`'s `SubscriptionRequestSummary`, declared here so
|
|
36
|
+
* `SubscriptionAuthProfile.modelMapper` is type-identical WITHOUT a circular
|
|
37
|
+
* import back into `provider-proxy/types` (which imports THIS module).
|
|
38
|
+
*/
|
|
39
|
+
interface SubscriptionRequestSummary {
|
|
40
|
+
messageCount: number;
|
|
41
|
+
estimatedInputTokens: number;
|
|
42
|
+
/**
|
|
43
|
+
* OPTIONAL bounded per-message match-text slice — kept structurally identical
|
|
44
|
+
* to the canonical declaration in `provider-proxy/types.ts` (the two are
|
|
45
|
+
* deliberate mirrors, not one shared import). Consumed only by the OpenCodeGo
|
|
46
|
+
* keyword matcher in `@omnicross/subscriptions`; core writes, never reads it.
|
|
47
|
+
*/
|
|
48
|
+
matchText?: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The subset of a `SubscriptionDispatchProfile` the subscription paths need.
|
|
52
|
+
* Kept structural (not the full profile type) so the wrapper does not pull in
|
|
53
|
+
* the whole registry surface. The full `SubscriptionDispatchProfile` (which IS
|
|
54
|
+
* what gets passed here) satisfies this shape; the optional `mode` + `modelMapper`
|
|
55
|
+
* are read by the built-in `/v1/messages` subscription path (RT2.1) to decide the
|
|
56
|
+
* verbatim-vs-transformer shape and to apply opencodego scenario routing.
|
|
57
|
+
*/
|
|
58
|
+
interface SubscriptionAuthProfile {
|
|
59
|
+
readonly authStrategy: AuthStrategy;
|
|
60
|
+
/** Per-model upstream URL resolver (transformer profiles). Optional for
|
|
61
|
+
* pass-through profiles that hard-code their endpoint upstream. The OPTIONAL
|
|
62
|
+
* 2nd `config` arg (opencodego `baseUrl` override, D1) is additive — existing
|
|
63
|
+
* one-arg callers compile unchanged; mirrors the full
|
|
64
|
+
* `SubscriptionDispatchProfile.resolveUpstreamUrl` so the registry profile
|
|
65
|
+
* stays assignable. */
|
|
66
|
+
readonly resolveUpstreamUrl?: (resolvedModel: string, config?: OpenCodeGoTokenConfig) => string;
|
|
67
|
+
/**
|
|
68
|
+
* Names of provider-level transformers (registered in `TransformerService`)
|
|
69
|
+
* to run on the subscription chain — re-encode Unified → the upstream's wire.
|
|
70
|
+
* The full `SubscriptionDispatchProfile` (which IS what gets passed here)
|
|
71
|
+
* carries these; exposing them on the narrow structural type lets the
|
|
72
|
+
* Responses ingress build the profile's REAL chain (cross-vendor route-to,
|
|
73
|
+
* task #29) instead of hard-coding `['openai-response']`. Absent/empty →
|
|
74
|
+
* the ingress falls back to its endpoint transformer (codex byte-identity).
|
|
75
|
+
*/
|
|
76
|
+
readonly providerTransformerNames?: readonly string[];
|
|
77
|
+
/** Names of model-specific transformers — usually empty. See above. */
|
|
78
|
+
readonly modelTransformerNames?: readonly string[];
|
|
79
|
+
/**
|
|
80
|
+
* OPTIONAL shape-aware provider transformer-name resolver (opencodego zen).
|
|
81
|
+
* Type-identical to `SubscriptionDispatchProfile.resolveProviderTransformerNames`
|
|
82
|
+
* so the registry profile stays assignable. The built-in `/v1/messages`
|
|
83
|
+
* subscription path (Phase 3) consults it via
|
|
84
|
+
* `profile.resolveProviderTransformerNames?.(model, route.subscriptionConfig)`
|
|
85
|
+
* to pick the right zen chain per resolved shape. `config` is `unknown` (core
|
|
86
|
+
* opaque-config discipline — no `@omnicross/subscriptions` import). When ABSENT
|
|
87
|
+
* the path reads the static `providerTransformerNames` exactly as today (codex
|
|
88
|
+
* byte-identity).
|
|
89
|
+
*/
|
|
90
|
+
readonly resolveProviderTransformerNames?: (model: string, config?: unknown) => readonly string[];
|
|
91
|
+
/**
|
|
92
|
+
* Pass-through (claude) vs transformer (codex / opencodego / gemini). The
|
|
93
|
+
* built-in `/v1/messages` subscription path (RT2.1) reads this for its
|
|
94
|
+
* core-local same-format signal (pass-through ⇒ always verbatim relay).
|
|
95
|
+
* Optional on the narrow type — partial profiles built by other route-minting
|
|
96
|
+
* sites may omit it.
|
|
97
|
+
*/
|
|
98
|
+
readonly mode?: 'pass-through' | 'transformer';
|
|
99
|
+
/**
|
|
100
|
+
* Optional model placeholder rewriter — only set for OpenCodeGo. Type-identical
|
|
101
|
+
* to `SubscriptionDispatchProfile.modelMapper` so the registry profile stays
|
|
102
|
+
* assignable. Applied by the built-in `/v1/messages` subscription path BEFORE
|
|
103
|
+
* resolving the upstream URL (so scenario-based shape routing picks the right
|
|
104
|
+
* Anthropic-shape vs OpenAI-shape upstream).
|
|
105
|
+
*/
|
|
106
|
+
readonly modelMapper?: (sdkModel: string, summary: SubscriptionRequestSummary, config: OpenCodeGoTokenConfig | undefined) => {
|
|
107
|
+
resolvedModel: string;
|
|
108
|
+
scenario: OpenCodeGoScenario;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Optional fallback resolver — only set for OpenCodeGo. Type-identical to
|
|
112
|
+
* `SubscriptionDispatchProfile.nextFallback` so the registry profile stays
|
|
113
|
+
* assignable. Read by the built-in `/v1/messages` fallback loop (D6b) to pick
|
|
114
|
+
* the next model after an unrecoverable upstream failure; returns `null` when
|
|
115
|
+
* exhausted (claude / codex / gemini omit it → no fallback attempted).
|
|
116
|
+
*/
|
|
117
|
+
readonly nextFallback?: (scenario: OpenCodeGoScenario, attempted: readonly string[], config: OpenCodeGoTokenConfig | undefined) => OpenCodeGoModelEntry | null;
|
|
118
|
+
/**
|
|
119
|
+
* Optional circuit-breaker admission gate for the PRIMARY (mapped) model (D5
|
|
120
|
+
* primary-gating). Type-identical to `SubscriptionDispatchProfile.allowModel`.
|
|
121
|
+
* Only OpenCodeGo sets it; the core `/v1/messages` loop consults it for the
|
|
122
|
+
* primary before its first attempt and jumps to the first admitting
|
|
123
|
+
* `nextFallback` candidate when the primary's circuit is open. Absent ⇒ the
|
|
124
|
+
* primary is always admitted (claude / codex / gemini — no breaker).
|
|
125
|
+
*/
|
|
126
|
+
readonly allowModel?: (modelId: string) => boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Optional record-outcome callback (D5 record seam). Type-identical to
|
|
129
|
+
* `SubscriptionDispatchProfile.recordModelOutcome`. The core `/v1/messages`
|
|
130
|
+
* loop calls `profile.recordModelOutcome?.(model, ok)` THROUGH this optional
|
|
131
|
+
* field after each attempt, so `@omnicross/core` gains NO import of
|
|
132
|
+
* `@omnicross/subscriptions` (the cross-layer litmus stays 0 — exactly the
|
|
133
|
+
* `nextFallback` precedent). `ok: true` on `2xx`; `ok: false` on
|
|
134
|
+
* thrown/`5xx`/`429`; a non-429 `4xx` is NEUTRAL (the loop does NOT call it).
|
|
135
|
+
* Absent for claude / codex / gemini ⇒ no-op.
|
|
136
|
+
*/
|
|
137
|
+
readonly recordModelOutcome?: (modelId: string, ok: boolean) => void;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Drop auth headers the transformer chain may have set so the `AuthStrategy`
|
|
141
|
+
* is the single source of truth for outbound authentication. Byte-identical
|
|
142
|
+
* to `SubscriptionDispatcher.stripAuthHeaders`.
|
|
143
|
+
*/
|
|
144
|
+
declare function stripAuthHeaders(headers: Record<string, string>): void;
|
|
145
|
+
declare class SubscriptionAuthSource implements AuthSource {
|
|
146
|
+
private readonly profile;
|
|
147
|
+
constructor(profile: SubscriptionAuthProfile);
|
|
148
|
+
/**
|
|
149
|
+
* Strip any transformer-set auth headers, then delegate to the bound
|
|
150
|
+
* strategy. Mirrors `SubscriptionDispatcher`'s
|
|
151
|
+
* `stripAuthHeaders(...)` + `applyHeadersWithRetry(...)` sequence, including
|
|
152
|
+
* the best-effort swallow-and-warn around a throwing `applyHeaders`.
|
|
153
|
+
*
|
|
154
|
+
* The strategy's looser `AuthApplyHints` (optional `upstreamUrl` /
|
|
155
|
+
* `resolvedModel`) is fed from the pipeline's required `{ upstreamUrl,
|
|
156
|
+
* model }` at the boundary.
|
|
157
|
+
*/
|
|
158
|
+
applyHeaders(headers: Record<string, string>, hints: AuthApplyHints): Promise<void>;
|
|
159
|
+
/** Delegate the 401-refresh decision to the bound strategy. */
|
|
160
|
+
onUnauthorized(): Promise<boolean>;
|
|
161
|
+
/** Resolve the upstream URL from the profile, when it provides one. */
|
|
162
|
+
resolveUpstreamUrl(model: string): string | undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { type SubscriptionAuthProfile, SubscriptionAuthSource, type SubscriptionRequestSummary, stripAuthHeaders };
|
|
@@ -1,3 +1,165 @@
|
|
|
1
|
-
import '@omnicross/contracts/subscription-types';
|
|
2
|
-
|
|
3
|
-
import './SubscriptionAuthStrategy.js';
|
|
1
|
+
import { OpenCodeGoTokenConfig, OpenCodeGoScenario, OpenCodeGoModelEntry } from '@omnicross/contracts/subscription-types';
|
|
2
|
+
import { AuthSource, AuthApplyHints } from './AuthSource.js';
|
|
3
|
+
import { AuthStrategy } from './SubscriptionAuthStrategy.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SubscriptionAuthSource — `AuthSource` wrapping a subscription `AuthStrategy`.
|
|
7
|
+
*
|
|
8
|
+
* Phase 2 of the `provider-request-pipeline` OpenSpec change (design D3, task 4.3).
|
|
9
|
+
*
|
|
10
|
+
* Re-expresses the subscription auth used by `SubscriptionDispatcher` behind
|
|
11
|
+
* the unified `AuthSource` contract, delegating to the existing
|
|
12
|
+
* `AuthStrategy` so the OAuth refresh / token formatting logic is NOT
|
|
13
|
+
* rewritten:
|
|
14
|
+
*
|
|
15
|
+
* - `applyHeaders` → `stripAuthHeaders(headers)` then
|
|
16
|
+
* `authStrategy.applyHeaders(headers, { upstreamUrl, resolvedModel })`,
|
|
17
|
+
* wrapped in the same best-effort try/catch as
|
|
18
|
+
* `SubscriptionDispatcher.applyHeadersWithRetry` (a thrown
|
|
19
|
+
* `applyHeaders` is logged + swallowed, NOT propagated — preserved
|
|
20
|
+
* verbatim).
|
|
21
|
+
* - `onUnauthorized` → `authStrategy.onUnauthorized()`.
|
|
22
|
+
* - `resolveUpstreamUrl` → `profile.resolveUpstreamUrl?.(model)`.
|
|
23
|
+
*
|
|
24
|
+
* IMPORTANT (Phase 2 scope): this WRAPS the strategy + strip behavior but does
|
|
25
|
+
* NOT re-route `SubscriptionDispatcher` through it. The dispatcher's fragile
|
|
26
|
+
* 401-refresh + fallback loop is left UNCHANGED (task 4.5 deferred). This
|
|
27
|
+
* class is unit-tested in isolation only.
|
|
28
|
+
*
|
|
29
|
+
* @module pipeline/SubscriptionAuthSource
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Lightweight summary derived from the inbound request body — consumed by a
|
|
34
|
+
* profile's `modelMapper` (scenario routing). Structural mirror of
|
|
35
|
+
* `provider-proxy/types.ts`'s `SubscriptionRequestSummary`, declared here so
|
|
36
|
+
* `SubscriptionAuthProfile.modelMapper` is type-identical WITHOUT a circular
|
|
37
|
+
* import back into `provider-proxy/types` (which imports THIS module).
|
|
38
|
+
*/
|
|
39
|
+
interface SubscriptionRequestSummary {
|
|
40
|
+
messageCount: number;
|
|
41
|
+
estimatedInputTokens: number;
|
|
42
|
+
/**
|
|
43
|
+
* OPTIONAL bounded per-message match-text slice — kept structurally identical
|
|
44
|
+
* to the canonical declaration in `provider-proxy/types.ts` (the two are
|
|
45
|
+
* deliberate mirrors, not one shared import). Consumed only by the OpenCodeGo
|
|
46
|
+
* keyword matcher in `@omnicross/subscriptions`; core writes, never reads it.
|
|
47
|
+
*/
|
|
48
|
+
matchText?: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The subset of a `SubscriptionDispatchProfile` the subscription paths need.
|
|
52
|
+
* Kept structural (not the full profile type) so the wrapper does not pull in
|
|
53
|
+
* the whole registry surface. The full `SubscriptionDispatchProfile` (which IS
|
|
54
|
+
* what gets passed here) satisfies this shape; the optional `mode` + `modelMapper`
|
|
55
|
+
* are read by the built-in `/v1/messages` subscription path (RT2.1) to decide the
|
|
56
|
+
* verbatim-vs-transformer shape and to apply opencodego scenario routing.
|
|
57
|
+
*/
|
|
58
|
+
interface SubscriptionAuthProfile {
|
|
59
|
+
readonly authStrategy: AuthStrategy;
|
|
60
|
+
/** Per-model upstream URL resolver (transformer profiles). Optional for
|
|
61
|
+
* pass-through profiles that hard-code their endpoint upstream. The OPTIONAL
|
|
62
|
+
* 2nd `config` arg (opencodego `baseUrl` override, D1) is additive — existing
|
|
63
|
+
* one-arg callers compile unchanged; mirrors the full
|
|
64
|
+
* `SubscriptionDispatchProfile.resolveUpstreamUrl` so the registry profile
|
|
65
|
+
* stays assignable. */
|
|
66
|
+
readonly resolveUpstreamUrl?: (resolvedModel: string, config?: OpenCodeGoTokenConfig) => string;
|
|
67
|
+
/**
|
|
68
|
+
* Names of provider-level transformers (registered in `TransformerService`)
|
|
69
|
+
* to run on the subscription chain — re-encode Unified → the upstream's wire.
|
|
70
|
+
* The full `SubscriptionDispatchProfile` (which IS what gets passed here)
|
|
71
|
+
* carries these; exposing them on the narrow structural type lets the
|
|
72
|
+
* Responses ingress build the profile's REAL chain (cross-vendor route-to,
|
|
73
|
+
* task #29) instead of hard-coding `['openai-response']`. Absent/empty →
|
|
74
|
+
* the ingress falls back to its endpoint transformer (codex byte-identity).
|
|
75
|
+
*/
|
|
76
|
+
readonly providerTransformerNames?: readonly string[];
|
|
77
|
+
/** Names of model-specific transformers — usually empty. See above. */
|
|
78
|
+
readonly modelTransformerNames?: readonly string[];
|
|
79
|
+
/**
|
|
80
|
+
* OPTIONAL shape-aware provider transformer-name resolver (opencodego zen).
|
|
81
|
+
* Type-identical to `SubscriptionDispatchProfile.resolveProviderTransformerNames`
|
|
82
|
+
* so the registry profile stays assignable. The built-in `/v1/messages`
|
|
83
|
+
* subscription path (Phase 3) consults it via
|
|
84
|
+
* `profile.resolveProviderTransformerNames?.(model, route.subscriptionConfig)`
|
|
85
|
+
* to pick the right zen chain per resolved shape. `config` is `unknown` (core
|
|
86
|
+
* opaque-config discipline — no `@omnicross/subscriptions` import). When ABSENT
|
|
87
|
+
* the path reads the static `providerTransformerNames` exactly as today (codex
|
|
88
|
+
* byte-identity).
|
|
89
|
+
*/
|
|
90
|
+
readonly resolveProviderTransformerNames?: (model: string, config?: unknown) => readonly string[];
|
|
91
|
+
/**
|
|
92
|
+
* Pass-through (claude) vs transformer (codex / opencodego / gemini). The
|
|
93
|
+
* built-in `/v1/messages` subscription path (RT2.1) reads this for its
|
|
94
|
+
* core-local same-format signal (pass-through ⇒ always verbatim relay).
|
|
95
|
+
* Optional on the narrow type — partial profiles built by other route-minting
|
|
96
|
+
* sites may omit it.
|
|
97
|
+
*/
|
|
98
|
+
readonly mode?: 'pass-through' | 'transformer';
|
|
99
|
+
/**
|
|
100
|
+
* Optional model placeholder rewriter — only set for OpenCodeGo. Type-identical
|
|
101
|
+
* to `SubscriptionDispatchProfile.modelMapper` so the registry profile stays
|
|
102
|
+
* assignable. Applied by the built-in `/v1/messages` subscription path BEFORE
|
|
103
|
+
* resolving the upstream URL (so scenario-based shape routing picks the right
|
|
104
|
+
* Anthropic-shape vs OpenAI-shape upstream).
|
|
105
|
+
*/
|
|
106
|
+
readonly modelMapper?: (sdkModel: string, summary: SubscriptionRequestSummary, config: OpenCodeGoTokenConfig | undefined) => {
|
|
107
|
+
resolvedModel: string;
|
|
108
|
+
scenario: OpenCodeGoScenario;
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Optional fallback resolver — only set for OpenCodeGo. Type-identical to
|
|
112
|
+
* `SubscriptionDispatchProfile.nextFallback` so the registry profile stays
|
|
113
|
+
* assignable. Read by the built-in `/v1/messages` fallback loop (D6b) to pick
|
|
114
|
+
* the next model after an unrecoverable upstream failure; returns `null` when
|
|
115
|
+
* exhausted (claude / codex / gemini omit it → no fallback attempted).
|
|
116
|
+
*/
|
|
117
|
+
readonly nextFallback?: (scenario: OpenCodeGoScenario, attempted: readonly string[], config: OpenCodeGoTokenConfig | undefined) => OpenCodeGoModelEntry | null;
|
|
118
|
+
/**
|
|
119
|
+
* Optional circuit-breaker admission gate for the PRIMARY (mapped) model (D5
|
|
120
|
+
* primary-gating). Type-identical to `SubscriptionDispatchProfile.allowModel`.
|
|
121
|
+
* Only OpenCodeGo sets it; the core `/v1/messages` loop consults it for the
|
|
122
|
+
* primary before its first attempt and jumps to the first admitting
|
|
123
|
+
* `nextFallback` candidate when the primary's circuit is open. Absent ⇒ the
|
|
124
|
+
* primary is always admitted (claude / codex / gemini — no breaker).
|
|
125
|
+
*/
|
|
126
|
+
readonly allowModel?: (modelId: string) => boolean;
|
|
127
|
+
/**
|
|
128
|
+
* Optional record-outcome callback (D5 record seam). Type-identical to
|
|
129
|
+
* `SubscriptionDispatchProfile.recordModelOutcome`. The core `/v1/messages`
|
|
130
|
+
* loop calls `profile.recordModelOutcome?.(model, ok)` THROUGH this optional
|
|
131
|
+
* field after each attempt, so `@omnicross/core` gains NO import of
|
|
132
|
+
* `@omnicross/subscriptions` (the cross-layer litmus stays 0 — exactly the
|
|
133
|
+
* `nextFallback` precedent). `ok: true` on `2xx`; `ok: false` on
|
|
134
|
+
* thrown/`5xx`/`429`; a non-429 `4xx` is NEUTRAL (the loop does NOT call it).
|
|
135
|
+
* Absent for claude / codex / gemini ⇒ no-op.
|
|
136
|
+
*/
|
|
137
|
+
readonly recordModelOutcome?: (modelId: string, ok: boolean) => void;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Drop auth headers the transformer chain may have set so the `AuthStrategy`
|
|
141
|
+
* is the single source of truth for outbound authentication. Byte-identical
|
|
142
|
+
* to `SubscriptionDispatcher.stripAuthHeaders`.
|
|
143
|
+
*/
|
|
144
|
+
declare function stripAuthHeaders(headers: Record<string, string>): void;
|
|
145
|
+
declare class SubscriptionAuthSource implements AuthSource {
|
|
146
|
+
private readonly profile;
|
|
147
|
+
constructor(profile: SubscriptionAuthProfile);
|
|
148
|
+
/**
|
|
149
|
+
* Strip any transformer-set auth headers, then delegate to the bound
|
|
150
|
+
* strategy. Mirrors `SubscriptionDispatcher`'s
|
|
151
|
+
* `stripAuthHeaders(...)` + `applyHeadersWithRetry(...)` sequence, including
|
|
152
|
+
* the best-effort swallow-and-warn around a throwing `applyHeaders`.
|
|
153
|
+
*
|
|
154
|
+
* The strategy's looser `AuthApplyHints` (optional `upstreamUrl` /
|
|
155
|
+
* `resolvedModel`) is fed from the pipeline's required `{ upstreamUrl,
|
|
156
|
+
* model }` at the boundary.
|
|
157
|
+
*/
|
|
158
|
+
applyHeaders(headers: Record<string, string>, hints: AuthApplyHints): Promise<void>;
|
|
159
|
+
/** Delegate the 401-refresh decision to the bound strategy. */
|
|
160
|
+
onUnauthorized(): Promise<boolean>;
|
|
161
|
+
/** Resolve the upstream URL from the profile, when it provides one. */
|
|
162
|
+
resolveUpstreamUrl(model: string): string | undefined;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { type SubscriptionAuthProfile, SubscriptionAuthSource, type SubscriptionRequestSummary, stripAuthHeaders };
|