@caeliq/llms 1.0.65 → 1.0.67

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 (59) hide show
  1. package/README.md +4 -2
  2. package/dist/cjs/server.cjs +287 -227
  3. package/dist/cjs/server.cjs.map +4 -4
  4. package/dist/cursor-sdk/auth-exchange-cache.d.ts +23 -0
  5. package/dist/cursor-sdk/lifecycle-planner.d.ts +16 -4
  6. package/dist/cursor-sdk/prompt.d.ts +10 -0
  7. package/dist/cursor-sdk/session.d.ts +23 -0
  8. package/dist/cursor-sdk/turn-output.d.ts +3 -0
  9. package/dist/cursor-sdk/usage.d.ts +17 -0
  10. package/dist/esm/server.mjs +287 -227
  11. package/dist/esm/server.mjs.map +4 -4
  12. package/dist/routing/inbound-pipeline.d.ts +6 -2
  13. package/dist/routing/protocol-adapter.d.ts +2 -0
  14. package/dist/routing/protocol-endpoints.d.ts +14 -0
  15. package/dist/server.d.ts +4 -0
  16. package/dist/tests/anthropic.message-start-usage.test.d.ts +1 -0
  17. package/dist/tests/cache-outcome.d.ts +1 -0
  18. package/dist/tests/codex-system-instructions.d.ts +1 -0
  19. package/dist/tests/cross-protocol.matrix.d.ts +1 -0
  20. package/dist/tests/cursor-sdk.auth-exchange-cache.d.ts +1 -0
  21. package/dist/tests/latency-cadence.d.ts +1 -0
  22. package/dist/tests/message-debug.d.ts +1 -0
  23. package/dist/tests/openrouter-headers.d.ts +1 -0
  24. package/dist/tests/proxy-dispatcher-cache.d.ts +1 -0
  25. package/dist/tests/responses.encrypted-content-cache.d.ts +1 -0
  26. package/dist/tests/sse-event-native.d.ts +1 -0
  27. package/dist/tests/tool-content.multimodal.d.ts +1 -0
  28. package/dist/tests/transformer-plan.d.ts +1 -0
  29. package/dist/tests/wire-keep.d.ts +1 -0
  30. package/dist/transformer/antigravity-auth.transformer.d.ts +2 -0
  31. package/dist/transformer/codex.transformer.d.ts +20 -44
  32. package/dist/transformer/cursor-sdk.transformer.d.ts +2 -0
  33. package/dist/transformer/openai.responses.transformer.d.ts +1 -1
  34. package/dist/transformer/openai.transformer.d.ts +2 -0
  35. package/dist/transformer/opencode-headers.transformer.d.ts +3 -0
  36. package/dist/transformer/openrouter.transformer.d.ts +15 -1
  37. package/dist/transformer/reasoning.transformer.d.ts +1 -0
  38. package/dist/types/llm.d.ts +11 -0
  39. package/dist/types/transformer.d.ts +10 -0
  40. package/dist/utils/cache-outcome.d.ts +79 -0
  41. package/dist/utils/cache-prefix-debug.d.ts +21 -1
  42. package/dist/utils/cacheControl.d.ts +8 -0
  43. package/dist/utils/deepseek.util.d.ts +1 -1
  44. package/dist/utils/message-debug.d.ts +45 -0
  45. package/dist/utils/nested-agent.d.ts +26 -0
  46. package/dist/utils/openai.responses.util.d.ts +21 -0
  47. package/dist/utils/paced-sse.d.ts +38 -0
  48. package/dist/utils/request-latency.d.ts +37 -0
  49. package/dist/utils/request.d.ts +8 -1
  50. package/dist/utils/responses.encrypted-content-cache.d.ts +42 -0
  51. package/dist/utils/sse/incremental-parser.d.ts +35 -0
  52. package/dist/utils/sse-debug-tap.d.ts +44 -2
  53. package/dist/utils/stream-peek.d.ts +20 -0
  54. package/dist/utils/stream.d.ts +26 -3
  55. package/dist/utils/token-count-worker.d.ts +12 -0
  56. package/dist/utils/tool-content.d.ts +54 -0
  57. package/dist/utils/transformer-plan.d.ts +30 -0
  58. package/dist/utils/vertex-claude.util.d.ts +1 -1
  59. package/package.json +4 -4
@@ -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
  /**
@@ -1,5 +1,6 @@
1
1
  import type { RouterScenarioType } from "../utils/router";
2
2
  import type { AnthropicClientKind, AnthropicProviderMode } from "../utils/anthropic-client-policy";
3
+ import type { ResponsesCallIdMap } from "../utils/openai.responses.util";
3
4
  /**
4
5
  * Inbound client protocols supported by CCR's gateway lifecycle.
5
6
  */
@@ -35,11 +36,24 @@ export interface ClientProtocolContext {
35
36
  anthropicPolicyApplied?: boolean;
36
37
  anthropicSystemTransformed?: boolean;
37
38
  claudeAuthToolNameMap?: Map<string, string>;
39
+ /** Per-request Responses call/result correlation across both pipeline legs. */
40
+ responsesCallIdMap?: ResponsesCallIdMap;
41
+ responsesCustomToolNames?: Set<string>;
38
42
  /** Claude Code routing metadata extracted without mutating the source billing block. */
39
43
  claudeCodeSubagent?: boolean;
44
+ /**
45
+ * Nested/worker agent on any inbound protocol (Claude Code Task, OpenCode
46
+ * child session, Codex x-openai-subagent, Cursor fork boilerplate).
47
+ */
48
+ nestedAgent?: boolean;
40
49
  taggedSubagentModel?: string;
41
50
  /** Transformer that owns this client protocol */
42
51
  ownerTransformerName: string;
52
+ /**
53
+ * Client conversation id captured from the original wire (never harness
54
+ * version or system text). Used for prompt-cache affinity and Codex headers.
55
+ */
56
+ sessionId?: string;
43
57
  }
44
58
  export interface ProtocolRouteMatch {
45
59
  protocol: ClientProtocol;
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 {};
@@ -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;
@@ -1,61 +1,37 @@
1
- import { UnifiedChatRequest } from "../types/llm";
2
1
  import { Transformer } from "../types/transformer";
2
+ /**
3
+ * ChatGPT/Codex backend auth + Responses-wire constraints.
4
+ *
5
+ * Body conversion is owned by `openai-responses`. Configure
6
+ * `transformer.use: ["openai-responses", "codex"]`. Same-protocol
7
+ * Responses clients keep `input[]` (including `reasoning.encrypted_content`);
8
+ * this transformer only stamps auth, Codex headers, `store: false`, and
9
+ * `stream: true`.
10
+ */
3
11
  export declare class CodexTransformer implements Transformer {
4
12
  name: string;
13
+ requestPhase: "headers";
5
14
  logger?: any;
6
15
  private streamIntent;
7
- transformRequestIn(request: UnifiedChatRequest, provider: any, context?: any): Promise<Record<string, any>>;
16
+ transformRequestIn(request: any, provider: any, context?: any): Promise<Record<string, any>>;
8
17
  auth(request: any, provider: any): Promise<any>;
9
18
  private resolveAuth;
10
19
  private buildAuthHeaders;
11
20
  private recoverUnauthorizedAuth;
12
21
  private resolvePatAuth;
13
22
  private requestPatAuth;
23
+ /**
24
+ * Transport quirks only. Do not convert Responses → Chat — openai-responses
25
+ * owns that, and same-protocol keep must forward native `input[]` /
26
+ * `encrypted_content` events unchanged.
27
+ */
14
28
  transformResponseOut(response: Response, context?: {
15
29
  req?: {
16
30
  id?: string;
17
31
  };
18
32
  }): Promise<Response>;
19
- private transformResponseOutInner;
20
- private convertStreamEvent;
21
- /**
22
- * Consume a Codex SSE response fully and return a single OpenAI
23
- * ChatCompletion JSON. Used for non-streaming Anthropic SDK calls
24
- * (e.g. client.beta.messages.create with stream:false) where the
25
- * SDK expects a flat BetaMessage. The SDK accumulates the response
26
- * by reading a single JSON object, not by parsing SSE, so we
27
- * have to materialize the response here.
28
- */
29
- /**
30
- * Re-emit a single OpenAI ChatCompletion JSON as a one-shot SSE stream of
31
- * `chat.completion.chunk` events, so a streaming caller (which expects SSE)
32
- * still receives the content when codex returned a flat JSON instead of a
33
- * stream. The downstream anthropic transformer's stream reader parses each
34
- * `data:` line as a chunk, so we split the full message into proper delta
35
- * chunks (text content first, then a final chunk with finish_reason + usage)
36
- * — emitting the raw chat.completion would put the text under `message`
37
- * instead of `delta` and the content would be dropped.
38
- */
39
- private jsonToSseStream;
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.
55
- */
56
- private readBodyAndPeek;
57
- private collectSseIntoChatCompletion;
58
- private normalizeRequestContent;
59
- private convertResponseToChat;
60
- private buildImageContent;
33
+ private normalizeCodexTransport;
34
+ private ensureSseContentType;
35
+ private jsonToSseBytes;
36
+ private collectSseIntoResponses;
61
37
  }
@@ -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);
@@ -16,7 +16,7 @@ export declare class OpenAIResponsesTransformer implements Transformer {
16
16
  transformResponseIn(response: Response, context?: TransformerContext): Promise<Response>;
17
17
  private convertUnifiedStreamToResponses;
18
18
  transformRequestIn(request: UnifiedChatRequest, provider?: any, context?: any): Promise<UnifiedChatRequest>;
19
- transformResponseOut(response: Response): Promise<Response>;
19
+ transformResponseOut(response: Response, context?: TransformerContext): Promise<Response>;
20
20
  /**
21
21
  * Convert one Responses stream event to a Chat chunk. `choices[0].index` is
22
22
  * always 0 — parallel-call identity lives in `delta.tool_calls[n].index`,
@@ -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;
@@ -30,6 +32,7 @@ export declare class OpencodeHeadersTransformer implements Transformer {
30
32
  private retryDelayMs;
31
33
  private exponentialRetryDelayMs;
32
34
  private retryAfterHeaders;
35
+ private ensurePromptCacheKey;
33
36
  private fingerprintConversation;
34
37
  private getOrCreateSessionId;
35
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>;
@@ -138,6 +138,17 @@ export interface UnifiedChatRequest {
138
138
  anthropic_metadata?: Record<string, any>;
139
139
  anthropic_stop_sequences?: string[];
140
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;
141
152
  }
142
153
  export interface UnifiedChatResponse {
143
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,79 @@
1
+ import type { CachePrefixDiff } from "./cache-prefix-debug";
2
+ /**
3
+ * Provider-family-specific cache contracts. OpenAI-style message prefix +
4
+ * prompt_cache_key is only one of several; Cursor uses conversation/lifecycle,
5
+ * Anthropic uses ephemeral breakpoints, Gemini uses cachedContent resources.
6
+ */
7
+ export type CacheFamily = "openai_prefix" | "anthropic_ephemeral" | "gemini_cached_content" | "cursor_conversation" | "deepseek_prefix" | "unknown";
8
+ export type CacheVerdict = "cold" | "warm-start" | "hit" | "partial" | "expected-miss" | "unexpected-miss" | "unknown";
9
+ export type CachePrediction = {
10
+ family: CacheFamily;
11
+ firstTurn: boolean;
12
+ /** Provider-specific: was a hit expected this turn? */
13
+ predictedHit: boolean;
14
+ /** Why we predicted miss/hit (for logs). */
15
+ reason: string;
16
+ /** OpenAI-style prefix intactness when available (diagnostic for Cursor). */
17
+ prefixIntact?: boolean;
18
+ firstDivergencePath?: string;
19
+ approxPrefixTokensLost?: number;
20
+ conversationId?: string;
21
+ conversationIdSource?: string;
22
+ /** Cursor lifecycle action when family is cursor_conversation. */
23
+ lifecycleAction?: string;
24
+ hostPrefixIntact?: boolean;
25
+ };
26
+ export type CursorCacheLifecycle = {
27
+ sessionKey?: string;
28
+ action: string;
29
+ reason?: string;
30
+ };
31
+ export type ResolveCacheFamilyInput = {
32
+ provider?: string;
33
+ model?: string;
34
+ body?: Record<string, any> | null;
35
+ cursorLifecycle?: CursorCacheLifecycle | null;
36
+ };
37
+ /**
38
+ * Prefer explicit provider/transformer id; fall back to body sniffing.
39
+ */
40
+ export declare function resolveCacheFamily(input: ResolveCacheFamilyInput): CacheFamily;
41
+ /**
42
+ * Join what we predicted against what upstream reported.
43
+ * Labels intentionally match the historical sse-debug-tap strings.
44
+ */
45
+ export declare function classifyCacheOutcome(prediction: CachePrediction | null | undefined, hitRatio: number | undefined): CacheVerdict;
46
+ /** OpenAI Chat/Responses, Codex, Zen, Cerebras, OpenRouter, Mistral, xAI. */
47
+ export declare function predictOpenAiPrefix(diff: CachePrefixDiff | null | undefined): CachePrediction;
48
+ /** DeepSeek uses the same outbound prefix contract; hit tokens are separate. */
49
+ export declare function predictDeepSeekPrefix(diff: CachePrefixDiff | null | undefined): CachePrediction;
50
+ /**
51
+ * Anthropic caches only when ephemeral breakpoints exist and the covered
52
+ * prefix stayed intact. No breakpoints → predicted miss.
53
+ */
54
+ export declare function predictAnthropicEphemeral(diff: CachePrefixDiff | null | undefined, body?: Record<string, any> | null): CachePrediction;
55
+ export declare function __resetGeminiCachedContentNamesForTests(): void;
56
+ export declare function predictGeminiCachedContent(opts: {
57
+ diff?: CachePrefixDiff | null;
58
+ body?: Record<string, any> | null;
59
+ conversationId?: string;
60
+ }): CachePrediction;
61
+ /**
62
+ * Cursor has no prompt_cache_key. Prediction follows lifecycle:
63
+ * resume/incremental → hit expected; retire/replay or fresh send → miss expected.
64
+ */
65
+ export declare function predictCursorConversation(opts: {
66
+ lifecycle?: CursorCacheLifecycle | null;
67
+ diff?: CachePrefixDiff | null;
68
+ }): CachePrediction;
69
+ /**
70
+ * Build the right prediction for this outbound leg.
71
+ */
72
+ export declare function buildCachePrediction(opts: {
73
+ provider?: string;
74
+ model?: string;
75
+ body?: Record<string, any> | null;
76
+ diff?: CachePrefixDiff | null;
77
+ cursorLifecycle?: CursorCacheLifecycle | null;
78
+ conversationId?: string;
79
+ }): CachePrediction;
@@ -35,7 +35,9 @@ export type CachePrefixSnapshot = {
35
35
  segments: CachePrefixSegment[];
36
36
  };
37
37
  export type CachePrefixChange = "none" | "appended" | "modified" | "removed";
38
- export type CachePrefixIdSource = "session" | "cache_key" | "fingerprint";
38
+ export type CachePrefixIdSource = "session" | "cache_key" | "fingerprint"
39
+ /** Parent session id mixed with first substantive user text (Claude Code Task). */
40
+ | "subagent";
39
41
  export type CachePrefixDiff = {
40
42
  conversationId: string;
41
43
  conversationIdSource: CachePrefixIdSource;
@@ -91,6 +93,8 @@ export type CachePrefixDiffOptions = {
91
93
  * become the baseline the following turn is judged against.
92
94
  */
93
95
  commit?: boolean;
96
+ /** Override when `conversationId` is a derived subagent key rather than the raw session. */
97
+ conversationIdSource?: CachePrefixIdSource;
94
98
  };
95
99
  export declare function __resetCachePrefixSnapshotsForTests(): void;
96
100
  /**
@@ -102,6 +106,22 @@ export declare function diffCachePrefixSnapshots(conversationId: string, previou
102
106
  stage?: CachePrefixStage;
103
107
  conversationIdSource?: CachePrefixIdSource;
104
108
  }): CachePrefixDiff;
109
+ /**
110
+ * Snapshot key for consecutive cache-prefix diffs.
111
+ *
112
+ * Claude Code Tasks share the parent `session_id`. Mixing first substantive
113
+ * user text keeps parent vs fork (and two forks) from overwriting one baseline
114
+ * and reporting 25k-token "modified" misses.
115
+ */
116
+ export declare function resolveCachePrefixConversationId(opts: {
117
+ sessionId?: string;
118
+ isSubagent?: boolean;
119
+ nestedAgent?: boolean;
120
+ firstUserText?: string;
121
+ }): {
122
+ id?: string;
123
+ source?: CachePrefixIdSource;
124
+ };
105
125
  /**
106
126
  * Compare this outbound body to the last one for the conversation, then
107
127
  * remember the current snapshot. Returns null when there is nothing cacheable.
@@ -28,6 +28,14 @@ export declare function stripMessagesCacheControl(messages: UnifiedMessage[]): U
28
28
  * but non-Anthropic providers reject it on tool definitions.
29
29
  */
30
30
  export declare function stripToolsCacheControl(tools: UnifiedTool[] | undefined): UnifiedTool[] | undefined;
31
+ /**
32
+ * Conversation id from the client wire. Never uses harness version, billing
33
+ * markers, or system-prompt text.
34
+ */
35
+ export declare function extractClientSessionId(input: {
36
+ body?: any;
37
+ headers?: unknown;
38
+ }): string | undefined;
31
39
  export declare function deriveCacheSessionKey(context: any, request: UnifiedChatRequest): string | undefined;
32
40
  export declare function selectCacheBreakpoints(request: UnifiedChatRequest, options: {
33
41
  maxBreakpoints: number;
@@ -11,7 +11,7 @@ type AssistantResponseRecorder = {
11
11
  };
12
12
  export declare function assistantNeedsReasoningForToolContext(message: MessageLike, priorMessages: MessageLike[]): boolean;
13
13
  export declare function isDeepSeekThinkingRequest(request: Pick<UnifiedChatRequest, "model" | "thinking" | "enable_thinking" | "reasoning">, provider?: Pick<LLMProvider, "name" | "baseUrl">): boolean;
14
- export declare function buildReasoningCacheNamespace(request: Pick<UnifiedChatRequest, "model" | "thinking" | "enable_thinking" | "reasoning">, provider?: Pick<LLMProvider, "name" | "baseUrl">): string;
14
+ export declare function buildReasoningCacheNamespace(request: Pick<UnifiedChatRequest, "model" | "thinking" | "enable_thinking" | "reasoning">, provider?: Pick<LLMProvider, "name" | "baseUrl">, context?: TransformerContext): string;
15
15
  export declare function prepareReasoningReplay(request: UnifiedChatRequest, provider: Pick<LLMProvider, "name" | "baseUrl"> | undefined, context?: TransformerContext): {
16
16
  restoredFromCache: number;
17
17
  restoredFromThinking: number;
@@ -0,0 +1,45 @@
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
+ * Compact keep-wire snapshot for debug logs. Full transcripts stay behind
33
+ * LOG_REQUEST_BODY; this is how keep (Responses/Chat) shows encrypted
34
+ * replay on `ccr→provider` without a 200k-token dump.
35
+ */
36
+ export declare function summarizeKeepWire(body: unknown): Record<string, unknown>;
37
+ export declare function logKeepWire(body: unknown, opts: {
38
+ logger?: {
39
+ debug?: (...args: any[]) => void;
40
+ };
41
+ reqId?: string | number;
42
+ provider?: string;
43
+ model?: string;
44
+ }): void;
45
+ export declare function logMessageBody(body: unknown, opts: MessageBodyLogOptions): void;
@@ -0,0 +1,26 @@
1
+ /** First user-turn text only — never system (billing / harness version). */
2
+ export declare function firstUserText(request: unknown): string;
3
+ export declare function isHarnessUserNoise(text: string): boolean;
4
+ export declare function userMessageTextParts(content: unknown): string[];
5
+ /**
6
+ * First user text that distinguishes a worker transcript.
7
+ * Shared reminder/caveat preambles are skipped so parallel Tasks do not collide.
8
+ */
9
+ export declare function firstSubstantiveUserText(request: unknown): string;
10
+ /** Statusline / spinner polls — must not supersede or become a cache baseline. */
11
+ export declare function isStatuslinePollTurn(request: unknown): boolean;
12
+ /**
13
+ * Nested/worker agent on any inbound protocol.
14
+ *
15
+ * Claude Code: `cc_is_subagent`.
16
+ * OpenCode / Kilocode / MiMo: child session + `x-parent-session-id`.
17
+ * Kilocode gateway: `X-KILOCODE-PARENT-TASKID`.
18
+ * Codex: `x-openai-subagent`.
19
+ * Cursor/Claude forks: `<fork-boilerplate>` / worker-fork opening text.
20
+ * Grok CLI: child `x-grok-session-id` (unique) plus opening-text mix.
21
+ */
22
+ export declare function detectNestedAgent(input: {
23
+ headers?: unknown;
24
+ body?: unknown;
25
+ claudeCodeSubagent?: boolean;
26
+ }): boolean;
@@ -7,11 +7,24 @@ export interface ResponsesCallIdMap {
7
7
  export declare function createCallIdMap(): ResponsesCallIdMap;
8
8
  /** Sanitize and remember a stable per-turn mapping for function call correlation. */
9
9
  export declare function mapCallId(map: ResponsesCallIdMap, id: unknown, direction?: "client_to_unified" | "unified_to_client"): string | undefined;
10
+ /**
11
+ * Enforce the Responses call_id contract without rebuilding an exact-wire body.
12
+ *
13
+ * Same-protocol wire keep deliberately skips the Responses owner's full
14
+ * transformRequestIn so images/files/reasoning/cache fields remain byte-faithful.
15
+ * Call ids are still a provider validation boundary, though: Cursor-style
16
+ * composite ids can exceed 64 characters. Rewrite only the identity field on
17
+ * call/output items and reuse the normalization map so paired items and hash
18
+ * collisions resolve identically in both directions.
19
+ */
20
+ export declare function sanitizeResponsesWireCallIds(body: any, callIdMap?: ResponsesCallIdMap): any;
10
21
  /**
11
22
  * Client Responses wire → Unified (Chat Completions shape).
12
23
  * Supports the Responses MVP subset; rejects CCR-unsupported stateful fields.
13
24
  */
14
25
  export declare function responsesRequestToUnified(body: any, callIdMap?: ResponsesCallIdMap, customToolNames?: Set<string>): UnifiedChatRequest;
26
+ /** Responses `include` is a string list; drop non-strings rather than invent values. */
27
+ export declare function normalizeResponsesInclude(include: unknown): string[] | undefined;
15
28
  export declare function isResponsesReasoningItemId(value: unknown): value is string;
16
29
  /**
17
30
  * Ciphertext Codex/OpenAI will verify. Item ids and Anthropic/Gemini
@@ -82,6 +95,11 @@ export declare function responsesReasoningItemFromThinking(thinking: {
82
95
  encrypted_content?: string;
83
96
  id?: string;
84
97
  } | undefined, id?: string): any | null;
98
+ /**
99
+ * Zen rejects Requests whose `input` repeats the same reasoning item id.
100
+ * Rewrite placeholders / collisions using ciphertext (or summary) as seed.
101
+ */
102
+ export declare function uniquifyReasoningItemIds(items: any[] | undefined): void;
85
103
  /** Synthetic argument key used to carry a `custom` tool's freeform text
86
104
  * through the Unified/Chat Completions function-call shape. */
87
105
  export declare const CUSTOM_TOOL_INPUT_KEY = "input";
@@ -192,6 +210,9 @@ export interface ResponsesStreamState {
192
210
  thinkingContent: string;
193
211
  thinkingEncryptedContent?: string;
194
212
  thinkingId?: string;
213
+ thinkingStarted: boolean;
214
+ thinkingClosed: boolean;
215
+ thinkingOutputIndex?: number;
195
216
  codexIsolateConventions: boolean;
196
217
  }
197
218
  export declare function createResponsesStreamState(options?: {