@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.
- package/README.md +4 -2
- package/dist/cjs/server.cjs +287 -227
- package/dist/cjs/server.cjs.map +4 -4
- package/dist/cursor-sdk/auth-exchange-cache.d.ts +23 -0
- package/dist/cursor-sdk/lifecycle-planner.d.ts +16 -4
- package/dist/cursor-sdk/prompt.d.ts +10 -0
- package/dist/cursor-sdk/session.d.ts +23 -0
- package/dist/cursor-sdk/turn-output.d.ts +3 -0
- package/dist/cursor-sdk/usage.d.ts +17 -0
- package/dist/esm/server.mjs +287 -227
- package/dist/esm/server.mjs.map +4 -4
- package/dist/routing/inbound-pipeline.d.ts +6 -2
- package/dist/routing/protocol-adapter.d.ts +2 -0
- package/dist/routing/protocol-endpoints.d.ts +14 -0
- package/dist/server.d.ts +4 -0
- package/dist/tests/anthropic.message-start-usage.test.d.ts +1 -0
- package/dist/tests/cache-outcome.d.ts +1 -0
- package/dist/tests/codex-system-instructions.d.ts +1 -0
- package/dist/tests/cross-protocol.matrix.d.ts +1 -0
- package/dist/tests/cursor-sdk.auth-exchange-cache.d.ts +1 -0
- package/dist/tests/latency-cadence.d.ts +1 -0
- package/dist/tests/message-debug.d.ts +1 -0
- package/dist/tests/openrouter-headers.d.ts +1 -0
- package/dist/tests/proxy-dispatcher-cache.d.ts +1 -0
- package/dist/tests/responses.encrypted-content-cache.d.ts +1 -0
- package/dist/tests/sse-event-native.d.ts +1 -0
- package/dist/tests/tool-content.multimodal.d.ts +1 -0
- package/dist/tests/transformer-plan.d.ts +1 -0
- package/dist/tests/wire-keep.d.ts +1 -0
- package/dist/transformer/antigravity-auth.transformer.d.ts +2 -0
- package/dist/transformer/codex.transformer.d.ts +20 -44
- package/dist/transformer/cursor-sdk.transformer.d.ts +2 -0
- package/dist/transformer/openai.responses.transformer.d.ts +1 -1
- package/dist/transformer/openai.transformer.d.ts +2 -0
- package/dist/transformer/opencode-headers.transformer.d.ts +3 -0
- package/dist/transformer/openrouter.transformer.d.ts +15 -1
- package/dist/transformer/reasoning.transformer.d.ts +1 -0
- package/dist/types/llm.d.ts +11 -0
- package/dist/types/transformer.d.ts +10 -0
- package/dist/utils/cache-outcome.d.ts +79 -0
- package/dist/utils/cache-prefix-debug.d.ts +21 -1
- package/dist/utils/cacheControl.d.ts +8 -0
- package/dist/utils/deepseek.util.d.ts +1 -1
- package/dist/utils/message-debug.d.ts +45 -0
- package/dist/utils/nested-agent.d.ts +26 -0
- package/dist/utils/openai.responses.util.d.ts +21 -0
- package/dist/utils/paced-sse.d.ts +38 -0
- package/dist/utils/request-latency.d.ts +37 -0
- package/dist/utils/request.d.ts +8 -1
- package/dist/utils/responses.encrypted-content-cache.d.ts +42 -0
- package/dist/utils/sse/incremental-parser.d.ts +35 -0
- package/dist/utils/sse-debug-tap.d.ts +44 -2
- package/dist/utils/stream-peek.d.ts +20 -0
- package/dist/utils/stream.d.ts +26 -3
- package/dist/utils/token-count-worker.d.ts +12 -0
- package/dist/utils/tool-content.d.ts +54 -0
- package/dist/utils/transformer-plan.d.ts +30 -0
- package/dist/utils/vertex-claude.util.d.ts +1 -1
- package/package.json +4 -4
|
@@ -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[];
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
method?: string;
|
|
14
|
+
url?: string;
|
|
15
|
+
scenario?: string;
|
|
16
|
+
bypass?: boolean;
|
|
17
|
+
wireKeep?: boolean;
|
|
18
|
+
tokenCount?: number;
|
|
19
|
+
tokenCountSource?: "exact" | "estimate" | "skipped";
|
|
20
|
+
inputBytes?: number;
|
|
21
|
+
upstreamAttempts?: number;
|
|
22
|
+
cancelled?: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
};
|
|
25
|
+
emitted?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare function createRequestLatency(): RequestLatency;
|
|
28
|
+
export declare function markLatency(latency: RequestLatency | undefined | null, stage: LatencyStage): void;
|
|
29
|
+
export declare function tapResponseFirstByte(response: Response, onFirstByte: () => void): Response;
|
|
30
|
+
export declare function attachLatencyMeta(latency: RequestLatency | undefined | null, meta: Partial<RequestLatency["meta"]>): void;
|
|
31
|
+
/** Emit one structured terminal latency record. Safe to call multiple times. */
|
|
32
|
+
export declare function emitLatencyRecord(logger: {
|
|
33
|
+
info?: (obj: unknown, msg?: string) => void;
|
|
34
|
+
} | undefined | null, latency: RequestLatency | undefined | null): void;
|
|
35
|
+
export declare function ensureRequestLatency(req: {
|
|
36
|
+
_latency?: RequestLatency;
|
|
37
|
+
}): RequestLatency;
|
package/dist/utils/request.d.ts
CHANGED
|
@@ -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,
|
|
11
|
+
export declare function sendUnifiedRequest(url: URL | string, request: UnifiedChatRequest, config: any, context: any, _logger?: any): Promise<Response>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { LLMProvider, UnifiedChatRequest, UnifiedMessage } from "../types/llm";
|
|
2
|
+
import { TransformerContext } from "../types/transformer";
|
|
3
|
+
type MessageLike = Pick<UnifiedMessage, "role" | "content" | "thinking" | "tool_calls" | "tool_call_id" | "reasoning_content"> & {
|
|
4
|
+
name?: string;
|
|
5
|
+
};
|
|
6
|
+
export type EncryptedReasoningPayload = {
|
|
7
|
+
encrypted_content: string;
|
|
8
|
+
content?: string;
|
|
9
|
+
id?: string;
|
|
10
|
+
};
|
|
11
|
+
export type EncryptedReasoningStreamRecorder = {
|
|
12
|
+
observe(event: any): void;
|
|
13
|
+
completedOutput(): any[] | undefined;
|
|
14
|
+
discard(): void;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Accumulate only the opaque reasoning/tool state needed for replay. Some
|
|
18
|
+
* Responses-compatible hosts omit full output from response.completed, so the
|
|
19
|
+
* cache cannot depend on that one event. Bounds make malformed streams fail
|
|
20
|
+
* closed (no cache write) without affecting client-visible stream conversion.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createEncryptedReasoningStreamRecorder(): EncryptedReasoningStreamRecorder;
|
|
23
|
+
export declare function isCrossProtocolResponsesClient(context?: TransformerContext): boolean;
|
|
24
|
+
export declare function buildEncryptedReasoningCacheNamespace(request: Pick<UnifiedChatRequest, "model" | "thinking" | "reasoning">, provider?: Pick<LLMProvider, "name" | "baseUrl">, context?: TransformerContext): string;
|
|
25
|
+
/**
|
|
26
|
+
* Anthropic/Chat clients cannot round-trip Responses `encrypted_content`.
|
|
27
|
+
* For those inbound protocols, request ciphertext from the destination and
|
|
28
|
+
* restore it onto assistant tool turns from a local cache keyed like DeepSeek's
|
|
29
|
+
* reasoning replay cache.
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareEncryptedReasoningReplay(request: UnifiedChatRequest, provider: Pick<LLMProvider, "name" | "baseUrl"> | undefined, context?: TransformerContext): {
|
|
32
|
+
restoredFromCache: number;
|
|
33
|
+
includeRequested: boolean;
|
|
34
|
+
};
|
|
35
|
+
export declare function hasEncryptedReasoningContext(context?: TransformerContext): boolean;
|
|
36
|
+
export declare function recordEncryptedReasoningResponseMessage(message: MessageLike | null | undefined, context?: TransformerContext): number;
|
|
37
|
+
/**
|
|
38
|
+
* Build a cacheable assistant message from a Responses `output` array.
|
|
39
|
+
* Ciphertext often arrives only on the terminal reasoning item.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assistantMessageFromResponsesOutput(output: any[] | undefined): MessageLike | null;
|
|
42
|
+
export {};
|
|
@@ -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,6 @@
|
|
|
1
|
-
import { type CacheAffinityHeaders, type CachePrefixDiff, type CachePrefixStage } from "./cache-prefix-debug";
|
|
1
|
+
import { type CacheAffinityHeaders, type CachePrefixDiff, type CachePrefixIdSource, type CachePrefixStage } from "./cache-prefix-debug";
|
|
2
|
+
import { type CachePrediction, type CursorCacheLifecycle } from "./cache-outcome";
|
|
3
|
+
import type { MessageDebugDirection } from "./message-debug";
|
|
2
4
|
export type UpstreamSSEDebugOptions = {
|
|
3
5
|
logger?: any;
|
|
4
6
|
reqId?: string | number;
|
|
@@ -7,6 +9,9 @@ export type UpstreamSSEDebugOptions = {
|
|
|
7
9
|
model?: string;
|
|
8
10
|
/** Conversation / Claude session id used to pair consecutive cache snapshots. */
|
|
9
11
|
conversationId?: string;
|
|
12
|
+
conversationIdSource?: CachePrefixIdSource;
|
|
13
|
+
/** When false, diff against the last baseline but do not replace it. */
|
|
14
|
+
commitCachePrefix?: boolean;
|
|
10
15
|
/** Pipeline position this body was captured at. Defaults to `wire`. */
|
|
11
16
|
stage?: CachePrefixStage;
|
|
12
17
|
/** Codex (and similar) routing headers that pin prompt-cache affinity. */
|
|
@@ -17,14 +22,45 @@ export type UpstreamSSEDebugOptions = {
|
|
|
17
22
|
clientStageDiff?: CachePrefixDiff | null;
|
|
18
23
|
/** Outbound diff for this request, joined with the observed cache usage. */
|
|
19
24
|
cacheDiff?: CachePrefixDiff | null;
|
|
25
|
+
/** Outbound body used to resolve Anthropic/Gemini family signals. */
|
|
26
|
+
outboundBody?: Record<string, any> | null;
|
|
27
|
+
/** Precomputed prediction; built from cacheDiff + family when absent. */
|
|
28
|
+
cachePrediction?: CachePrediction | null;
|
|
29
|
+
/** Cursor lifecycle plan for conversation-cache prediction. */
|
|
30
|
+
cursorLifecycle?: CursorCacheLifecycle | null;
|
|
20
31
|
/** Cap for a single logged payload string (raw `data` field). */
|
|
21
32
|
maxBytes?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Opt-in raw per-event SSE logging. Independent of LOG_LEVEL=debug.
|
|
35
|
+
* When false (default), the debug tap still computes terminal cache outcome
|
|
36
|
+
* summaries but does not log every delta.
|
|
37
|
+
*/
|
|
38
|
+
rawEvents?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Which wire leg produced these bytes. Defaults to `provider→ccr` for the
|
|
41
|
+
* upstream tap and `ccr→client` for the client tap.
|
|
42
|
+
*/
|
|
43
|
+
direction?: MessageDebugDirection;
|
|
44
|
+
/**
|
|
45
|
+
* When true, only emit raw SSE/JSON event logs (no cache outcome summary).
|
|
46
|
+
* Used for the client-bound leg where cache usage was already observed upstream.
|
|
47
|
+
*/
|
|
48
|
+
eventsOnly?: boolean;
|
|
49
|
+
};
|
|
50
|
+
export type ClientSSEDebugOptions = {
|
|
51
|
+
logger?: any;
|
|
52
|
+
reqId?: string | number;
|
|
53
|
+
provider?: string;
|
|
54
|
+
model?: string;
|
|
55
|
+
protocol?: string;
|
|
56
|
+
maxBytes?: number;
|
|
57
|
+
rawEvents?: boolean;
|
|
22
58
|
};
|
|
23
59
|
/**
|
|
24
60
|
* Byte-preserving upstream response debug tap.
|
|
25
61
|
*
|
|
26
62
|
* For SSE: mirrors bytes to a background consumer that emits Codex-parity
|
|
27
|
-
* `
|
|
63
|
+
* `received data` / `Original Response` logs (including Anthropic usage /
|
|
28
64
|
* cache fields on message_start / message_delta).
|
|
29
65
|
*
|
|
30
66
|
* Important: do **not** use `ReadableStream.tee()` here. Tee couples
|
|
@@ -42,6 +78,12 @@ export type UpstreamSSEDebugOptions = {
|
|
|
42
78
|
* the single shared place that covers every outbound provider.
|
|
43
79
|
*/
|
|
44
80
|
export declare function tapUpstreamSSEDebug(response: Response, opts: UpstreamSSEDebugOptions): Promise<Response>;
|
|
81
|
+
/**
|
|
82
|
+
* Byte-preserving tap for the SSE body CCR sends back to the client after
|
|
83
|
+
* response transformers. Same non-blocking tunnel as the upstream tap; events
|
|
84
|
+
* are tagged `direction: "ccr→client"` so greps can split the two legs.
|
|
85
|
+
*/
|
|
86
|
+
export declare function tapClientSSEDebug(body: ReadableStream<Uint8Array>, opts: ClientSSEDebugOptions): ReadableStream<Uint8Array>;
|
|
45
87
|
export type CacheStructureSummary = {
|
|
46
88
|
systemBreakpoints: number;
|
|
47
89
|
messageBreakpoints: number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sniff a response body as JSON vs SSE without Response.clone().
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare (Codex) often strips Content-Type from SSE. The first
|
|
5
|
+
* non-whitespace byte is `{`/`[` for a JSON object/array and anything
|
|
6
|
+
* else (typically `d` from `data:`) for SSE. JSON drains into text;
|
|
7
|
+
* SSE returns a new Response that replays the peeked chunk then
|
|
8
|
+
* continues from the same reader.
|
|
9
|
+
*/
|
|
10
|
+
export type PeekedResponseBody = {
|
|
11
|
+
kind: "json";
|
|
12
|
+
firstChar: string;
|
|
13
|
+
text: string;
|
|
14
|
+
} | {
|
|
15
|
+
kind: "sse";
|
|
16
|
+
response: Response;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "empty";
|
|
19
|
+
};
|
|
20
|
+
export declare function peekResponseBody(response: Response): Promise<PeekedResponseBody>;
|
package/dist/utils/stream.d.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multimodal tool-result helpers.
|
|
3
|
+
*
|
|
4
|
+
* Responses / OpenCode attach images (and files) on function_call_output as
|
|
5
|
+
* structured parts. Unified carries them as text / image_url / file parts on
|
|
6
|
+
* role:"tool". Destinations differ:
|
|
7
|
+
* - Responses/Codex: re-emit input_image / input_file in output[]
|
|
8
|
+
* - Anthropic: image / document blocks inside tool_result.content
|
|
9
|
+
* - Gemini: text in functionResponse + sibling inlineData parts
|
|
10
|
+
* - Chat Completions / Mistral: string tool content only — extract media
|
|
11
|
+
* into a follow-up user message (OpenCode's pattern for non-supporting APIs)
|
|
12
|
+
*/
|
|
13
|
+
export type UnifiedToolPart = {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
cache_control?: any;
|
|
17
|
+
} | {
|
|
18
|
+
type: "image_url";
|
|
19
|
+
image_url: {
|
|
20
|
+
url: string;
|
|
21
|
+
detail?: string;
|
|
22
|
+
};
|
|
23
|
+
media_type?: string;
|
|
24
|
+
cache_control?: any;
|
|
25
|
+
} | {
|
|
26
|
+
type: "file";
|
|
27
|
+
filename?: string;
|
|
28
|
+
file_data?: string;
|
|
29
|
+
file_url?: string;
|
|
30
|
+
media_type?: string;
|
|
31
|
+
cache_control?: any;
|
|
32
|
+
};
|
|
33
|
+
export declare function isUnifiedToolMediaPart(part: any): part is Extract<UnifiedToolPart, {
|
|
34
|
+
type: "image_url" | "file";
|
|
35
|
+
}>;
|
|
36
|
+
/** Normalize string | part[] tool content into a part list. */
|
|
37
|
+
export declare function normalizeUnifiedToolParts(content: unknown): UnifiedToolPart[];
|
|
38
|
+
export declare function unifiedToolTextOnly(content: unknown): string;
|
|
39
|
+
export declare function unifiedToolHasMedia(content: unknown): boolean;
|
|
40
|
+
/** Anthropic tool_result.content: string or (text|image|document)[]. */
|
|
41
|
+
export declare function unifiedToolContentToAnthropic(content: unknown): string | any[];
|
|
42
|
+
/**
|
|
43
|
+
* Anthropic inbound tool_result.content → Unified tool content
|
|
44
|
+
* (string or text/image_url/file parts).
|
|
45
|
+
*/
|
|
46
|
+
export declare function anthropicToolResultToUnified(content: unknown): string | any[];
|
|
47
|
+
/** Gemini sibling inlineData / fileData parts for tool media. */
|
|
48
|
+
export declare function unifiedToolMediaToGeminiParts(content: unknown): any[];
|
|
49
|
+
/**
|
|
50
|
+
* Chat Completions / Mistral: string-only tool content. Pull media out of
|
|
51
|
+
* tool messages and insert a synthetic user message after each contiguous
|
|
52
|
+
* tool-result group so vision still reaches the model.
|
|
53
|
+
*/
|
|
54
|
+
export declare function extractToolMediaForStringToolApis(messages: any[]): any[];
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
export declare function isExactProtocolRequestPlan(plan: CompiledTransformerPlan, endpointTransformer: Transformer, clientProtocolOwnerName: string | undefined): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* v1 allowlist: middleware known to be safe on a kept native wire.
|
|
23
|
+
* `OpenAI` is handled separately — it always runs. `reasoning` is
|
|
24
|
+
* Chat-shaped and only allowed with an OpenAI owner. Everything else
|
|
25
|
+
* (Anthropic/Responses owners) does not run Unified-only middleware.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isWireSafeMiddlewareForKeep(name: string | undefined, ownerName: string | undefined): boolean;
|
|
28
|
+
export declare function planContains(plan: CompiledTransformerPlan, name: string): boolean;
|
|
29
|
+
/** Cancel a Response body when a newer transport result replaces it. */
|
|
30
|
+
export declare function cancelReplacedProviderResponse(previous: Response | undefined | null, next: Response | undefined | null): void;
|
|
@@ -2,7 +2,7 @@ import { UnifiedChatRequest } from "../types/llm";
|
|
|
2
2
|
interface ClaudeMessage {
|
|
3
3
|
role: "user" | "assistant";
|
|
4
4
|
content: Array<{
|
|
5
|
-
type: "text" | "image" | "tool_use" | "tool_result";
|
|
5
|
+
type: "text" | "image" | "document" | "tool_use" | "tool_result";
|
|
6
6
|
text?: string;
|
|
7
7
|
source?: {
|
|
8
8
|
type: "base64";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caeliq/llms",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.67",
|
|
4
4
|
"description": "A universal LLM API transformation server",
|
|
5
5
|
"main": "dist/cjs/server.cjs",
|
|
6
6
|
"module": "dist/esm/server.mjs",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@anthropic-ai/sdk": "^0.120.0",
|
|
33
|
-
"@caeliq/ccr-shared": "^2.1.
|
|
34
|
-
"@cursor/sdk": "^1.0.
|
|
33
|
+
"@caeliq/ccr-shared": "^2.1.9",
|
|
34
|
+
"@cursor/sdk": "^1.0.30",
|
|
35
35
|
"@fastify/cors": "^11.3.0",
|
|
36
36
|
"@fastify/rate-limit": "^11.2.0",
|
|
37
37
|
"@google/genai": "^2.18.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"uuid": "^14.0.2"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/node": "^26.
|
|
53
|
+
"@types/node": "^26.4.0",
|
|
54
54
|
"esbuild": "^0.28.2",
|
|
55
55
|
"tsx": "^4.23.12",
|
|
56
56
|
"typescript": "^6.0.3"
|