@caeliq/llms 1.0.58 → 1.0.60

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.
Files changed (57) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +87 -685
  3. package/dist/api/routes.d.ts +2 -0
  4. package/dist/cjs/server.cjs +289 -235
  5. package/dist/cjs/server.cjs.map +4 -4
  6. package/dist/cursor-sdk/session.d.ts +2 -1
  7. package/dist/esm/server.mjs +287 -233
  8. package/dist/esm/server.mjs.map +4 -4
  9. package/dist/routing/inbound-pipeline.d.ts +34 -0
  10. package/dist/routing/protocol-adapter.d.ts +36 -0
  11. package/dist/routing/protocol-endpoints.d.ts +89 -0
  12. package/dist/routing/protocol-errors.d.ts +10 -0
  13. package/dist/server.d.ts +3 -1
  14. package/dist/services/provider.d.ts +1 -1
  15. package/dist/tests/anthropic.client-policy.d.ts +1 -0
  16. package/dist/tests/anthropic.provider-wire.d.ts +1 -0
  17. package/dist/tests/claude-auth.identity.d.ts +1 -0
  18. package/dist/tests/client-abort-classification.test.d.ts +1 -0
  19. package/dist/tests/inbound-protocol-routes.d.ts +1 -0
  20. package/dist/tests/inbound-routing-pipeline.d.ts +1 -0
  21. package/dist/tests/openai.inbound-chat.d.ts +1 -0
  22. package/dist/tests/openai.inbound-responses.d.ts +1 -0
  23. package/dist/tests/protocol-endpoints.d.ts +1 -0
  24. package/dist/tests/reasoning.effort-levels.d.ts +1 -0
  25. package/dist/tests/redact.body-for-log.d.ts +1 -0
  26. package/dist/tests/responses.call-id-sanitize.d.ts +1 -0
  27. package/dist/tests/responses.parallel-and-failure.d.ts +1 -0
  28. package/dist/tests/router-scenario-precedence.d.ts +1 -0
  29. package/dist/tests/system-instructions-fold.d.ts +1 -0
  30. package/dist/tests/upstream-error-semantics.d.ts +1 -0
  31. package/dist/transformer/anthropic.transformer.d.ts +15 -2
  32. package/dist/transformer/claude-auth.transformer.d.ts +59 -4
  33. package/dist/transformer/openai.responses.transformer.d.ts +17 -1
  34. package/dist/transformer/openai.transformer.d.ts +26 -32
  35. package/dist/transformer/tooluse.transformer.d.ts +1 -1
  36. package/dist/transformer/vercel.transformer.d.ts +1 -1
  37. package/dist/transformer/vertex-claude.transformer.d.ts +1 -1
  38. package/dist/transformer/vertex-gemini.transformer.d.ts +1 -1
  39. package/dist/types/llm.d.ts +2 -1
  40. package/dist/types/transformer.d.ts +9 -0
  41. package/dist/utils/anthropic-client-policy.d.ts +45 -0
  42. package/dist/utils/anthropic-url.d.ts +1 -0
  43. package/dist/utils/claude-auth.d.ts +9 -2
  44. package/dist/utils/claude-billing.d.ts +64 -0
  45. package/dist/utils/claude-model-catalog.d.ts +50 -0
  46. package/dist/utils/gemini-thinking.d.ts +2 -1
  47. package/dist/utils/headers.d.ts +10 -0
  48. package/dist/utils/mistral.util.d.ts +1 -1
  49. package/dist/utils/openai.responses.util.d.ts +60 -0
  50. package/dist/utils/reasoning-effort.d.ts +13 -0
  51. package/dist/utils/redact.d.ts +19 -0
  52. package/dist/utils/request.d.ts +1 -1
  53. package/dist/utils/retry.d.ts +7 -0
  54. package/dist/utils/router.d.ts +7 -0
  55. package/dist/utils/stream.d.ts +2 -0
  56. package/dist/utils/toolCallId.d.ts +8 -0
  57. package/package.json +25 -21
@@ -0,0 +1,34 @@
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
+ /** Client wire body after protocol adaptation and CCR-only cleanup. */
11
+ clientWireBody: any;
12
+ /** Normalized Unified body used for routing and provider conversion. */
13
+ unifiedBody: UnifiedChatRequest;
14
+ /** Unified projection before destination-specific Anthropic emulation. */
15
+ prePolicyUnifiedBody: UnifiedChatRequest;
16
+ providerName: string;
17
+ modelName: string;
18
+ }
19
+ /**
20
+ * Stages 1–7 of the canonical inbound lifecycle:
21
+ * detect → adapt → normalize → route → validate destination.
22
+ */
23
+ export declare function prepareInboundRequest(req: FastifyRequest, reply: FastifyReply, fastify: FastifyInstance, endpointTransformer: Transformer, routePath: string): Promise<PreparedInboundRequest>;
24
+ export declare function resolveDestination(model: string | undefined, protocol?: ClientProtocolContext["protocol"]): {
25
+ providerName: string;
26
+ modelName: string;
27
+ };
28
+ /**
29
+ * Decode a discovery alias before scenario routing. Aliases are constrained to
30
+ * configured canonical routes; ordinary `provider,model` ids are unchanged.
31
+ */
32
+ export declare function resolveConfiguredClaudeModelAlias(model: string | undefined, isConfigured: (canonicalId: string) => boolean, protocol?: ClientProtocolContext["protocol"]): string | undefined;
33
+ export declare function throwProtocolError(protocol: ClientProtocolContext["protocol"] | undefined, message: string, statusCode: number, code: string, type?: string): never;
34
+ export declare function protocolAwareBypass(provider: any, transformer: Transformer, protocolContext: ClientProtocolContext | undefined, modelName: string | undefined): boolean;
@@ -0,0 +1,36 @@
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 all end-to-end application headers for a native client. Only
28
+ * credentials, cookies, CCR/proxy routing metadata and hop-by-hop transport
29
+ * headers are removed; provider authentication is generated independently.
30
+ */
31
+ export declare function sanitizePassthroughHeaders(headers: Headers | Record<string, unknown> | undefined): Record<string, string>;
32
+ /**
33
+ * Protocol-aware passthrough: only bypass when the provider speaks the same
34
+ * client protocol (matching transformer name) and the request is same-protocol.
35
+ */
36
+ export declare function shouldBypassTransformersProtocolAware(provider: any, endpointTransformer: Transformer, protocol: ClientProtocolContext["protocol"], bodyModel: string | undefined): boolean;
@@ -0,0 +1,89 @@
1
+ import type { RouterScenarioType } from "../utils/router";
2
+ import type { AnthropicClientKind, AnthropicProviderMode } from "../utils/anthropic-client-policy";
3
+ /**
4
+ * Inbound client protocols supported by CCR's gateway lifecycle.
5
+ */
6
+ export type ClientProtocol = "anthropic_messages" | "openai_chat_completions" | "openai_responses";
7
+ export interface AnthropicSourceRequestFields {
8
+ metadata?: Record<string, unknown>;
9
+ thinking?: Record<string, unknown>;
10
+ outputConfig?: Record<string, unknown>;
11
+ stopSequences?: string[];
12
+ }
13
+ export interface ClientProtocolContext {
14
+ protocol: ClientProtocol;
15
+ pathname: string;
16
+ /** Canonical Fastify route path (without preset prefix), e.g. /v1/responses */
17
+ canonicalPath: string;
18
+ /** Alias path that matched, if different from canonical */
19
+ matchedPath: string;
20
+ originalModel?: string;
21
+ /** Client selected the gateway's trailing `[1m]` context variant. */
22
+ requestedOneMillion?: boolean;
23
+ stream: boolean;
24
+ scenarioType?: RouterScenarioType;
25
+ /** Source-only Anthropic semantics retained before destination routing. */
26
+ anthropicSource?: AnthropicSourceRequestFields;
27
+ /** Client fingerprint captured before Anthropic normalization. */
28
+ anthropicClientKind?: AnthropicClientKind;
29
+ /** In-scope Anthropic destination/auth variant selected after routing. */
30
+ anthropicProviderMode?: AnthropicProviderMode;
31
+ anthropicDestinationInScope?: boolean;
32
+ /** Native Desktop/CLI requests must bypass body and response conversion. */
33
+ anthropicNativeWire?: boolean;
34
+ /** Third-party emulation has already modified the Unified projection. */
35
+ anthropicPolicyApplied?: boolean;
36
+ anthropicSystemTransformed?: boolean;
37
+ claudeAuthToolNameMap?: Map<string, string>;
38
+ /** Claude Code routing metadata extracted without mutating the source billing block. */
39
+ claudeCodeSubagent?: boolean;
40
+ taggedSubagentModel?: string;
41
+ /** Transformer that owns this client protocol */
42
+ ownerTransformerName: string;
43
+ }
44
+ export interface ProtocolRouteMatch {
45
+ protocol: ClientProtocol;
46
+ canonicalPath: string;
47
+ matchedPath: string;
48
+ ownerTransformerName: string;
49
+ /** True when matchedPath is an alias of canonicalPath */
50
+ isAlias: boolean;
51
+ stream: boolean;
52
+ /** Preset namespace prefix without trailing slash, e.g. /preset/foo */
53
+ presetPrefix?: string;
54
+ }
55
+ interface ProtocolRouteSpec {
56
+ protocol: ClientProtocol;
57
+ canonicalPath: string;
58
+ aliases: string[];
59
+ ownerTransformerName: string;
60
+ /** Default stream intent when not encoded in the path */
61
+ defaultStream?: boolean;
62
+ }
63
+ /**
64
+ * Client-facing route table. Aliases are first-class; registration must not
65
+ * rely on transformer endPoint first-wins.
66
+ */
67
+ export declare const PROTOCOL_ROUTE_SPECS: ProtocolRouteSpec[];
68
+ /**
69
+ * Match a client LLM POST path to a protocol. Works with preset prefixes,
70
+ * trailing-slash normalization, and query stripping.
71
+ */
72
+ export declare function matchClientProtocol(method: string, pathnameOrUrl: string): ProtocolRouteMatch | null;
73
+ /** True when method+path is an in-scope routed LLM POST. */
74
+ export declare function isRoutedLlmPost(method: string, pathnameOrUrl: string): boolean;
75
+ /** All Fastify paths that should be registered for a protocol (canonical + aliases). */
76
+ export declare function getRegisteredPathsForProtocol(protocol: ClientProtocol): string[];
77
+ /** Flat list of registered client routes and their owner transformers. */
78
+ export declare function listClientRouteRegistrations(): Array<{
79
+ path: string;
80
+ protocol: ClientProtocol;
81
+ ownerTransformerName: string;
82
+ isCanonical: boolean;
83
+ }>;
84
+ export declare function createClientProtocolContext(match: ProtocolRouteMatch, options?: {
85
+ originalModel?: string;
86
+ stream?: boolean;
87
+ scenarioType?: RouterScenarioType;
88
+ }): ClientProtocolContext;
89
+ 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, enabled: boolean): boolean;
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 {};
@@ -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, _context?: any): Promise<any>;
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,80 @@
1
1
  import { UnifiedChatRequest } from "../types/llm";
2
2
  import { Transformer, TransformerContext } from "../types/transformer";
3
+ import { HeaderRecord } from "../utils/headers";
4
+ import { ClaudeModelCatalogEntry } from "../utils/claude-model-catalog";
3
5
  /** Anthropic beta required for Claude subscription / Claude Code OAuth Bearer auth. */
4
6
  export declare const CLAUDE_OAUTH_REQUIRED_BETA = "oauth-2025-04-20";
5
7
  export declare function mergeAnthropicBetaValues(...values: Array<string | undefined | null>): string;
6
8
  /** Read a named header value from a Fastify/Node headers object (case-insensitive). */
7
9
  export declare function readHeaderValue(headers: Record<string, unknown> | undefined, name: string): string | undefined;
10
+ /** True when the client's User-Agent identifies it as the genuine Claude Code CLI. */
11
+ export declare function isClaudeCodeClient(userAgent: string | undefined): boolean;
8
12
  /**
9
13
  * Build outbound anthropic-beta for Claude subscription OAuth.
10
14
  *
11
15
  * - If the client sent anthropic-beta (e.g. Claude Code), merge with
12
16
  * oauth-2025-04-20 (deduped, case-insensitive).
13
- * - Otherwise, send only oauth-2025-04-20. Do not synthesise Claude Code
14
- * betas — Anthropic validates the attestation on claude-code-20250219
15
- * and subscription OAuth works without it for non-Claude-Code clients.
17
+ * - Otherwise, send only oauth-2025-04-20.
16
18
  */
17
19
  export declare function resolveClaudeAuthAnthropicBeta(input: {
18
20
  clientBeta?: string;
19
21
  }): string;
22
+ /**
23
+ * Build outbound anthropic-beta for the non-Claude-Code (full synthesis)
24
+ * branch, mirroring Claude Code's current model-driven beta selection. Model
25
+ * capabilities come from the catalog; the CLI's one family-level exception
26
+ * (the ordinary Haiku profile omits the Claude Code beta) is retained from the
27
+ * decompiled `cui()` branch. Current CLI `ANTHROPIC_BETAS` values are appended
28
+ * to the profile; OAuth callers still add their required OAuth beta at the auth
29
+ * boundary.
30
+ */
31
+ export declare function resolveClaudeAuthBetas(modelId: string | undefined, opts?: {
32
+ envBeta?: string;
33
+ includeOAuthBeta?: boolean;
34
+ includeToolSearch?: boolean;
35
+ includeEffort?: boolean;
36
+ includeFallbackCredit?: boolean;
37
+ }): string;
38
+ /**
39
+ * Recreate the SDK's context marker only for models whose 1M window is a beta.
40
+ * Native-1M models still accept the gateway picker suffix, but must not receive
41
+ * the legacy context beta upstream.
42
+ */
43
+ export declare function modelIdForRequestedOneMillionBeta(modelId: string | undefined, requestedOneMillion: boolean | undefined): string | undefined;
44
+ /**
45
+ * Reshape a built Anthropic body's `thinking`/`output_config`/`max_tokens`
46
+ * to what the resolved model actually supports, replacing a hand-rolled
47
+ * per-model denylist with a single catalog-driven pass. Operates on the
48
+ * post-build Anthropic body (not the Unified request) because
49
+ * `buildAnthropicBody` may synthesize `thinking`/`output_config` itself.
50
+ */
51
+ export declare function applyClaudeModelCapabilityAdjustments(anthropicBody: Record<string, any>, entry: ClaudeModelCatalogEntry | undefined): void;
52
+ /** Test-only reset hook so session-id state doesn't leak across test cases. */
53
+ export declare function __resetClaudeAuthTransformerStateForTests(): void;
54
+ /** Synthesized Claude Code identity headers for the non-Claude-Code branch. */
55
+ export declare function buildSynthesizedIdentityHeaders(): HeaderRecord;
56
+ export declare function buildSynthesizedUserMetadata(): Record<string, string>;
20
57
  export declare class ClaudeAuthTransformer implements Transformer {
21
58
  name: string;
22
59
  logger?: any;
23
60
  transformRequestIn(request: UnifiedChatRequest, provider: any, context?: TransformerContext): Promise<Record<string, any>>;
24
- transformResponseOut(response: Response): Promise<Response>;
61
+ /**
62
+ * Auth-only path used by native Desktop/CLI raw-wire requests. It keeps the
63
+ * original body and application headers untouched while still replacing the
64
+ * caller credential with CCR's OAuth token.
65
+ */
66
+ auth(request: any, provider: any, context?: TransformerContext): Promise<any>;
67
+ /**
68
+ * Body/URL/wire-format conversion belong to AnthropicTransformer's
69
+ * provider pair, which already ran (response-side order is reversed, so
70
+ * it runs before this stage). This stage only inspects the resulting
71
+ * response for subscription-specific overage observability.
72
+ */
73
+ transformResponseOut(response: Response, context?: TransformerContext): Promise<Response>;
74
+ /**
75
+ * 401 recovery: reload the token file in case another process (e.g. a
76
+ * concurrent `ccr claude-auth` re-login) rotated it externally, otherwise
77
+ * refresh and persist. Never falls through to an unauthenticated request.
78
+ */
79
+ private recoverUnauthorizedAuth;
25
80
  }
@@ -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
- * ## How endPoint works
7
- *
8
- * At startup, `registerApiRoutes` (see `api/routes.ts`) scans all registered
9
- * transformers for ones that define `endPoint`. For each, it registers a
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, provider?: any, context?: any): Promise<any>;
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, provider?: any, context?: any): Promise<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, provider: LLMProvider): Promise<Record<string, any>>;
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, context?: any): Promise<Record<string, any>>;
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
  }
@@ -84,7 +84,8 @@ export interface UnifiedTool {
84
84
  ttl?: "5m" | "1h";
85
85
  };
86
86
  }
87
- export type ThinkLevel = "none" | "low" | "medium" | "high" | "xhigh" | "max";
87
+ export declare const THINK_LEVELS: readonly ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
88
+ export type ThinkLevel = (typeof THINK_LEVELS)[number];
88
89
  export interface UnifiedChatRequest {
89
90
  messages: UnifiedMessage[];
90
91
  model: string;
@@ -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 = {
@@ -0,0 +1,45 @@
1
+ import { UnifiedChatRequest } from "../types/llm";
2
+ export type AnthropicClientKind = "claude_desktop" | "claude_code" | "other";
3
+ export type AnthropicProviderMode = "api_key" | "claude_oauth" | "out_of_scope";
4
+ export interface AnthropicClientFingerprintSignals {
5
+ desktopMarker: boolean;
6
+ desktopUserAgent: boolean;
7
+ desktopAgentSdkUserAgent: boolean;
8
+ cliUserAgent: boolean;
9
+ cliApp: boolean;
10
+ cliSession: boolean;
11
+ stainlessPackage: boolean;
12
+ billingSystem: boolean;
13
+ identitySystem: boolean;
14
+ }
15
+ export interface AnthropicClientPolicyContext {
16
+ anthropicClientKind?: AnthropicClientKind;
17
+ anthropicProviderMode?: AnthropicProviderMode;
18
+ anthropicDestinationInScope?: boolean;
19
+ anthropicNativeWire?: boolean;
20
+ anthropicPolicyApplied?: boolean;
21
+ anthropicSystemTransformed?: boolean;
22
+ claudeAuthToolNameMap?: Map<string, string>;
23
+ }
24
+ export declare function readHeaderValue(headers: Record<string, unknown> | undefined, name: string): string | undefined;
25
+ /**
26
+ * Classify the original Anthropic wire request. A generic SDK UA is never
27
+ * enough to grant native pass-through; incomplete fingerprints fail closed to
28
+ * the third-party emulation path.
29
+ */
30
+ export declare function classifyAnthropicClient(headers: Record<string, unknown> | undefined, body: any): AnthropicClientKind;
31
+ /** Return only non-sensitive boolean fingerprint signals for debug logging. */
32
+ export declare function inspectAnthropicClientFingerprint(headers: Record<string, unknown> | undefined, body: any): AnthropicClientFingerprintSignals;
33
+ /**
34
+ * The feature is intentionally scoped to CCR's real Anthropic provider, with
35
+ * either the exact Anthropic API-key chain or the exact claude-auth + Anthropic
36
+ * OAuth chain. Adjacent middleware makes a provider out of scope.
37
+ */
38
+ export declare function getAnthropicProviderMode(provider: any, endpointTransformerName?: string): AnthropicProviderMode;
39
+ export declare function isNativeAnthropicClient(kind: AnthropicClientKind): boolean;
40
+ /**
41
+ * Apply the one and only system transformation allowed by the gateway policy.
42
+ * This runs after routing has identified an in-scope Anthropic destination and
43
+ * before the provider's Anthropic body builder runs.
44
+ */
45
+ export declare function applyThirdPartyAnthropicPolicy(request: UnifiedChatRequest, context: AnthropicClientPolicyContext, configService: any): Promise<void>;
@@ -0,0 +1 @@
1
+ export declare function buildAnthropicMessagesUrl(baseUrl: string | undefined): string;
@@ -1,4 +1,5 @@
1
- declare const CLAUDE_AUTH_FILE: string;
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
- export { OAUTH_CONFIG, CLAUDE_AUTH_FILE };
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 };