@caeliq/llms 1.0.58 → 1.0.59
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/LICENSE +1 -1
- package/README.md +82 -686
- package/dist/api/routes.d.ts +2 -0
- package/dist/cjs/server.cjs +286 -236
- package/dist/cjs/server.cjs.map +4 -4
- package/dist/cursor-sdk/session.d.ts +2 -1
- package/dist/esm/server.mjs +286 -236
- package/dist/esm/server.mjs.map +4 -4
- package/dist/routing/inbound-pipeline.d.ts +31 -0
- package/dist/routing/protocol-adapter.d.ts +37 -0
- package/dist/routing/protocol-endpoints.d.ts +77 -0
- package/dist/routing/protocol-errors.d.ts +10 -0
- package/dist/server.d.ts +3 -1
- package/dist/services/provider.d.ts +1 -1
- package/dist/tests/anthropic.provider-wire.d.ts +1 -0
- package/dist/tests/claude-auth.identity.d.ts +1 -0
- package/dist/tests/client-abort-classification.test.d.ts +1 -0
- package/dist/tests/inbound-protocol-routes.d.ts +1 -0
- package/dist/tests/inbound-routing-pipeline.d.ts +1 -0
- package/dist/tests/openai.inbound-chat.d.ts +1 -0
- package/dist/tests/openai.inbound-responses.d.ts +1 -0
- package/dist/tests/protocol-endpoints.d.ts +1 -0
- package/dist/tests/redact.body-for-log.d.ts +1 -0
- package/dist/tests/responses.call-id-sanitize.d.ts +1 -0
- package/dist/tests/responses.parallel-and-failure.d.ts +1 -0
- package/dist/tests/router-scenario-precedence.d.ts +1 -0
- package/dist/tests/system-instructions-fold.d.ts +1 -0
- package/dist/tests/upstream-error-semantics.d.ts +1 -0
- package/dist/transformer/anthropic.transformer.d.ts +15 -2
- package/dist/transformer/claude-auth.transformer.d.ts +36 -4
- package/dist/transformer/openai.responses.transformer.d.ts +17 -1
- package/dist/transformer/openai.transformer.d.ts +26 -32
- package/dist/transformer/tooluse.transformer.d.ts +1 -1
- package/dist/transformer/vercel.transformer.d.ts +1 -1
- package/dist/transformer/vertex-claude.transformer.d.ts +1 -1
- package/dist/transformer/vertex-gemini.transformer.d.ts +1 -1
- package/dist/types/transformer.d.ts +9 -0
- package/dist/utils/claude-auth.d.ts +9 -2
- package/dist/utils/claude-billing.d.ts +58 -0
- package/dist/utils/claude-model-catalog.d.ts +49 -0
- package/dist/utils/headers.d.ts +10 -0
- package/dist/utils/mistral.util.d.ts +1 -1
- package/dist/utils/openai.responses.util.d.ts +53 -0
- package/dist/utils/redact.d.ts +18 -0
- package/dist/utils/request.d.ts +1 -1
- package/dist/utils/retry.d.ts +7 -0
- package/dist/utils/router.d.ts +7 -0
- package/dist/utils/stream.d.ts +2 -0
- package/dist/utils/toolCallId.d.ts +8 -0
- package/package.json +25 -21
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
|
2
|
+
import { Transformer } from "../types/transformer";
|
|
3
|
+
import { UnifiedChatRequest } from "../types/llm";
|
|
4
|
+
import { ClientProtocolContext, ProtocolRouteMatch } from "./protocol-endpoints";
|
|
5
|
+
export interface PreparedInboundRequest {
|
|
6
|
+
match: ProtocolRouteMatch;
|
|
7
|
+
protocolContext: ClientProtocolContext;
|
|
8
|
+
/** Original client wire body (preserved for Anthropic custom routers). */
|
|
9
|
+
originalBody: any;
|
|
10
|
+
/**
|
|
11
|
+
* Client wire body after protocol adaptation and CCR-only cleanup
|
|
12
|
+
* (subagent tag stripped, REWRITE_SYSTEM_PROMPT applied). This — not
|
|
13
|
+
* originalBody — is what an exact-wire passthrough must send upstream.
|
|
14
|
+
*/
|
|
15
|
+
clientWireBody: any;
|
|
16
|
+
/** Normalized Unified body used for routing and provider conversion. */
|
|
17
|
+
unifiedBody: UnifiedChatRequest;
|
|
18
|
+
providerName: string;
|
|
19
|
+
modelName: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Stages 1–7 of the canonical inbound lifecycle:
|
|
23
|
+
* detect → adapt → normalize → route → validate destination.
|
|
24
|
+
*/
|
|
25
|
+
export declare function prepareInboundRequest(req: FastifyRequest, reply: FastifyReply, fastify: FastifyInstance, endpointTransformer: Transformer, routePath: string): Promise<PreparedInboundRequest>;
|
|
26
|
+
export declare function resolveDestination(model: string | undefined, protocol?: ClientProtocolContext["protocol"]): {
|
|
27
|
+
providerName: string;
|
|
28
|
+
modelName: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function throwProtocolError(protocol: ClientProtocolContext["protocol"] | undefined, message: string, statusCode: number, code: string, type?: string): never;
|
|
31
|
+
export declare function protocolAwareBypass(provider: any, transformer: Transformer, protocolContext: ClientProtocolContext | undefined, modelName: string | undefined): boolean;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { UnifiedChatRequest } from "../types/llm";
|
|
2
|
+
import type { Transformer } from "../types/transformer";
|
|
3
|
+
import { ClientProtocolContext, ProtocolRouteMatch } from "./protocol-endpoints";
|
|
4
|
+
export interface ProtocolAdaptResult {
|
|
5
|
+
/** Cloned client body used as normalization input (never the live req.body). */
|
|
6
|
+
normalizationInput: any;
|
|
7
|
+
context: ClientProtocolContext;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Adapt path/query fields into a cloned normalization input and build the
|
|
11
|
+
* initial ClientProtocolContext. Does not mutate the caller's body object.
|
|
12
|
+
*/
|
|
13
|
+
export declare function adaptClientRequest(match: ProtocolRouteMatch, rawBody: any, _query?: Record<string, unknown>): ProtocolAdaptResult;
|
|
14
|
+
/**
|
|
15
|
+
* Normalize client wire → Unified once via the endpoint transformer's
|
|
16
|
+
* transformRequestOut when present. Chat Completions bodies are already
|
|
17
|
+
* Unified-shaped; until Phase 2/3 add full converters, fall back to a
|
|
18
|
+
* lightweight projection sufficient for routing.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeClientToUnified(protocol: ClientProtocolContext["protocol"], normalizationInput: any, endpointTransformer: Transformer, context: any): Promise<UnifiedChatRequest>;
|
|
21
|
+
/**
|
|
22
|
+
* Provider transformers are allowed to mutate their input. Every primary and
|
|
23
|
+
* fallback attempt therefore needs an independent copy of the normalized body.
|
|
24
|
+
*/
|
|
25
|
+
export declare function cloneProtocolBody<T>(value: T): T;
|
|
26
|
+
/**
|
|
27
|
+
* Preserve only known protocol/version and SDK metadata headers for exact-wire
|
|
28
|
+
* passthrough. An allowlist prevents an arbitrary client header from becoming
|
|
29
|
+
* an upstream credential or tenant-routing secret. Provider authentication is
|
|
30
|
+
* generated independently.
|
|
31
|
+
*/
|
|
32
|
+
export declare function sanitizePassthroughHeaders(headers: Headers | Record<string, unknown> | undefined): Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* Protocol-aware passthrough: only bypass when the provider speaks the same
|
|
35
|
+
* client protocol (matching transformer name) and the request is same-protocol.
|
|
36
|
+
*/
|
|
37
|
+
export declare function shouldBypassTransformersProtocolAware(provider: any, endpointTransformer: Transformer, protocol: ClientProtocolContext["protocol"], bodyModel: string | undefined): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { RouterScenarioType } from "../utils/router";
|
|
2
|
+
/**
|
|
3
|
+
* Inbound client protocols supported by CCR's gateway lifecycle.
|
|
4
|
+
*/
|
|
5
|
+
export type ClientProtocol = "anthropic_messages" | "openai_chat_completions" | "openai_responses";
|
|
6
|
+
export interface AnthropicSourceRequestFields {
|
|
7
|
+
metadata?: Record<string, unknown>;
|
|
8
|
+
thinking?: Record<string, unknown>;
|
|
9
|
+
outputConfig?: Record<string, unknown>;
|
|
10
|
+
stopSequences?: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface ClientProtocolContext {
|
|
13
|
+
protocol: ClientProtocol;
|
|
14
|
+
pathname: string;
|
|
15
|
+
/** Canonical Fastify route path (without preset prefix), e.g. /v1/responses */
|
|
16
|
+
canonicalPath: string;
|
|
17
|
+
/** Alias path that matched, if different from canonical */
|
|
18
|
+
matchedPath: string;
|
|
19
|
+
originalModel?: string;
|
|
20
|
+
stream: boolean;
|
|
21
|
+
scenarioType?: RouterScenarioType;
|
|
22
|
+
/** Source-only Anthropic semantics retained before destination routing. */
|
|
23
|
+
anthropicSource?: AnthropicSourceRequestFields;
|
|
24
|
+
/** Keep explicit source cache directives or add provider-native automatic caching. */
|
|
25
|
+
anthropicCacheMode?: "preserve" | "automatic";
|
|
26
|
+
/** Claude Code routing metadata extracted without mutating the source billing block. */
|
|
27
|
+
claudeCodeSubagent?: boolean;
|
|
28
|
+
taggedSubagentModel?: string;
|
|
29
|
+
/** Transformer that owns this client protocol */
|
|
30
|
+
ownerTransformerName: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ProtocolRouteMatch {
|
|
33
|
+
protocol: ClientProtocol;
|
|
34
|
+
canonicalPath: string;
|
|
35
|
+
matchedPath: string;
|
|
36
|
+
ownerTransformerName: string;
|
|
37
|
+
/** True when matchedPath is an alias of canonicalPath */
|
|
38
|
+
isAlias: boolean;
|
|
39
|
+
stream: boolean;
|
|
40
|
+
/** Preset namespace prefix without trailing slash, e.g. /preset/foo */
|
|
41
|
+
presetPrefix?: string;
|
|
42
|
+
}
|
|
43
|
+
interface ProtocolRouteSpec {
|
|
44
|
+
protocol: ClientProtocol;
|
|
45
|
+
canonicalPath: string;
|
|
46
|
+
aliases: string[];
|
|
47
|
+
ownerTransformerName: string;
|
|
48
|
+
/** Default stream intent when not encoded in the path */
|
|
49
|
+
defaultStream?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Client-facing route table. Aliases are first-class; registration must not
|
|
53
|
+
* rely on transformer endPoint first-wins.
|
|
54
|
+
*/
|
|
55
|
+
export declare const PROTOCOL_ROUTE_SPECS: ProtocolRouteSpec[];
|
|
56
|
+
/**
|
|
57
|
+
* Match a client LLM POST path to a protocol. Works with preset prefixes,
|
|
58
|
+
* trailing-slash normalization, and query stripping.
|
|
59
|
+
*/
|
|
60
|
+
export declare function matchClientProtocol(method: string, pathnameOrUrl: string): ProtocolRouteMatch | null;
|
|
61
|
+
/** True when method+path is an in-scope routed LLM POST. */
|
|
62
|
+
export declare function isRoutedLlmPost(method: string, pathnameOrUrl: string): boolean;
|
|
63
|
+
/** All Fastify paths that should be registered for a protocol (canonical + aliases). */
|
|
64
|
+
export declare function getRegisteredPathsForProtocol(protocol: ClientProtocol): string[];
|
|
65
|
+
/** Flat list of registered client routes and their owner transformers. */
|
|
66
|
+
export declare function listClientRouteRegistrations(): Array<{
|
|
67
|
+
path: string;
|
|
68
|
+
protocol: ClientProtocol;
|
|
69
|
+
ownerTransformerName: string;
|
|
70
|
+
isCanonical: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
export declare function createClientProtocolContext(match: ProtocolRouteMatch, options?: {
|
|
73
|
+
originalModel?: string;
|
|
74
|
+
stream?: boolean;
|
|
75
|
+
scenarioType?: RouterScenarioType;
|
|
76
|
+
}): ClientProtocolContext;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ClientProtocol } from "./protocol-endpoints";
|
|
2
|
+
export interface ProtocolErrorBody {
|
|
3
|
+
statusCode: number;
|
|
4
|
+
body: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Build a client-protocol-shaped error envelope for pre-provider failures
|
|
8
|
+
* (auth, validation, missing Router.default, etc.).
|
|
9
|
+
*/
|
|
10
|
+
export declare function protocolErrorBody(protocol: ClientProtocol | undefined, message: string, statusCode: number, code: string, type?: string): ProtocolErrorBody;
|
package/dist/server.d.ts
CHANGED
|
@@ -56,5 +56,7 @@ export { TokenizerService } from "./services/tokenizer";
|
|
|
56
56
|
export { pluginManager, tokenSpeedPlugin, getTokenSpeedStats, getGlobalTokenSpeedStats, CCRPlugin, CCRPluginOptions, PluginMetadata } from "./plugins";
|
|
57
57
|
export { SSEParserTransform, SSESerializerTransform, rewriteStream } from "./utils/sse";
|
|
58
58
|
export { isClientAbortError } from "./utils/retry";
|
|
59
|
-
export { sanitizeHeadersForLog, diffHeadersForLog, } from "./utils/redact";
|
|
59
|
+
export { sanitizeHeadersForLog, diffHeadersForLog, sanitizeBodyForLog, DEFAULT_LOG_BODY_MAX_BYTES, } from "./utils/redact";
|
|
60
60
|
export { exchangeAuthorizationCode, fetchUserEmail, resolveProjectId, saveTokens, loadTokens, getValidAccessToken, ANTIGRAVITY_CLIENT_ID, ANTIGRAVITY_CLIENT_SECRET, ANTIGRAVITY_REDIRECT_URI, ANTIGRAVITY_SCOPES, type AntigravityTokens, } from "./utils/antigravity-auth";
|
|
61
|
+
export { matchClientProtocol, isRoutedLlmPost, listClientRouteRegistrations, type ClientProtocol, type ClientProtocolContext, type ProtocolRouteMatch, } from "./routing/protocol-endpoints";
|
|
62
|
+
export { protocolErrorBody } from "./routing/protocol-errors";
|
|
@@ -17,7 +17,7 @@ export declare class ProviderService {
|
|
|
17
17
|
getProvider(name: string): LLMProvider | undefined;
|
|
18
18
|
updateProvider(id: string, updates: Partial<LLMProvider>): LLMProvider | null;
|
|
19
19
|
deleteProvider(id: string): boolean;
|
|
20
|
-
toggleProvider(name: string,
|
|
20
|
+
toggleProvider(name: string, _enabled: boolean): boolean;
|
|
21
21
|
resolveModelRoute(modelName: string): RequestRouteInfo | null;
|
|
22
22
|
getAvailableModelNames(): string[];
|
|
23
23
|
getModelRoutes(): ModelRoute[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -7,7 +7,20 @@ export declare class AnthropicTransformer implements Transformer {
|
|
|
7
7
|
private useBearer;
|
|
8
8
|
logger?: any;
|
|
9
9
|
constructor(options?: TransformerOptions | undefined);
|
|
10
|
-
auth(request: any, provider: LLMProvider,
|
|
10
|
+
auth(request: any, provider: LLMProvider, context?: TransformerContext): Promise<any>;
|
|
11
|
+
/**
|
|
12
|
+
* Provider-side: Unified → Anthropic Messages wire.
|
|
13
|
+
* Enables cross-protocol clients (Chat/Responses) to reach Anthropic-shaped
|
|
14
|
+
* upstreams. Same-protocol Anthropic clients still use transformRequestOut
|
|
15
|
+
* for client→Unified and may bypass via protocol-aware passthrough.
|
|
16
|
+
*/
|
|
17
|
+
transformRequestIn(request: UnifiedChatRequest, provider: LLMProvider, _context?: TransformerContext): Promise<Record<string, any>>;
|
|
18
|
+
/**
|
|
19
|
+
* Provider-side: Anthropic Messages wire → Unified (Chat Completions shape).
|
|
20
|
+
* Reuses the Vertex Claude Anthropic→Unified converter so streaming and JSON
|
|
21
|
+
* envelopes match existing Anthropic upstream behavior.
|
|
22
|
+
*/
|
|
23
|
+
transformResponseOut(response: Response, _context?: TransformerContext): Promise<Response>;
|
|
11
24
|
transformRequestOut(request: Record<string, any>, context?: TransformerContext): Promise<UnifiedChatRequest>;
|
|
12
25
|
transformResponseIn(response: Response, context?: TransformerContext): Promise<Response>;
|
|
13
26
|
/**
|
|
@@ -15,7 +28,7 @@ export declare class AnthropicTransformer implements Transformer {
|
|
|
15
28
|
* Used by claude-auth.transformRequestIn() to reconstruct the body before
|
|
16
29
|
* sending to Anthropic, preserving all original parameters.
|
|
17
30
|
*/
|
|
18
|
-
static buildAnthropicBody(request: UnifiedChatRequest, logger?: any): Record<string, any>;
|
|
31
|
+
static buildAnthropicBody(request: UnifiedChatRequest, logger?: any, context?: TransformerContext): Record<string, any>;
|
|
19
32
|
private convertAnthropicToolsToUnified;
|
|
20
33
|
private convertOpenAIStreamToAnthropic;
|
|
21
34
|
private convertOpenAIResponseToAnthropic;
|
|
@@ -1,25 +1,57 @@
|
|
|
1
1
|
import { UnifiedChatRequest } from "../types/llm";
|
|
2
2
|
import { Transformer, TransformerContext } from "../types/transformer";
|
|
3
|
+
import { ClaudeModelCatalogEntry } from "../utils/claude-model-catalog";
|
|
3
4
|
/** Anthropic beta required for Claude subscription / Claude Code OAuth Bearer auth. */
|
|
4
5
|
export declare const CLAUDE_OAUTH_REQUIRED_BETA = "oauth-2025-04-20";
|
|
5
6
|
export declare function mergeAnthropicBetaValues(...values: Array<string | undefined | null>): string;
|
|
6
7
|
/** Read a named header value from a Fastify/Node headers object (case-insensitive). */
|
|
7
8
|
export declare function readHeaderValue(headers: Record<string, unknown> | undefined, name: string): string | undefined;
|
|
9
|
+
/** True when the client's User-Agent identifies it as the genuine Claude Code CLI. */
|
|
10
|
+
export declare function isClaudeCodeClient(userAgent: string | undefined): boolean;
|
|
8
11
|
/**
|
|
9
12
|
* Build outbound anthropic-beta for Claude subscription OAuth.
|
|
10
13
|
*
|
|
11
14
|
* - If the client sent anthropic-beta (e.g. Claude Code), merge with
|
|
12
15
|
* oauth-2025-04-20 (deduped, case-insensitive).
|
|
13
|
-
* - Otherwise, send only oauth-2025-04-20.
|
|
14
|
-
* betas — Anthropic validates the attestation on claude-code-20250219
|
|
15
|
-
* and subscription OAuth works without it for non-Claude-Code clients.
|
|
16
|
+
* - Otherwise, send only oauth-2025-04-20.
|
|
16
17
|
*/
|
|
17
18
|
export declare function resolveClaudeAuthAnthropicBeta(input: {
|
|
18
19
|
clientBeta?: string;
|
|
19
20
|
}): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build outbound anthropic-beta for the non-Claude-Code (full synthesis)
|
|
23
|
+
* branch, mirroring Claude Code's own model-driven beta selection. Never
|
|
24
|
+
* derived from model-name prefix matching — always from the capability
|
|
25
|
+
* catalog. `ANTHROPIC_BETA_FLAGS` replaces the list wholesale.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveClaudeAuthBetas(modelId: string | undefined, opts?: {
|
|
28
|
+
envBeta?: string;
|
|
29
|
+
}): string;
|
|
30
|
+
/**
|
|
31
|
+
* Reshape a built Anthropic body's `thinking`/`output_config`/`max_tokens`
|
|
32
|
+
* to what the resolved model actually supports, replacing a hand-rolled
|
|
33
|
+
* per-model denylist with a single catalog-driven pass. Operates on the
|
|
34
|
+
* post-build Anthropic body (not the Unified request) because
|
|
35
|
+
* `buildAnthropicBody` may synthesize `thinking`/`output_config` itself.
|
|
36
|
+
*/
|
|
37
|
+
export declare function applyClaudeModelCapabilityAdjustments(anthropicBody: Record<string, any>, entry: ClaudeModelCatalogEntry | undefined): void;
|
|
38
|
+
/** Test-only reset hook so session-id state doesn't leak across test cases. */
|
|
39
|
+
export declare function __resetClaudeAuthTransformerStateForTests(): void;
|
|
20
40
|
export declare class ClaudeAuthTransformer implements Transformer {
|
|
21
41
|
name: string;
|
|
22
42
|
logger?: any;
|
|
23
43
|
transformRequestIn(request: UnifiedChatRequest, provider: any, context?: TransformerContext): Promise<Record<string, any>>;
|
|
24
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Body/URL/wire-format conversion belong to AnthropicTransformer's
|
|
46
|
+
* provider pair, which already ran (response-side order is reversed, so
|
|
47
|
+
* it runs before this stage). This stage only inspects the resulting
|
|
48
|
+
* response for subscription-specific overage observability.
|
|
49
|
+
*/
|
|
50
|
+
transformResponseOut(response: Response, context?: TransformerContext): Promise<Response>;
|
|
51
|
+
/**
|
|
52
|
+
* 401 recovery: reload the token file in case another process (e.g. a
|
|
53
|
+
* concurrent `ccr claude-auth` re-login) rotated it externally, otherwise
|
|
54
|
+
* refresh and persist. Never falls through to an unauthenticated request.
|
|
55
|
+
*/
|
|
56
|
+
private recoverUnauthorizedAuth;
|
|
25
57
|
}
|
|
@@ -1,11 +1,27 @@
|
|
|
1
1
|
import { UnifiedChatRequest } from "../types/llm";
|
|
2
|
-
import { Transformer } from "../types/transformer";
|
|
2
|
+
import { Transformer, TransformerContext } from "../types/transformer";
|
|
3
3
|
export declare class OpenAIResponsesTransformer implements Transformer {
|
|
4
4
|
logger?: any;
|
|
5
5
|
name: string;
|
|
6
6
|
endPoint: string;
|
|
7
|
+
/**
|
|
8
|
+
* Client → Unified: validate Responses MVP and project to Chat Completions shape.
|
|
9
|
+
* Call-id mapping is stored on the transformer context for the response path.
|
|
10
|
+
*/
|
|
11
|
+
transformRequestOut(request: any, context?: TransformerContext): Promise<UnifiedChatRequest>;
|
|
12
|
+
/**
|
|
13
|
+
* Unified → client Responses: JSON object or SSE lifecycle with mandatory
|
|
14
|
+
* content_part events (Codex requires these or streamed text is discarded).
|
|
15
|
+
*/
|
|
16
|
+
transformResponseIn(response: Response, context?: TransformerContext): Promise<Response>;
|
|
17
|
+
private convertUnifiedStreamToResponses;
|
|
7
18
|
transformRequestIn(request: UnifiedChatRequest, provider?: any, context?: any): Promise<UnifiedChatRequest>;
|
|
8
19
|
transformResponseOut(response: Response): Promise<Response>;
|
|
20
|
+
/**
|
|
21
|
+
* Convert one Responses stream event to a Chat chunk. `choices[0].index` is
|
|
22
|
+
* always 0 — parallel-call identity lives in `delta.tool_calls[n].index`,
|
|
23
|
+
* allocated per Responses item by `toolIndexFor`.
|
|
24
|
+
*/
|
|
9
25
|
private convertStreamEvent;
|
|
10
26
|
private normalizeRequestContent;
|
|
11
27
|
private convertResponseToChat;
|
|
@@ -1,39 +1,12 @@
|
|
|
1
|
-
import { Transformer } from "../types/transformer";
|
|
1
|
+
import { Transformer, TransformerContext } from "../types/transformer";
|
|
2
2
|
import { UnifiedChatRequest } from "../types/llm";
|
|
3
3
|
/**
|
|
4
4
|
* Server-side route handler for the OpenAI Chat Completions API.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* `POST` route at that path. When a request hits the route,
|
|
11
|
-
* `handleTransformerEndpoint` is invoked with the matching transformer as
|
|
12
|
-
* the "endpoint transformer" — the one responsible for converting between
|
|
13
|
-
* the external wire format and the internal Unified format.
|
|
14
|
-
*
|
|
15
|
-
* ## Request handling
|
|
16
|
-
*
|
|
17
|
-
* The Unified format IS the OpenAI Chat Completions format. The conversion
|
|
18
|
-
* from Anthropic → Unified already happened in
|
|
19
|
-
* `AnthropicTransformer.transformRequestOut()` (which runs first in the
|
|
20
|
-
* pipeline). So by the time the provider chain executes, the body is already
|
|
21
|
-
* in the right shape — no further conversion is needed.
|
|
22
|
-
*
|
|
23
|
-
* `transformRequestIn` also translates Claude Code cache intent to the
|
|
24
|
-
* selected provider's native Chat Completions behavior. The provider identity
|
|
25
|
-
* is checked before adding request-level fields so OpenAI-compatible services
|
|
26
|
-
* do not receive OpenAI-only parameters.
|
|
27
|
-
*
|
|
28
|
-
* ## Relationship to OpenAIResponsesTransformer
|
|
29
|
-
*
|
|
30
|
-
* `OpenAIResponsesTransformer` (in `openai.responses.transformer.ts`) is the
|
|
31
|
-
* counterpart for the Responses API (`/v1/responses`). Unlike this
|
|
32
|
-
* transformer, it defines `transformRequestIn` / `transformResponseOut`
|
|
33
|
-
* because the Responses API uses a different wire format (e.g. `messages`
|
|
34
|
-
* → `input`, function tools → flat tool definitions). It also uses the
|
|
35
|
-
* shared utilities in `openai.util.ts` (`validateOpenAIToolCalls`,
|
|
36
|
-
* `injectPromptCaching`) to sanitize the Unified body before converting it.
|
|
6
|
+
* The Unified format IS the OpenAI Chat Completions format. Client inbound
|
|
7
|
+
* normalization validates the MVP subset and passes through already-correct
|
|
8
|
+
* Chat bodies. Provider-side transformRequestIn applies cache policy for
|
|
9
|
+
* OpenAI-compatible upstreams.
|
|
37
10
|
*
|
|
38
11
|
* ## Full request pipeline (for context)
|
|
39
12
|
*
|
|
@@ -44,9 +17,30 @@ import { UnifiedChatRequest } from "../types/llm";
|
|
|
44
17
|
* → provider.transformer.use[].transformResponseOut() // provider middleware (reversed)
|
|
45
18
|
* → AnthropicTransformer.transformResponseIn() // Unified (OpenAI) → Anthropic
|
|
46
19
|
* → Client
|
|
20
|
+
*
|
|
21
|
+
* For inbound Chat Completions clients:
|
|
22
|
+
*
|
|
23
|
+
* Client → POST /v1/chat/completions
|
|
24
|
+
* → OpenAITransformer.transformRequestOut() // validate → Unified
|
|
25
|
+
* → provider.transformer.use[].transformRequestIn()
|
|
26
|
+
* → … → OpenAITransformer.transformResponseIn() // identity / light normalize
|
|
47
27
|
*/
|
|
48
28
|
export declare class OpenAITransformer implements Transformer {
|
|
49
29
|
name: string;
|
|
50
30
|
endPoint: string;
|
|
31
|
+
/**
|
|
32
|
+
* Client → Unified: validate the Chat Completions MVP subset.
|
|
33
|
+
* Unified is already Chat-shaped, so this is validation + light normalization.
|
|
34
|
+
*/
|
|
35
|
+
transformRequestOut(request: any, _context?: TransformerContext): Promise<UnifiedChatRequest>;
|
|
36
|
+
/**
|
|
37
|
+
* Provider-side: apply OpenAI-native cache policy to a Unified Chat body.
|
|
38
|
+
*/
|
|
51
39
|
transformRequestIn(request: UnifiedChatRequest, provider: any, context: any): Promise<UnifiedChatRequest>;
|
|
40
|
+
/**
|
|
41
|
+
* Unified → client Chat Completions: pass through already-correct Chat JSON/SSE.
|
|
42
|
+
* Ensures Content-Type and that streaming responses terminate with [DONE] when
|
|
43
|
+
* the upstream already speaks Chat Completions.
|
|
44
|
+
*/
|
|
45
|
+
transformResponseIn(response: Response, _context?: TransformerContext): Promise<Response>;
|
|
52
46
|
}
|
|
@@ -2,6 +2,6 @@ import { UnifiedChatRequest } from "../types/llm";
|
|
|
2
2
|
import { Transformer } from "../types/transformer";
|
|
3
3
|
export declare class TooluseTransformer implements Transformer {
|
|
4
4
|
name: string;
|
|
5
|
-
transformRequestIn(request: UnifiedChatRequest,
|
|
5
|
+
transformRequestIn(request: UnifiedChatRequest, _provider?: any, _context?: any): Promise<any>;
|
|
6
6
|
transformResponseOut(response: Response): Promise<Response>;
|
|
7
7
|
}
|
|
@@ -6,6 +6,6 @@ export declare class VercelTransformer implements Transformer {
|
|
|
6
6
|
logger?: any;
|
|
7
7
|
endPoint: string;
|
|
8
8
|
constructor(options?: TransformerOptions | undefined);
|
|
9
|
-
transformRequestIn(request: UnifiedChatRequest,
|
|
9
|
+
transformRequestIn(request: UnifiedChatRequest, _provider?: any, _context?: any): Promise<UnifiedChatRequest>;
|
|
10
10
|
transformResponseOut(response: Response): Promise<Response>;
|
|
11
11
|
}
|
|
@@ -3,7 +3,7 @@ import { Transformer } from "../types/transformer";
|
|
|
3
3
|
export declare class VertexClaudeTransformer implements Transformer {
|
|
4
4
|
logger?: any;
|
|
5
5
|
name: string;
|
|
6
|
-
transformRequestIn(request: UnifiedChatRequest,
|
|
6
|
+
transformRequestIn(request: UnifiedChatRequest, _provider: LLMProvider): Promise<Record<string, any>>;
|
|
7
7
|
transformRequestOut(request: Record<string, any>): Promise<UnifiedChatRequest>;
|
|
8
8
|
transformResponseOut(response: Response): Promise<Response>;
|
|
9
9
|
}
|
|
@@ -6,7 +6,7 @@ export declare class VertexGeminiTransformer implements Transformer {
|
|
|
6
6
|
name: string;
|
|
7
7
|
private readonly thoughtSignatureFallback;
|
|
8
8
|
constructor(options?: TransformerOptions);
|
|
9
|
-
transformRequestIn(request: UnifiedChatRequest, provider: LLMProvider,
|
|
9
|
+
transformRequestIn(request: UnifiedChatRequest, provider: LLMProvider, _context?: any): Promise<Record<string, any>>;
|
|
10
10
|
transformRequestOut(request: Record<string, any>): Promise<UnifiedChatRequest>;
|
|
11
11
|
transformResponseOut(response: Response, context?: TransformerContext): Promise<Response>;
|
|
12
12
|
}
|
|
@@ -14,6 +14,15 @@ export interface TransformerContext {
|
|
|
14
14
|
signal?: AbortSignal;
|
|
15
15
|
/** Protocol semantics that must not be serialized into the provider body. */
|
|
16
16
|
unifiedRequest?: UnifiedRequestRuntime;
|
|
17
|
+
/**
|
|
18
|
+
* Set by claude-auth's transformRequestIn (non-Claude-Code branch) so that
|
|
19
|
+
* AnthropicTransformer.transformRequestIn — which owns building the wire
|
|
20
|
+
* body — can apply claude-auth's catalog-driven capability clamping and
|
|
21
|
+
* synthesized user_id metadata immediately after building it. Keeps model
|
|
22
|
+
* capability/identity-synthesis policy owned by claude-auth while
|
|
23
|
+
* AnthropicTransformer remains the sole body-shape/timing owner.
|
|
24
|
+
*/
|
|
25
|
+
claudeAuthPostBuildHook?: (anthropicBody: Record<string, any>) => void;
|
|
17
26
|
[key: string]: any;
|
|
18
27
|
}
|
|
19
28
|
export type Transformer = {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
declare
|
|
1
|
+
declare function getClaudeAuthFilePath(): string;
|
|
2
|
+
declare function getClaudeDeviceFilePath(): string;
|
|
2
3
|
declare const OAUTH_CONFIG: {
|
|
3
4
|
client_id: string;
|
|
4
5
|
authorization_endpoint: string;
|
|
@@ -19,4 +20,10 @@ export declare function saveTokens(tokens: ClaudeTokens): void;
|
|
|
19
20
|
export declare function isTokenExpired(tokens: ClaudeTokens, leewaySeconds?: number): boolean;
|
|
20
21
|
export declare function refreshTokens(refreshToken: string): Promise<ClaudeTokens>;
|
|
21
22
|
export declare function getValidAccessToken(): Promise<ClaudeTokens>;
|
|
22
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Load the persisted synthesized-client device id, minting and persisting a
|
|
25
|
+
* fresh 64-hex value on first use. Stored alongside the OAuth token file
|
|
26
|
+
* (mode 0600) but kept separate from it — it is not a credential.
|
|
27
|
+
*/
|
|
28
|
+
export declare function loadOrCreateDeviceId(): string;
|
|
29
|
+
export { OAUTH_CONFIG, getClaudeAuthFilePath, getClaudeDeviceFilePath };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { TextContent, UnifiedChatRequest, UnifiedMessage } from "../types/llm";
|
|
2
|
+
/** Salt used in Claude Code's `cc_version` suffix hash (`RYn()`). */
|
|
3
|
+
export declare const BILLING_SALT = "59cf53e54c78";
|
|
4
|
+
export declare const CC_VERSION: string;
|
|
5
|
+
export declare const CC_ENTRYPOINT: string;
|
|
6
|
+
export declare const SYSTEM_IDENTITY = "You are Claude Code, Anthropic's official CLI for Claude.";
|
|
7
|
+
export declare function extractFirstUserMessageText(messages: UnifiedMessage[] | undefined): string;
|
|
8
|
+
export declare function computeVersionSuffix(text: string, version: string): string;
|
|
9
|
+
/** 5 lowercase hex chars, cached per process — not a content hash. */
|
|
10
|
+
export declare function sessionCch(): string;
|
|
11
|
+
export declare function __resetClaudeBillingStateForTests(): void;
|
|
12
|
+
export declare function buildClaudeBillingHeaderValue(messages: UnifiedMessage[] | undefined, version?: string, entrypoint?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Normalize `request.system` to an array as a complete ordered fold:
|
|
15
|
+
* top-level `request.system` blocks first, then every `role:"system"` /
|
|
16
|
+
* `role:"developer"` message's text blocks in source order. Consumed messages
|
|
17
|
+
* are removed from `request.messages` so no downstream builder can drop or
|
|
18
|
+
* double-emit them. Block-level `cache_control` is preserved.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeSystemToArray(request: UnifiedChatRequest): TextContent[];
|
|
21
|
+
/** Drop any existing billing entry (dedupe) and prepend a fresh one at system[0]. */
|
|
22
|
+
export declare function applyClaudeBillingSystemBlock(system: TextContent[], messages: UnifiedMessage[] | undefined): void;
|
|
23
|
+
/**
|
|
24
|
+
* Insert SYSTEM_IDENTITY as its own entry at system[1]. Any remaining
|
|
25
|
+
* caller system content is left in place here — relocateForeignSystemContent
|
|
26
|
+
* (called separately, afterwards) is what moves it out of system[].
|
|
27
|
+
*/
|
|
28
|
+
export declare function applyClaudeSystemIdentity(system: TextContent[]): void;
|
|
29
|
+
/**
|
|
30
|
+
* Move everything in `system[]` past the identity block (index 1) into the
|
|
31
|
+
* first user message instead. Anthropic's OAuth billing validator appears to
|
|
32
|
+
* inspect `system[]` content beyond the identity prefix and reject requests
|
|
33
|
+
* whose system array carries a foreign harness prompt with an "out of extra
|
|
34
|
+
* usage" 400 — the same approach used by third-party Claude Code OAuth
|
|
35
|
+
* clients (e.g. opencode-claude-auth). The relocated text still reaches the
|
|
36
|
+
* model, just as part of the first user turn rather than
|
|
37
|
+
* `system[]`.
|
|
38
|
+
*
|
|
39
|
+
* A no-op when there is no user message to attach the content to, so nothing
|
|
40
|
+
* is silently dropped — the caller's system content stays in `system[]`
|
|
41
|
+
* instead.
|
|
42
|
+
*/
|
|
43
|
+
export declare function relocateForeignSystemContent(system: TextContent[], messages: UnifiedMessage[] | undefined): void;
|
|
44
|
+
/**
|
|
45
|
+
* Claude Code's OAuth validator expects tool names in the mcp_PascalCase
|
|
46
|
+
* spelling used by the official CLI. Non-Claude-Code clients commonly send
|
|
47
|
+
* ordinary names such as `bash` or `read`, so normalize them before the
|
|
48
|
+
* Anthropic body is built. The prefix check keeps this operation idempotent.
|
|
49
|
+
*/
|
|
50
|
+
export declare function prefixClaudeToolName(name: string): string;
|
|
51
|
+
/** Restore a Claude Code tool name to the caller's original spelling. */
|
|
52
|
+
export declare function unprefixClaudeToolName(name: string): string;
|
|
53
|
+
/** Rewrite tool names in a Unified request in place for the OAuth wire path. */
|
|
54
|
+
export declare function prefixClaudeToolNames(request: UnifiedChatRequest, nameMap?: Map<string, string>): void;
|
|
55
|
+
/** Rewrite tool names in a Unified/OpenAI-shaped response in place. */
|
|
56
|
+
export declare function unprefixClaudeToolNames(value: any, nameMap?: Map<string, string>): void;
|
|
57
|
+
/** Rewrite one OpenAI SSE data payload's tool names. */
|
|
58
|
+
export declare function unprefixClaudeToolNamesInSseData(value: any, nameMap?: Map<string, string>): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's bundled model capability catalog (extracted from v2.1.220).
|
|
3
|
+
*
|
|
4
|
+
* Every model-dependent decision in the claude-auth impersonation path (beta
|
|
5
|
+
* flags, effort support, thinking shape, max_tokens ceiling) is driven by
|
|
6
|
+
* `capabilities` membership here, never by matching on the model name.
|
|
7
|
+
*/
|
|
8
|
+
export interface ClaudeModelCatalogEntry {
|
|
9
|
+
/** Context window in tokens, or undefined when the model predates 1M-context routing. */
|
|
10
|
+
window?: number;
|
|
11
|
+
/** Router carries a native (unconditional) 1M-token context window. */
|
|
12
|
+
nativeOneMillion: boolean;
|
|
13
|
+
/** Model can opt into a 1M-token window via the context-1m-2025-08-07 beta. */
|
|
14
|
+
supportsOneMillionBeta: boolean;
|
|
15
|
+
/** Model id accepts an explicit "[1m]" wire suffix. */
|
|
16
|
+
supportsOneMillionSuffix: boolean;
|
|
17
|
+
maxOutputTokens: {
|
|
18
|
+
default: number;
|
|
19
|
+
upper: number;
|
|
20
|
+
};
|
|
21
|
+
defaultEffort?: string;
|
|
22
|
+
capabilities: string[];
|
|
23
|
+
}
|
|
24
|
+
export declare const CLAUDE_MODEL_CATALOG: Record<string, ClaudeModelCatalogEntry>;
|
|
25
|
+
/** Strip the "[1m]" wire marker, reporting whether it was present. */
|
|
26
|
+
export declare function stripOneMillionContextMarker(modelId: string | undefined): {
|
|
27
|
+
modelId: string;
|
|
28
|
+
requestedOneMillion: boolean;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Normalize a routed model id (CCR "provider,model" selector, an optional
|
|
32
|
+
* "[1m]" marker, and Anthropic's dated model-id suffix) down to a catalog
|
|
33
|
+
* key, e.g. "anthropic,claude-opus-5-20260101[1m]" -> "claude-opus-5".
|
|
34
|
+
*/
|
|
35
|
+
export declare function normalizeModelIdForCatalog(modelId: string | undefined): string;
|
|
36
|
+
/** Look up a model's catalog entry. Unknown models resolve to undefined (minimal capability set). */
|
|
37
|
+
export declare function lookupClaudeModelCatalogEntry(modelId: string | undefined): ClaudeModelCatalogEntry | undefined;
|
|
38
|
+
export declare function catalogEntryHasCapability(entry: ClaudeModelCatalogEntry | undefined, capability: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether extended-thinking betas apply to this model. The catalog has no
|
|
41
|
+
* dedicated "supports_thinking" column, but every entry that predates the
|
|
42
|
+
* Claude 4 thinking generation (claude-3-5-haiku, claude-3-5-sonnet,
|
|
43
|
+
* claude-3-7-sonnet) — plus the not-yet-classified claude-mythos-5 — carries
|
|
44
|
+
* an empty capability set; every thinking-capable model carries at least
|
|
45
|
+
* "context_management". A non-empty capability set is therefore a reliable,
|
|
46
|
+
* self-documenting proxy that also degrades unknown models to "no thinking"
|
|
47
|
+
* rather than guessing.
|
|
48
|
+
*/
|
|
49
|
+
export declare function catalogEntrySupportsThinking(entry: ClaudeModelCatalogEntry | undefined): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type HeaderRecord = Record<string, string | undefined>;
|
|
2
|
+
export declare function mergeHeadersCaseInsensitive(base: HeaderRecord | undefined, update: HeaderRecord | undefined): HeaderRecord;
|
|
3
|
+
/**
|
|
4
|
+
* Carry non-representational upstream response headers (rate-limit/usage
|
|
5
|
+
* metadata, request ids, etc.) onto a reshaped `Response`, so overage
|
|
6
|
+
* observability (`anthropic-ratelimit-unified-*`) survives SSE re-framing.
|
|
7
|
+
*/
|
|
8
|
+
export declare function preserveUpstreamResponseHeaders(headers: Headers | undefined): Record<string, string>;
|
|
9
|
+
export declare function selectSafeDownstreamHeaders(headers: Headers | HeaderRecord | undefined): Record<string, string>;
|
|
10
|
+
export declare function canonicalizeOutboundHeaders(headers: HeaderRecord | undefined, fallbackBearer?: string): Record<string, string>;
|
|
@@ -2,7 +2,7 @@ import { UnifiedChatRequest } from "../types/llm";
|
|
|
2
2
|
/**
|
|
3
3
|
* Transform incoming request to Mistral-compatible format
|
|
4
4
|
*/
|
|
5
|
-
export declare function buildRequestBody(request: UnifiedChatRequest, context?: any,
|
|
5
|
+
export declare function buildRequestBody(request: UnifiedChatRequest, context?: any, _provider?: any): Record<string, any>;
|
|
6
6
|
/**
|
|
7
7
|
* Transform a Mistral provider request back into a UnifiedChatRequest
|
|
8
8
|
*/
|