@caeliq/llms 1.0.64 → 1.0.66

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 (37) hide show
  1. package/README.md +2 -1
  2. package/dist/cjs/server.cjs +261 -211
  3. package/dist/cjs/server.cjs.map +4 -4
  4. package/dist/esm/server.mjs +261 -211
  5. package/dist/esm/server.mjs.map +4 -4
  6. package/dist/routing/inbound-pipeline.d.ts +6 -2
  7. package/dist/routing/protocol-adapter.d.ts +2 -0
  8. package/dist/server.d.ts +4 -0
  9. package/dist/tests/codex-system-instructions.d.ts +1 -0
  10. package/dist/tests/latency-cadence.d.ts +1 -0
  11. package/dist/tests/message-debug.d.ts +1 -0
  12. package/dist/tests/openrouter-headers.d.ts +1 -0
  13. package/dist/tests/proxy-dispatcher-cache.d.ts +1 -0
  14. package/dist/tests/reasoning.auto-summary.d.ts +1 -0
  15. package/dist/tests/sse-event-native.d.ts +1 -0
  16. package/dist/tests/transformer-plan.d.ts +1 -0
  17. package/dist/transformer/antigravity-auth.transformer.d.ts +2 -0
  18. package/dist/transformer/codex.transformer.d.ts +4 -14
  19. package/dist/transformer/cursor-sdk.transformer.d.ts +2 -0
  20. package/dist/transformer/openai.transformer.d.ts +2 -0
  21. package/dist/transformer/opencode-headers.transformer.d.ts +4 -0
  22. package/dist/transformer/openrouter.transformer.d.ts +15 -1
  23. package/dist/transformer/reasoning.transformer.d.ts +1 -0
  24. package/dist/types/llm.d.ts +16 -0
  25. package/dist/types/transformer.d.ts +10 -0
  26. package/dist/utils/message-debug.d.ts +35 -0
  27. package/dist/utils/openai.responses.util.d.ts +10 -0
  28. package/dist/utils/paced-sse.d.ts +38 -0
  29. package/dist/utils/reasoning-effort.d.ts +22 -0
  30. package/dist/utils/request-latency.d.ts +33 -0
  31. package/dist/utils/request.d.ts +8 -1
  32. package/dist/utils/sse/incremental-parser.d.ts +35 -0
  33. package/dist/utils/sse-debug-tap.d.ts +32 -0
  34. package/dist/utils/stream.d.ts +26 -3
  35. package/dist/utils/token-count-worker.d.ts +12 -0
  36. package/dist/utils/transformer-plan.d.ts +21 -0
  37. package/package.json +9 -9
@@ -11,8 +11,12 @@ export interface PreparedInboundRequest {
11
11
  clientWireBody: any;
12
12
  /** Normalized Unified body used for routing and provider conversion. */
13
13
  unifiedBody: UnifiedChatRequest;
14
- /** Unified projection before destination-specific Anthropic emulation. */
15
- prePolicyUnifiedBody: UnifiedChatRequest;
14
+ /**
15
+ * Unified projection before destination-specific Anthropic emulation.
16
+ * Only cloned when global fallback is configured; otherwise undefined so
17
+ * fallback can fall back to `unifiedBody`.
18
+ */
19
+ prePolicyUnifiedBody?: UnifiedChatRequest;
16
20
  providerName: string;
17
21
  modelName: string;
18
22
  }
@@ -21,6 +21,8 @@ export declare function normalizeClientToUnified(protocol: ClientProtocolContext
21
21
  /**
22
22
  * Provider transformers are allowed to mutate their input. Every primary and
23
23
  * fallback attempt therefore needs an independent copy of the normalized body.
24
+ * Prefers structuredClone when available; falls back to JSON round-trip for
25
+ * environments without it.
24
26
  */
25
27
  export declare function cloneProtocolBody<T>(value: T): T;
26
28
  /**
package/dist/server.d.ts CHANGED
@@ -45,6 +45,8 @@ declare class Server {
45
45
  }
46
46
  export default Server;
47
47
  export { sessionUsageCache };
48
+ export { closeProxyDispatchers } from "./utils/request";
49
+ export { closeTokenCountWorkers } from "./utils/token-count-worker";
48
50
  export { router };
49
51
  export { calculateTokenCount };
50
52
  export { searchProjectBySession };
@@ -57,6 +59,8 @@ export { pluginManager, tokenSpeedPlugin, getTokenSpeedStats, getGlobalTokenSpee
57
59
  export { SSEParserTransform, SSESerializerTransform, rewriteStream } from "./utils/sse";
58
60
  export { isClientAbortError } from "./utils/retry";
59
61
  export { sanitizeHeadersForLog, diffHeadersForLog, sanitizeBodyForLog, DEFAULT_LOG_BODY_MAX_BYTES, } from "./utils/redact";
62
+ export { logMessageBody, bodyToLogString, shouldLogRequestBodies, shouldLogSSEEvents, resolveLogBodyMaxBytes, isTruthyConfigFlag, type MessageDebugDirection, } from "./utils/message-debug";
63
+ export { tapUpstreamSSEDebug, tapClientSSEDebug, } from "./utils/sse-debug-tap";
60
64
  export { exchangeAuthorizationCode, fetchUserEmail, resolveProjectId, saveTokens, loadTokens, getValidAccessToken, getValidAccessToken as getAntigravityAccessToken, ANTIGRAVITY_CLIENT_ID, ANTIGRAVITY_CLIENT_SECRET, ANTIGRAVITY_REDIRECT_URI, ANTIGRAVITY_SCOPES, type AntigravityTokens, } from "./utils/antigravity-auth";
61
65
  export { getValidAccessToken as getClaudeAccessToken } from "./utils/claude-auth";
62
66
  export { getValidAccessToken as getCodexAccessToken, } from "./utils/codex-auth";
@@ -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 {};
@@ -1,6 +1,8 @@
1
1
  import { Transformer } from "../types/transformer";
2
2
  export declare class AntigravityAuthTransformer implements Transformer {
3
3
  name: string;
4
+ ownsTransport: boolean;
5
+ requestPhase: "transport";
4
6
  logger?: any;
5
7
  private buildAuthAndEnvelope;
6
8
  private buildHeaders;
@@ -38,20 +38,10 @@ export declare class CodexTransformer implements Transformer {
38
38
  */
39
39
  private jsonToSseStream;
40
40
  /**
41
- * Peek at the first non-whitespace character of a cloned response body to
42
- * distinguish a real SSE stream (starts with `data:` or `event:`, first
43
- * char `d` or `e`) from a flat JSON body (first char `{` or `[`) that the
44
- * codex API sometimes returns even with text/event-stream Content-Type.
45
- *
46
- * - **For flat JSON** (`{` / `[`): reads the full clone body and returns
47
- * `{ firstChar, text }` so the caller can parse and handle it.
48
- * - **For SSE** (anything else): returns `null` immediately after reading
49
- * only the first chunk from the clone. The original `response.body` on
50
- * the other side of the tee is untouched and can still be streamed live
51
- * by the SSE reader — avoiding buffering the entire response.
52
- *
53
- * Callers must pass `response.clone().body!` so the original body is not
54
- * consumed by the peek.
41
+ * Peek the first chunk of the response body to distinguish flat JSON from
42
+ * SSE without Response.clone(). JSON drains the body into text; SSE returns
43
+ * a new Response whose stream replays the peeked chunk then continues from
44
+ * the same reader.
55
45
  */
56
46
  private readBodyAndPeek;
57
47
  private collectSseIntoChatCompletion;
@@ -17,6 +17,8 @@ export declare function buildCursorSdkRunnerOptions(options: CursorSdkTransforme
17
17
  export declare class CursorSdkTransformer implements Transformer {
18
18
  static TransformerName: string;
19
19
  name: string;
20
+ ownsTransport: boolean;
21
+ requestPhase: "transport";
20
22
  logger?: any;
21
23
  private options;
22
24
  constructor(options?: CursorSdkTransformerOptions);
@@ -35,6 +35,8 @@ export declare class OpenAITransformer implements Transformer {
35
35
  transformRequestOut(request: any, _context?: TransformerContext): Promise<UnifiedChatRequest>;
36
36
  /**
37
37
  * Provider-side: apply OpenAI-native cache policy to a Unified Chat body.
38
+ * Avoid cloning the entire Unified body (~800KB at longContext) when no
39
+ * mutation will occur – native opencode mutates in place.
38
40
  */
39
41
  transformRequestIn(request: UnifiedChatRequest, provider: any, context: any): Promise<UnifiedChatRequest>;
40
42
  /**
@@ -1,6 +1,8 @@
1
1
  import { Transformer } from "../types/transformer";
2
2
  export declare class OpencodeHeadersTransformer implements Transformer {
3
3
  name: string;
4
+ ownsTransport: boolean;
5
+ requestPhase: "transport";
4
6
  private sessionCache;
5
7
  private readonly MAX_SESSIONS;
6
8
  private lastTimestamp;
@@ -18,6 +20,7 @@ export declare class OpencodeHeadersTransformer implements Transformer {
18
20
  private preserveZenStreamErrors;
19
21
  private static zenStreamFailure;
20
22
  private buildHeaders;
23
+ private resolveParentSessionId;
21
24
  /**
22
25
  * True only for the two Zen session-hash routing failures — a re-roll can
23
26
  * recover these. Kept deliberately narrow (exact status + message) so genuine
@@ -29,6 +32,7 @@ export declare class OpencodeHeadersTransformer implements Transformer {
29
32
  private retryDelayMs;
30
33
  private exponentialRetryDelayMs;
31
34
  private retryAfterHeaders;
35
+ private ensurePromptCacheKey;
32
36
  private fingerprintConversation;
33
37
  private getOrCreateSessionId;
34
38
  private invalidateSession;
@@ -1,10 +1,24 @@
1
1
  import { UnifiedChatRequest } from "../types/llm";
2
2
  import { Transformer, TransformerOptions } from "../types/transformer";
3
+ import { HeaderRecord } from "../utils/headers";
4
+ /**
5
+ * OpenRouter app attribution headers. Some routed upstreams also require a
6
+ * Claude Code–shaped User-Agent; attribution alone is not enough for those.
7
+ * @see https://openrouter.ai/docs/app-attribution
8
+ */
9
+ export declare function buildOpenRouterAttributionHeaders(options?: TransformerOptions): HeaderRecord;
10
+ /**
11
+ * Claude Code CLI identity headers. Prefer the caller's genuine CLI headers;
12
+ * otherwise synthesize the same profile claude-auth uses for non-CLI clients.
13
+ * Several OpenRouter upstreams reject requests without a claude-cli User-Agent.
14
+ */
15
+ export declare function buildOpenRouterClaudeIdentityHeaders(clientHeaders?: Record<string, unknown>, options?: TransformerOptions): HeaderRecord;
16
+ export declare function buildOpenRouterOutboundHeaders(clientHeaders?: Record<string, unknown>, options?: TransformerOptions): HeaderRecord;
3
17
  export declare class OpenrouterTransformer implements Transformer {
4
18
  private readonly options?;
5
19
  static TransformerName: string;
6
20
  logger?: any;
7
21
  constructor(options?: TransformerOptions | undefined);
8
- transformRequestIn(request: UnifiedChatRequest, provider?: any, context?: any): Promise<UnifiedChatRequest>;
22
+ transformRequestIn(request: UnifiedChatRequest, provider?: any, context?: any): Promise<Record<string, any>>;
9
23
  transformResponseOut(response: Response): Promise<Response>;
10
24
  }
@@ -3,6 +3,7 @@ import { Transformer, TransformerOptions } from "../types/transformer";
3
3
  export declare class ReasoningTransformer implements Transformer {
4
4
  private readonly options?;
5
5
  static TransformerName: string;
6
+ name: string;
6
7
  enable: any;
7
8
  constructor(options?: TransformerOptions | undefined);
8
9
  transformRequestIn(request: UnifiedChatRequest, provider?: any, context?: any): Promise<UnifiedChatRequest>;
@@ -115,6 +115,11 @@ export interface UnifiedChatRequest {
115
115
  };
116
116
  reasoning?: {
117
117
  effort?: ThinkLevel;
118
+ /**
119
+ * Request readable reasoning text from destinations that gate it
120
+ * (Responses `reasoning.summary`, Codex, etc.). `"none"` opts out.
121
+ */
122
+ summary?: "auto" | "detailed" | "concise" | "none";
118
123
  max_tokens?: number;
119
124
  enabled?: boolean;
120
125
  };
@@ -133,6 +138,17 @@ export interface UnifiedChatRequest {
133
138
  anthropic_metadata?: Record<string, any>;
134
139
  anthropic_stop_sequences?: string[];
135
140
  reasoning_effort?: string;
141
+ /**
142
+ * Responses opaque `include` list (e.g. `reasoning.encrypted_content`).
143
+ * Client-driven: only set when the inbound protocol was Responses and the
144
+ * client sent it. Chat/Anthropic clients have no equivalent field.
145
+ */
146
+ include?: string[];
147
+ /**
148
+ * Responses `store`. Only `false` is preserved (CCR rejects `store: true`).
149
+ * Client-driven same-protocol hint, paired with `include` by OpenCode/AI SDK.
150
+ */
151
+ store?: false;
136
152
  }
137
153
  export interface UnifiedChatResponse {
138
154
  id: string;
@@ -25,6 +25,8 @@ export interface TransformerContext {
25
25
  claudeAuthPostBuildHook?: (anthropicBody: Record<string, any>) => void;
26
26
  [key: string]: any;
27
27
  }
28
+ /** Where a request transformer runs in the compiled provider/model plan. */
29
+ export type TransformerRequestPhase = "body" | "headers" | "transport";
28
30
  export type Transformer = {
29
31
  transformRequestIn?: (request: UnifiedChatRequest, provider: LLMProvider, context: TransformerContext) => Promise<Record<string, any>>;
30
32
  transformResponseIn?: (response: Response, context?: TransformerContext) => Promise<Response>;
@@ -32,6 +34,14 @@ export type Transformer = {
32
34
  transformResponseOut?: (response: Response, context: TransformerContext) => Promise<Response>;
33
35
  endPoint?: string;
34
36
  name?: string;
37
+ /**
38
+ * When true, this transformer performs the upstream call (fetch, SDK, etc.)
39
+ * and returns the Response via config.__providerResponse. The request plan
40
+ * runs at most one such transformer, after every body/header transform.
41
+ */
42
+ ownsTransport?: boolean;
43
+ /** Optional phase hint; ownsTransport implies "transport". */
44
+ requestPhase?: TransformerRequestPhase;
35
45
  auth?: (request: any, provider: LLMProvider, context: TransformerContext) => Promise<any>;
36
46
  logger?: any;
37
47
  };
@@ -0,0 +1,35 @@
1
+ /** Wire direction for request/response body and SSE message debug logs. */
2
+ export type MessageDebugDirection = "client→ccr" | "ccr→provider" | "provider→ccr" | "ccr→client";
3
+ export declare function isTruthyConfigFlag(value: unknown): boolean;
4
+ export declare function resolveLogBodyMaxBytes(configService: {
5
+ get?: (key: string) => unknown;
6
+ } | null | undefined): number;
7
+ export declare function shouldLogRequestBodies(configService: {
8
+ get?: (key: string) => unknown;
9
+ } | null | undefined): boolean;
10
+ export declare function shouldLogSSEEvents(configService: {
11
+ get?: (key: string) => unknown;
12
+ } | null | undefined): boolean;
13
+ /** Serialize a request/response body for sanitizeBodyForLog. */
14
+ export declare function bodyToLogString(body: unknown): string;
15
+ export type MessageBodyLogOptions = {
16
+ logger: {
17
+ debug?: (...args: any[]) => void;
18
+ info?: (...args: any[]) => void;
19
+ };
20
+ direction: MessageDebugDirection;
21
+ /** Prefer debug; info kept for the legacy Anthropic-only inbound path. */
22
+ level?: "debug" | "info";
23
+ reqId?: string | number;
24
+ protocol?: string;
25
+ provider?: string;
26
+ model?: string;
27
+ maxBytes?: number;
28
+ /** Override the historical `type` field when needed. */
29
+ type?: string;
30
+ };
31
+ /**
32
+ * Opt-in full message-body capture with a stable direction tag so operators
33
+ * can grep client↔CCR and CCR↔provider legs independently.
34
+ */
35
+ export declare function logMessageBody(body: unknown, opts: MessageBodyLogOptions): void;
@@ -12,6 +12,8 @@ export declare function mapCallId(map: ResponsesCallIdMap, id: unknown, directio
12
12
  * Supports the Responses MVP subset; rejects CCR-unsupported stateful fields.
13
13
  */
14
14
  export declare function responsesRequestToUnified(body: any, callIdMap?: ResponsesCallIdMap, customToolNames?: Set<string>): UnifiedChatRequest;
15
+ /** Responses `include` is a string list; drop non-strings rather than invent values. */
16
+ export declare function normalizeResponsesInclude(include: unknown): string[] | undefined;
15
17
  export declare function isResponsesReasoningItemId(value: unknown): value is string;
16
18
  /**
17
19
  * Ciphertext Codex/OpenAI will verify. Item ids and Anthropic/Gemini
@@ -82,6 +84,11 @@ export declare function responsesReasoningItemFromThinking(thinking: {
82
84
  encrypted_content?: string;
83
85
  id?: string;
84
86
  } | undefined, id?: string): any | null;
87
+ /**
88
+ * Zen rejects Requests whose `input` repeats the same reasoning item id.
89
+ * Rewrite placeholders / collisions using ciphertext (or summary) as seed.
90
+ */
91
+ export declare function uniquifyReasoningItemIds(items: any[] | undefined): void;
85
92
  /** Synthetic argument key used to carry a `custom` tool's freeform text
86
93
  * through the Unified/Chat Completions function-call shape. */
87
94
  export declare const CUSTOM_TOOL_INPUT_KEY = "input";
@@ -192,6 +199,9 @@ export interface ResponsesStreamState {
192
199
  thinkingContent: string;
193
200
  thinkingEncryptedContent?: string;
194
201
  thinkingId?: string;
202
+ thinkingStarted: boolean;
203
+ thinkingClosed: boolean;
204
+ thinkingOutputIndex?: number;
195
205
  codexIsolateConventions: boolean;
196
206
  }
197
207
  export declare function createResponsesStreamState(options?: {
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Hermetic paced SSE upstream for latency / cadence benchmarks.
3
+ * Emits fixed-cadence Chat Completions SSE events with configurable delays.
4
+ */
5
+ export type PacedSSEOptions = {
6
+ /** Delay before response headers resolve (ms). */
7
+ headerDelayMs?: number;
8
+ /** Delay before first SSE body byte after headers (ms). */
9
+ firstByteDelayMs?: number;
10
+ /** Gap between successive events (ms). */
11
+ eventIntervalMs?: number;
12
+ /** Number of content delta events. */
13
+ eventCount?: number;
14
+ /** Split each event across this many TCP-ish chunks (default 1). */
15
+ fragmentChunks?: number;
16
+ /** Abort tracking. */
17
+ signal?: AbortSignal;
18
+ /** Optional terminal Zen-style network_error finish_reason. */
19
+ terminalNetworkError?: boolean;
20
+ /** Fail with this HTTP status instead of streaming. */
21
+ httpErrorStatus?: number;
22
+ httpErrorBody?: string;
23
+ };
24
+ export type PacedSSEEventStamp = {
25
+ index: number;
26
+ enqueuedAt: number;
27
+ };
28
+ /**
29
+ * Build a Response whose body emits Chat Completions SSE at a fixed cadence.
30
+ * `stamps` is filled as each logical event is enqueued (before fragmentation).
31
+ */
32
+ export declare function createPacedSSEResponse(options?: PacedSSEOptions, stamps?: PacedSSEEventStamp[]): Promise<Response>;
33
+ /** Read a stream and record when each complete SSE event (blank-line delimited) arrives. */
34
+ export declare function collectSSEEventTimings(body: ReadableStream<Uint8Array>, t0?: number): Promise<{
35
+ events: string[];
36
+ arrivalsMs: number[];
37
+ }>;
38
+ export declare function interArrivalGaps(arrivalsMs: number[]): number[];
@@ -1,7 +1,29 @@
1
1
  import type { ThinkLevel, UnifiedChatRequest } from "../types/llm";
2
2
  type UnifiedReasoning = UnifiedChatRequest["reasoning"];
3
+ /** Readable-reasoning request levels shared across Responses / Codex / config. */
4
+ export type ReasoningSummaryLevel = "auto" | "detailed" | "concise";
3
5
  /** Normalize effort tokens at the protocol boundary without rejecting extensions. */
4
6
  export declare function normalizeReasoningEffort(value: unknown): ThinkLevel | undefined;
7
+ /**
8
+ * Parse `REASONING_AUTO_SUMMARY` / provider `reasoningSummary`.
9
+ * `true` → `"detailed"` (LiteLLM-compatible). `"none"` / false / unset → off.
10
+ */
11
+ export declare function resolveReasoningAutoSummary(value: unknown): ReasoningSummaryLevel | undefined;
12
+ /** True when reasoning is on (effort present and not none, or enabled:true). */
13
+ export declare function isReasoningActive(reasoning: UnifiedReasoning | undefined, thinking?: UnifiedChatRequest["thinking"]): boolean;
14
+ /**
15
+ * Opt-in: when config asks for auto-summary and the client enabled reasoning
16
+ * without an explicit `reasoning.summary`, stamp the Unified field so every
17
+ * destination protocol can request readable thinking the same way.
18
+ */
19
+ export declare function applyReasoningAutoSummary(request: UnifiedChatRequest, configValue: unknown): UnifiedChatRequest;
20
+ /**
21
+ * Outbound precedence: Unified `reasoning.summary` → provider.reasoningSummary.
22
+ * `"none"` means do not request a readable summary.
23
+ */
24
+ export declare function resolveOutboundReasoningSummary(request: Pick<UnifiedChatRequest, "reasoning" | "thinking">, provider?: {
25
+ reasoningSummary?: unknown;
26
+ } | null): ReasoningSummaryLevel | undefined;
5
27
  /** `none` and an explicit enabled:false are the canonical off signals. */
6
28
  export declare function isReasoningDisabled(reasoning: UnifiedReasoning | undefined, thinking?: UnifiedChatRequest["thinking"]): boolean;
7
29
  /** Build the canonical reasoning state used by every inbound protocol. */
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Request-stage latency timings. Allocation-light monotonic stamps; one
3
+ * terminal structured record per request. No per-event logging, no tee.
4
+ */
5
+ export type LatencyStage = "received" | "bodyParsed" | "normalized" | "projectLookup" | "tokenizeStart" | "tokenizeEnd" | "routeSelected" | "destinationPolicy" | "requestTransformers" | "upstreamFetchStart" | "upstreamHeaders" | "upstreamFirstByte" | "responseTransformers" | "downstreamFirstByte" | "complete";
6
+ export type RequestLatency = {
7
+ t0: number;
8
+ stages: Partial<Record<LatencyStage, number>>;
9
+ meta: {
10
+ protocol?: string;
11
+ provider?: string;
12
+ model?: string;
13
+ scenario?: string;
14
+ bypass?: boolean;
15
+ tokenCount?: number;
16
+ inputBytes?: number;
17
+ upstreamAttempts?: number;
18
+ cancelled?: boolean;
19
+ error?: string;
20
+ };
21
+ emitted?: boolean;
22
+ };
23
+ export declare function createRequestLatency(): RequestLatency;
24
+ export declare function markLatency(latency: RequestLatency | undefined | null, stage: LatencyStage): void;
25
+ export declare function tapResponseFirstByte(response: Response, onFirstByte: () => void): Response;
26
+ export declare function attachLatencyMeta(latency: RequestLatency | undefined | null, meta: Partial<RequestLatency["meta"]>): void;
27
+ /** Emit one structured terminal latency record. Safe to call multiple times. */
28
+ export declare function emitLatencyRecord(logger: {
29
+ info?: (obj: unknown, msg?: string) => void;
30
+ } | undefined | null, latency: RequestLatency | undefined | null): void;
31
+ export declare function ensureRequestLatency(req: {
32
+ _latency?: RequestLatency;
33
+ }): RequestLatency;
@@ -1,4 +1,11 @@
1
+ import { ProxyAgent } from "undici";
1
2
  import { UnifiedChatRequest } from "../types/llm";
3
+ /** One Undici ProxyAgent per normalized proxy URL so connections can be reused. */
4
+ export declare function getProxyDispatcher(httpsProxy: string): ProxyAgent;
5
+ /** Close every cached ProxyAgent (call on server shutdown). */
6
+ export declare function closeProxyDispatchers(): void;
7
+ /** Test-only: inspect the module-level dispatcher cache. */
8
+ export declare function __getProxyDispatcherCacheForTests(): Map<string, ProxyAgent>;
2
9
  /** Loopback and NO_PROXY/no_proxy hosts should not go through HTTPS_PROXY. */
3
10
  export declare function shouldBypassProxy(target: URL | string): boolean;
4
- export declare function sendUnifiedRequest(url: URL | string, request: UnifiedChatRequest, config: any, _context: any, _logger?: any): Promise<Response>;
11
+ export declare function sendUnifiedRequest(url: URL | string, request: UnifiedChatRequest, config: any, context: any, _logger?: any): Promise<Response>;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Incremental SSE event parser that preserves each event's raw bytes/text so
3
+ * unchanged events can be forwarded without re-serialization.
4
+ */
5
+ export type ParsedSSEEvent = {
6
+ event?: string;
7
+ id?: string;
8
+ retry?: number;
9
+ /** Parsed JSON, `{ type: "done" }` for [DONE], or `{ raw, error }`. */
10
+ data?: unknown;
11
+ /** Original data field string (without the `data:` prefix), if any. */
12
+ dataRaw?: string;
13
+ /**
14
+ * Exact event block as received, including the blank-line delimiter.
15
+ * Forward this unchanged for byte-preserving passthrough.
16
+ */
17
+ raw: string;
18
+ };
19
+ /**
20
+ * Feed decoded SSE text and emit complete events. Tolerates `\n` and `\r\n`.
21
+ */
22
+ export declare class IncrementalSSEParser {
23
+ private buffer;
24
+ push(chunk: string): ParsedSSEEvent[];
25
+ flush(): ParsedSSEEvent[];
26
+ private takeComplete;
27
+ }
28
+ /** Serialize a (possibly modified) event. Prefer `event.raw` when unchanged. */
29
+ export declare function serializeSSEEvent(event: {
30
+ event?: string;
31
+ id?: string;
32
+ retry?: number;
33
+ data?: unknown;
34
+ dataRaw?: string;
35
+ }): string;
@@ -1,4 +1,5 @@
1
1
  import { type CacheAffinityHeaders, type CachePrefixDiff, type CachePrefixStage } from "./cache-prefix-debug";
2
+ import type { MessageDebugDirection } from "./message-debug";
2
3
  export type UpstreamSSEDebugOptions = {
3
4
  logger?: any;
4
5
  reqId?: string | number;
@@ -19,6 +20,31 @@ export type UpstreamSSEDebugOptions = {
19
20
  cacheDiff?: CachePrefixDiff | null;
20
21
  /** Cap for a single logged payload string (raw `data` field). */
21
22
  maxBytes?: number;
23
+ /**
24
+ * Opt-in raw per-event SSE logging. Independent of LOG_LEVEL=debug.
25
+ * When false (default), the debug tap still computes terminal cache outcome
26
+ * summaries but does not log every delta.
27
+ */
28
+ rawEvents?: boolean;
29
+ /**
30
+ * Which wire leg produced these bytes. Defaults to `provider→ccr` for the
31
+ * upstream tap and `ccr→client` for the client tap.
32
+ */
33
+ direction?: MessageDebugDirection;
34
+ /**
35
+ * When true, only emit raw SSE/JSON event logs (no cache outcome summary).
36
+ * Used for the client-bound leg where cache usage was already observed upstream.
37
+ */
38
+ eventsOnly?: boolean;
39
+ };
40
+ export type ClientSSEDebugOptions = {
41
+ logger?: any;
42
+ reqId?: string | number;
43
+ provider?: string;
44
+ model?: string;
45
+ protocol?: string;
46
+ maxBytes?: number;
47
+ rawEvents?: boolean;
22
48
  };
23
49
  /**
24
50
  * Byte-preserving upstream response debug tap.
@@ -42,6 +68,12 @@ export type UpstreamSSEDebugOptions = {
42
68
  * the single shared place that covers every outbound provider.
43
69
  */
44
70
  export declare function tapUpstreamSSEDebug(response: Response, opts: UpstreamSSEDebugOptions): Promise<Response>;
71
+ /**
72
+ * Byte-preserving tap for the SSE body CCR sends back to the client after
73
+ * response transformers. Same non-blocking tunnel as the upstream tap; events
74
+ * are tagged `direction: "ccr→client"` so greps can split the two legs.
75
+ */
76
+ export declare function tapClientSSEDebug(body: ReadableStream<Uint8Array>, opts: ClientSSEDebugOptions): ReadableStream<Uint8Array>;
45
77
  export type CacheStructureSummary = {
46
78
  systemBreakpoints: number;
47
79
  messageBreakpoints: number;
@@ -1,13 +1,36 @@
1
+ import { type ParsedSSEEvent } from "./sse/incremental-parser";
1
2
  export interface StreamContext {
2
3
  controller: ReadableStreamDefaultController;
3
4
  encoder: TextEncoder;
4
5
  }
5
- export declare function createSSEStreamReader(response: Response, processLine: (line: string, context: StreamContext) => void, options?: {
6
+ export type SSEEvent = ParsedSSEEvent;
7
+ export type ProcessSSEEvent = (event: SSEEvent, context: StreamContext) => void;
8
+ export type ProcessSSELine = (line: string, context: StreamContext) => void;
9
+ /** Forward an event using its original raw bytes/string. */
10
+ export declare function forwardSSEEvent(event: SSEEvent, context: StreamContext): void;
11
+ /** Serialize and enqueue a modified event (only when data changed). */
12
+ export declare function emitSSEEvent(event: {
13
+ event?: string;
14
+ id?: string;
15
+ retry?: number;
16
+ data?: unknown;
17
+ dataRaw?: string;
18
+ }, context: StreamContext): void;
19
+ type StreamReaderOptions = {
6
20
  bufferSize?: number;
7
21
  onComplete?: (context: StreamContext) => void;
8
- /** Return true when the protocol adapter emitted its own terminal error. */
9
22
  onError?: (error: unknown, context: StreamContext) => boolean | void;
10
23
  logger?: any;
11
- }): Response;
24
+ processEvent?: ProcessSSEEvent;
25
+ };
26
+ /**
27
+ * Create a transformed SSE Response.
28
+ *
29
+ * Prefer `options.processEvent` for event-native handling (parse once, forward
30
+ * raw when unchanged). The legacy `processLine` callback is still supported via
31
+ * a shim that feeds reconstructed data lines.
32
+ */
33
+ export declare function createSSEStreamReader(response: Response, processLineOrOptions?: ProcessSSELine | StreamReaderOptions, maybeOptions?: StreamReaderOptions): Response;
12
34
  export declare function encodeSSEData(data: string, encoder: TextEncoder): Uint8Array;
13
35
  export declare function encodeSSELine(line: string, encoder: TextEncoder): Uint8Array;
36
+ export { serializeSSEEvent } from "./sse/incremental-parser";
@@ -0,0 +1,12 @@
1
+ export type TokenCountWorkerRequest = {
2
+ messages: unknown;
3
+ system: unknown;
4
+ tools: unknown;
5
+ };
6
+ /** Offload when serialized payload exceeds this many characters. */
7
+ export declare const TOKEN_COUNT_WORKER_THRESHOLD_CHARS = 200000;
8
+ export declare function estimateTokenizePayloadChars(messages: unknown, system: unknown, tools: unknown): number;
9
+ /** Conservative under-estimate: ~4 chars/token. Safe for "below threshold" skips. */
10
+ export declare function estimateTokensFromChars(charCount: number): number;
11
+ export declare function countTokensInWorker(request: TokenCountWorkerRequest): Promise<number>;
12
+ export declare function closeTokenCountWorkers(): Promise<void>;
@@ -0,0 +1,21 @@
1
+ import type { Transformer } from "../types/transformer";
2
+ export type CompiledTransformerPlan = {
3
+ /** Body/header middleware, then at most one transport owner. */
4
+ request: Transformer[];
5
+ /** Reverse of `request` for onion-style response transforms. */
6
+ response: Transformer[];
7
+ transportOwner?: Transformer;
8
+ };
9
+ /**
10
+ * Compile provider-level + model-level transformer chains into one plan.
11
+ *
12
+ * - Deduplicates by transformer name (first occurrence wins).
13
+ * - Runs every non-transport transformer before the transport owner.
14
+ * - Rejects configurations that leave more than one distinct transport owner.
15
+ */
16
+ export declare function compileTransformerPlan(providerUse: Transformer[] | undefined, modelUse: Transformer[] | undefined, options?: {
17
+ skipName?: string;
18
+ }): CompiledTransformerPlan;
19
+ export declare function isExactProtocolResponsePlan(plan: CompiledTransformerPlan, endpointTransformer: Transformer, clientProtocolOwnerName: string | undefined): boolean;
20
+ /** Cancel a Response body when a newer transport result replaces it. */
21
+ export declare function cancelReplacedProviderResponse(previous: Response | undefined | null, next: Response | undefined | null): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caeliq/llms",
3
- "version": "1.0.64",
3
+ "version": "1.0.66",
4
4
  "description": "A universal LLM API transformation server",
5
5
  "main": "dist/cjs/server.cjs",
6
6
  "module": "dist/esm/server.mjs",
@@ -29,28 +29,28 @@
29
29
  "LICENSE"
30
30
  ],
31
31
  "dependencies": {
32
- "@anthropic-ai/sdk": "^0.115.0",
33
- "@caeliq/ccr-shared": "^2.1.6",
34
- "@cursor/sdk": "^1.0.28",
32
+ "@anthropic-ai/sdk": "^0.120.0",
33
+ "@caeliq/ccr-shared": "^2.1.8",
34
+ "@cursor/sdk": "^1.0.30",
35
35
  "@fastify/cors": "^11.3.0",
36
36
  "@fastify/rate-limit": "^11.2.0",
37
- "@google/genai": "^2.17.1",
37
+ "@google/genai": "^2.18.0",
38
38
  "@huggingface/tokenizers": "^0.1.3",
39
39
  "dotenv": "^17.4.2",
40
- "fastify": "^5.12.0",
40
+ "fastify": "^5.12.1",
41
41
  "fastify-plugin": "^6.0.0",
42
42
  "google-auth-library": "^11.0.2",
43
43
  "json5": "^2.2.3",
44
44
  "jsonrepair": "^3.15.0",
45
45
  "latex-to-unicode": "^0.1.0",
46
46
  "lru-cache": "^11.5.2",
47
- "openai": "^7.4.0",
47
+ "openai": "^7.5.0",
48
48
  "tiktoken": "^1.0.22",
49
49
  "undici": "^8.10.0",
50
- "uuid": "^14.0.1"
50
+ "uuid": "^14.0.2"
51
51
  },
52
52
  "devDependencies": {
53
- "@types/node": "^26.2.0",
53
+ "@types/node": "^26.4.0",
54
54
  "esbuild": "^0.28.2",
55
55
  "tsx": "^4.23.12",
56
56
  "typescript": "^6.0.3"