@combycode/llm-sdk 1.0.0-rc.0

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 (228) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +103 -0
  4. package/dist/agent/approval-types.d.ts +49 -0
  5. package/dist/agent/context-registry/layers.d.ts +39 -0
  6. package/dist/agent/context-registry/registry-internal.d.ts +14 -0
  7. package/dist/agent/context-registry/registry.d.ts +104 -0
  8. package/dist/agent/context-registry/types.d.ts +110 -0
  9. package/dist/agent/guardrail-types.d.ts +58 -0
  10. package/dist/agent/history-types.d.ts +40 -0
  11. package/dist/agent/history.d.ts +111 -0
  12. package/dist/agent/loop-config.d.ts +67 -0
  13. package/dist/agent/loop-internals.d.ts +46 -0
  14. package/dist/agent/loop-step-state.d.ts +20 -0
  15. package/dist/agent/loop.d.ts +133 -0
  16. package/dist/agent/tool-key.d.ts +3 -0
  17. package/dist/agent/types.d.ts +138 -0
  18. package/dist/bus/agent-bus.d.ts +99 -0
  19. package/dist/bus/async-context.browser.d.ts +13 -0
  20. package/dist/bus/async-context.d.ts +11 -0
  21. package/dist/bus/async-context.types.d.ts +14 -0
  22. package/dist/bus/hook-bus.d.ts +43 -0
  23. package/dist/bus/hook-map.d.ts +592 -0
  24. package/dist/helpers/agent.d.ts +32 -0
  25. package/dist/helpers/batch.d.ts +74 -0
  26. package/dist/helpers/calibration-store.d.ts +27 -0
  27. package/dist/helpers/calibration-types.d.ts +64 -0
  28. package/dist/helpers/chain.d.ts +30 -0
  29. package/dist/helpers/client-pool.d.ts +15 -0
  30. package/dist/helpers/client-resolver.d.ts +62 -0
  31. package/dist/helpers/collection.d.ts +19 -0
  32. package/dist/helpers/consolidate.d.ts +66 -0
  33. package/dist/helpers/content.d.ts +25 -0
  34. package/dist/helpers/conversation-export.d.ts +14 -0
  35. package/dist/helpers/conversation-zip.d.ts +28 -0
  36. package/dist/helpers/count-tokens.d.ts +26 -0
  37. package/dist/helpers/define-tool.d.ts +66 -0
  38. package/dist/helpers/delegate.d.ts +6 -0
  39. package/dist/helpers/embed.d.ts +24 -0
  40. package/dist/helpers/engine.d.ts +121 -0
  41. package/dist/helpers/estimate-types.d.ts +67 -0
  42. package/dist/helpers/estimate.d.ts +45 -0
  43. package/dist/helpers/estimator.d.ts +48 -0
  44. package/dist/helpers/handoff-types.d.ts +18 -0
  45. package/dist/helpers/handoff.d.ts +14 -0
  46. package/dist/helpers/llm.d.ts +24 -0
  47. package/dist/helpers/mcp.d.ts +82 -0
  48. package/dist/helpers/media.d.ts +58 -0
  49. package/dist/helpers/models.d.ts +36 -0
  50. package/dist/helpers/moderate-types.d.ts +73 -0
  51. package/dist/helpers/moderate.d.ts +13 -0
  52. package/dist/helpers/moderation-guardrail.d.ts +29 -0
  53. package/dist/helpers/observer.d.ts +36 -0
  54. package/dist/helpers/one-shot.d.ts +86 -0
  55. package/dist/helpers/parallel.d.ts +16 -0
  56. package/dist/helpers/realtime.d.ts +25 -0
  57. package/dist/helpers/route.d.ts +29 -0
  58. package/dist/helpers/select-model.d.ts +41 -0
  59. package/dist/helpers/server.d.ts +32 -0
  60. package/dist/helpers/transcribe.d.ts +36 -0
  61. package/dist/index.browser.js +38047 -0
  62. package/dist/index.d.ts +275 -0
  63. package/dist/index.js +37974 -0
  64. package/dist/llm/audio/voices.d.ts +7 -0
  65. package/dist/llm/client-config.d.ts +37 -0
  66. package/dist/llm/client-internal.d.ts +28 -0
  67. package/dist/llm/client.d.ts +68 -0
  68. package/dist/llm/providers/_shared/constants.d.ts +5 -0
  69. package/dist/llm/providers/_shared/response-utils.d.ts +8 -0
  70. package/dist/llm/providers/anthropic/batch.d.ts +19 -0
  71. package/dist/llm/providers/anthropic/constants.d.ts +13 -0
  72. package/dist/llm/providers/anthropic/files.d.ts +23 -0
  73. package/dist/llm/providers/anthropic/messages.d.ts +30 -0
  74. package/dist/llm/providers/google/batch.d.ts +20 -0
  75. package/dist/llm/providers/google/constants.d.ts +6 -0
  76. package/dist/llm/providers/google/embeddings.d.ts +15 -0
  77. package/dist/llm/providers/google/files.d.ts +22 -0
  78. package/dist/llm/providers/google/generate.d.ts +27 -0
  79. package/dist/llm/providers/google/interactions.d.ts +30 -0
  80. package/dist/llm/providers/google/media.d.ts +27 -0
  81. package/dist/llm/providers/google/realtime.d.ts +27 -0
  82. package/dist/llm/providers/openai/batch.d.ts +19 -0
  83. package/dist/llm/providers/openai/completions.d.ts +25 -0
  84. package/dist/llm/providers/openai/embeddings.d.ts +16 -0
  85. package/dist/llm/providers/openai/files.d.ts +23 -0
  86. package/dist/llm/providers/openai/media.d.ts +28 -0
  87. package/dist/llm/providers/openai/moderations.d.ts +19 -0
  88. package/dist/llm/providers/openai/realtime.d.ts +24 -0
  89. package/dist/llm/providers/openai/responses.d.ts +29 -0
  90. package/dist/llm/providers/openai/tiers.d.ts +13 -0
  91. package/dist/llm/providers/openai/transcription.d.ts +20 -0
  92. package/dist/llm/providers/openrouter/completions.d.ts +15 -0
  93. package/dist/llm/providers/openrouter/embeddings.d.ts +7 -0
  94. package/dist/llm/providers/openrouter/media.d.ts +25 -0
  95. package/dist/llm/providers/openrouter/responses.d.ts +17 -0
  96. package/dist/llm/providers/xai/batch.d.ts +19 -0
  97. package/dist/llm/providers/xai/completions.d.ts +24 -0
  98. package/dist/llm/providers/xai/files.d.ts +23 -0
  99. package/dist/llm/providers/xai/media.d.ts +27 -0
  100. package/dist/llm/providers/xai/responses.d.ts +20 -0
  101. package/dist/llm/realtime/session.d.ts +34 -0
  102. package/dist/llm/realtime/types.d.ts +66 -0
  103. package/dist/llm/server-state.d.ts +32 -0
  104. package/dist/llm/types/audio.d.ts +18 -0
  105. package/dist/llm/types/messages.d.ts +125 -0
  106. package/dist/llm/types/options.d.ts +51 -0
  107. package/dist/llm/types/provider.d.ts +39 -0
  108. package/dist/llm/types/request.d.ts +51 -0
  109. package/dist/llm/types/response.d.ts +36 -0
  110. package/dist/llm/types/schema-utils.d.ts +8 -0
  111. package/dist/llm/types/stream.d.ts +42 -0
  112. package/dist/llm/types/tiers.d.ts +11 -0
  113. package/dist/llm/types/tools.d.ts +20 -0
  114. package/dist/network/engine.d.ts +87 -0
  115. package/dist/network/errors.d.ts +14 -0
  116. package/dist/network/queue-state-config.d.ts +41 -0
  117. package/dist/network/queue-state.d.ts +45 -0
  118. package/dist/network/rate-limiter.d.ts +49 -0
  119. package/dist/network/realtime-connection.d.ts +40 -0
  120. package/dist/network/request-queue.d.ts +40 -0
  121. package/dist/network/semaphore.d.ts +12 -0
  122. package/dist/network/sse.d.ts +3 -0
  123. package/dist/network/types.d.ts +127 -0
  124. package/dist/plugins/batch/batcher.d.ts +45 -0
  125. package/dist/plugins/batch/strategy.d.ts +20 -0
  126. package/dist/plugins/batch/types.d.ts +54 -0
  127. package/dist/plugins/cache/cache.d.ts +50 -0
  128. package/dist/plugins/cache/file-store.d.ts +15 -0
  129. package/dist/plugins/cache/memory-store.d.ts +10 -0
  130. package/dist/plugins/cache/types.d.ts +28 -0
  131. package/dist/plugins/configuration/configuration.d.ts +71 -0
  132. package/dist/plugins/context-guard/facts.d.ts +14 -0
  133. package/dist/plugins/context-guard/guard.d.ts +27 -0
  134. package/dist/plugins/context-guard/strategies/layered.d.ts +24 -0
  135. package/dist/plugins/context-guard/strategies/truncate.d.ts +19 -0
  136. package/dist/plugins/context-guard/tools.d.ts +50 -0
  137. package/dist/plugins/context-guard/types.d.ts +110 -0
  138. package/dist/plugins/context-measurer/calibration/store.d.ts +19 -0
  139. package/dist/plugins/context-measurer/counter/count-api.d.ts +41 -0
  140. package/dist/plugins/context-measurer/counter/heuristic.d.ts +25 -0
  141. package/dist/plugins/context-measurer/counter/hybrid.d.ts +33 -0
  142. package/dist/plugins/context-measurer/counter/tiktoken.d.ts +13 -0
  143. package/dist/plugins/context-measurer/measurer.d.ts +49 -0
  144. package/dist/plugins/context-measurer/types.d.ts +40 -0
  145. package/dist/plugins/cost-collector/collector.d.ts +42 -0
  146. package/dist/plugins/cost-collector/cost-collector-internal.d.ts +58 -0
  147. package/dist/plugins/cost-collector/cost-collector-types.d.ts +42 -0
  148. package/dist/plugins/embeddings/types.d.ts +23 -0
  149. package/dist/plugins/files/attachment.d.ts +79 -0
  150. package/dist/plugins/files/provider-adapter.d.ts +37 -0
  151. package/dist/plugins/files/registry.d.ts +48 -0
  152. package/dist/plugins/files/strategy.d.ts +38 -0
  153. package/dist/plugins/internal-tools/backends/local.d.ts +12 -0
  154. package/dist/plugins/internal-tools/builtin/builtin.d.ts +21 -0
  155. package/dist/plugins/internal-tools/builtin/clarify.d.ts +12 -0
  156. package/dist/plugins/internal-tools/builtin/classify.d.ts +12 -0
  157. package/dist/plugins/internal-tools/builtin/score.d.ts +13 -0
  158. package/dist/plugins/internal-tools/builtin/structure.d.ts +11 -0
  159. package/dist/plugins/internal-tools/builtin/summarize.d.ts +19 -0
  160. package/dist/plugins/internal-tools/id.d.ts +12 -0
  161. package/dist/plugins/internal-tools/registry.d.ts +24 -0
  162. package/dist/plugins/internal-tools/runner/define.d.ts +7 -0
  163. package/dist/plugins/internal-tools/runner/json-enforcement.d.ts +3 -0
  164. package/dist/plugins/internal-tools/runner/runner.d.ts +47 -0
  165. package/dist/plugins/internal-tools/runner/template.d.ts +10 -0
  166. package/dist/plugins/internal-tools/runner/types.d.ts +57 -0
  167. package/dist/plugins/internal-tools/runner/variants.d.ts +34 -0
  168. package/dist/plugins/internal-tools/types.d.ts +80 -0
  169. package/dist/plugins/logger/console-sink.d.ts +26 -0
  170. package/dist/plugins/logger/logger.d.ts +38 -0
  171. package/dist/plugins/logger/types.d.ts +25 -0
  172. package/dist/plugins/mcp/base-transport.d.ts +58 -0
  173. package/dist/plugins/mcp/client.d.ts +92 -0
  174. package/dist/plugins/mcp/jsonrpc.d.ts +20 -0
  175. package/dist/plugins/mcp/oauth.d.ts +122 -0
  176. package/dist/plugins/mcp/sampling.d.ts +17 -0
  177. package/dist/plugins/mcp/tools.d.ts +20 -0
  178. package/dist/plugins/mcp/transport-http.d.ts +50 -0
  179. package/dist/plugins/mcp/transport-stdio.d.ts +23 -0
  180. package/dist/plugins/mcp/transport-ws.d.ts +32 -0
  181. package/dist/plugins/mcp/transport.d.ts +29 -0
  182. package/dist/plugins/mcp/types.d.ts +202 -0
  183. package/dist/plugins/mcp/url-guard.d.ts +70 -0
  184. package/dist/plugins/mcp/win-spawn.d.ts +20 -0
  185. package/dist/plugins/media/file-store.d.ts +24 -0
  186. package/dist/plugins/media/memory-store.d.ts +17 -0
  187. package/dist/plugins/media/output.d.ts +44 -0
  188. package/dist/plugins/media/source-image.d.ts +36 -0
  189. package/dist/plugins/media/types.d.ts +146 -0
  190. package/dist/plugins/model-catalog/catalog.d.ts +152 -0
  191. package/dist/plugins/permissions/glob.d.ts +6 -0
  192. package/dist/plugins/permissions/matchers.d.ts +7 -0
  193. package/dist/plugins/permissions/policy.d.ts +10 -0
  194. package/dist/plugins/permissions/types.d.ts +22 -0
  195. package/dist/plugins/persistence/file.d.ts +25 -0
  196. package/dist/plugins/persistence/memory.d.ts +23 -0
  197. package/dist/plugins/persistence/types.d.ts +21 -0
  198. package/dist/plugins/retrieval/chunker.d.ts +28 -0
  199. package/dist/plugins/retrieval/hosted-google.d.ts +60 -0
  200. package/dist/plugins/retrieval/hosted-openai.d.ts +45 -0
  201. package/dist/plugins/retrieval/hosted-xai.d.ts +57 -0
  202. package/dist/plugins/retrieval/index.d.ts +70 -0
  203. package/dist/plugins/retrieval/local.d.ts +50 -0
  204. package/dist/plugins/retrieval/types.d.ts +161 -0
  205. package/dist/plugins/retrieval/vector-store.d.ts +70 -0
  206. package/dist/plugins/scheduler/scheduler.d.ts +31 -0
  207. package/dist/plugins/telemetry/telemetry.d.ts +118 -0
  208. package/dist/plugins/tool-catalog/catalog.d.ts +31 -0
  209. package/dist/plugins/tool-catalog/errors.d.ts +22 -0
  210. package/dist/plugins/tool-catalog/types.d.ts +44 -0
  211. package/dist/runtime/runtime.d.ts +20 -0
  212. package/dist/server/auth.d.ts +25 -0
  213. package/dist/server/dispatch.d.ts +35 -0
  214. package/dist/server/loaders.d.ts +26 -0
  215. package/dist/server/oai-adapter.d.ts +30 -0
  216. package/dist/server/oai-types.d.ts +114 -0
  217. package/dist/server/response-store.d.ts +59 -0
  218. package/dist/server/router.d.ts +59 -0
  219. package/dist/server/server.d.ts +61 -0
  220. package/dist/types/request-context.d.ts +46 -0
  221. package/dist/util/async.d.ts +3 -0
  222. package/dist/util/base64.d.ts +8 -0
  223. package/dist/util/duration.d.ts +12 -0
  224. package/dist/util/http.d.ts +9 -0
  225. package/dist/util/image-mime.d.ts +8 -0
  226. package/dist/util/json-schema.d.ts +7 -0
  227. package/dist/util/wav.d.ts +20 -0
  228. package/package.json +95 -0
@@ -0,0 +1,36 @@
1
+ /** Universal completion response. */
2
+ import type { ContentPart, MediaOutputPart, ToolCallPart } from './messages';
3
+ export interface CompletionResponse {
4
+ id: string;
5
+ model: string;
6
+ content: ContentPart[];
7
+ finishReason: FinishReason;
8
+ usage: Usage;
9
+ text: string;
10
+ toolCalls: ToolCallPart[];
11
+ thinking: string | null;
12
+ /** Media output parts (images, audio, video generated by model). */
13
+ media: MediaOutputPart[];
14
+ latencyMs: number;
15
+ raw: unknown;
16
+ }
17
+ export type FinishReason = 'stop' | 'tool_use' | 'length' | 'content_filter' | 'error';
18
+ export interface Usage {
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ totalTokens: number;
22
+ cachedTokens: number;
23
+ cacheWriteTokens: number;
24
+ reasoningTokens: number;
25
+ /** Audio input/output tokens (realtime / audio models). When set, inputTokens/
26
+ * outputTokens count only the TEXT portion so cost prices each at its own rate. */
27
+ audioInputTokens?: number;
28
+ audioOutputTokens?: number;
29
+ /** Service tier the provider actually billed, RAW as it reported it (openai
30
+ * `flex|priority|…`, anthropic `standard|priority|batch`). Auditable. */
31
+ serviceTier?: string;
32
+ /** The raw tier normalized by the adapter to the catalog's tier key — what cost
33
+ * uses for `pricing.tiers[...]`. Set alongside serviceTier; usually identical. */
34
+ pricingTier?: string;
35
+ }
36
+ export declare function emptyUsage(): Usage;
@@ -0,0 +1,8 @@
1
+ /** Shared JSON Schema utilities for provider-agnostic schema preprocessing. */
2
+ import type { JsonSchema } from './tools';
3
+ /**
4
+ * Recursively ensure every object-typed schema has `additionalProperties: false`.
5
+ * Required by OpenAI strict mode and Anthropic structured output — providers
6
+ * reject schemas without this explicit flag. Safe across all providers.
7
+ */
8
+ export declare function ensureAdditionalProperties(schema: JsonSchema): JsonSchema;
@@ -0,0 +1,42 @@
1
+ /** Universal streaming event types. */
2
+ import type { Usage } from './response';
3
+ export type MediaStreamType = 'image' | 'audio' | 'video';
4
+ export type StreamEvent = {
5
+ type: 'text';
6
+ text: string;
7
+ } | {
8
+ type: 'thinking';
9
+ text: string;
10
+ } | {
11
+ type: 'tool_call_start';
12
+ id: string;
13
+ name: string;
14
+ _meta?: Record<string, unknown>;
15
+ } | {
16
+ type: 'tool_call_delta';
17
+ id: string;
18
+ arguments: string;
19
+ } | {
20
+ type: 'tool_call_end';
21
+ id: string;
22
+ } | {
23
+ type: 'usage';
24
+ usage: Usage;
25
+ } | {
26
+ type: 'done';
27
+ finishReason: string;
28
+ } | {
29
+ type: 'error';
30
+ error: Error;
31
+ } | {
32
+ type: 'media_start';
33
+ mediaType: MediaStreamType;
34
+ mimeType: string;
35
+ } | {
36
+ type: 'media_chunk';
37
+ data: string;
38
+ progress?: number;
39
+ } | {
40
+ type: 'media_end';
41
+ mediaId?: string;
42
+ };
@@ -0,0 +1,11 @@
1
+ /** Unified service tier for a request. The four named values are the
2
+ * cross-provider core; the open `(string & {})` lets callers pass any tier
3
+ * (e.g. `'scale'`, or a future internal-optimization label) — each adapter
4
+ * decides whether it can honor it (pass through if the provider allows it,
5
+ * else fall back to that provider's `auto`).
6
+ *
7
+ * `batch` is intentionally NOT a value here — it's a separate API (the Batch
8
+ * endpoint), not a per-request flag on a synchronous call.
9
+ *
10
+ * Tier mapping is provider-specific and lives ENTIRELY in the adapters. */
11
+ export type ServiceTier = 'auto' | 'standard' | 'priority' | 'flex' | (string & {});
@@ -0,0 +1,20 @@
1
+ /** Universal tool schema definitions. */
2
+ export interface FunctionTool {
3
+ type?: 'function';
4
+ name: string;
5
+ description: string;
6
+ parameters: JsonSchema;
7
+ strict?: boolean;
8
+ cache?: boolean;
9
+ }
10
+ export interface BuiltinTool {
11
+ type: 'image_generation' | 'web_search' | 'code_interpreter' | 'file_search' | 'mcp';
12
+ params?: Record<string, unknown>;
13
+ }
14
+ export type Tool = FunctionTool | BuiltinTool;
15
+ export type ToolChoice = 'auto' | 'none' | 'required' | {
16
+ name: string;
17
+ };
18
+ export type JsonSchema = Record<string, unknown>;
19
+ export declare function isFunctionTool(tool: Tool): tool is FunctionTool;
20
+ export declare function isBuiltinTool(tool: Tool): tool is BuiltinTool;
@@ -0,0 +1,87 @@
1
+ /** NetworkEngine — multi-queue HTTP router (Layer 1).
2
+ *
3
+ * Holds a Map<queueName, QueueState>. Each queue has its own rate limiter,
4
+ * semaphore, retry policy, and request queue. Queues are created lazily on
5
+ * first use of a queueName, with default settings (or settings supplied via
6
+ * `configureQueue()` BEFORE first use — snapshot semantics).
7
+ *
8
+ * Knows nothing about LLMs, providers, or models. The semantic layer
9
+ * (LLMClient) populates `req.provider` and `req.model` for hook payloads
10
+ * and decides `queueName` (default formula: "$provider/$model").
11
+ *
12
+ * Public surface:
13
+ * - fetch(req, ctx?) — submit a non-streaming request
14
+ * - fetchStream(req, ctx?) — submit a streaming request (SSE)
15
+ * - configureQueue(name, settings) — pre-configure rate limit / retry
16
+ * - getQueueState(name) — introspect a queue (for tests / metrics)
17
+ * - destroy() — drop all queues (for teardown)
18
+ */
19
+ import { HookBus } from '../bus/hook-bus';
20
+ import type { RequestContext } from '../types/request-context';
21
+ import type { RateLimiterConfig } from './rate-limiter';
22
+ import type { QueueConfig } from './request-queue';
23
+ import { QueueState } from './queue-state';
24
+ import type { RetryConfig } from './queue-state-config';
25
+ import type { ConnectFn, FetchFn, HttpRequest, HttpResponse, RealtimeConnection, SSEEvent, WsRequest } from './types';
26
+ export interface QueueSettings {
27
+ limits?: Partial<RateLimiterConfig>;
28
+ retry?: Partial<RetryConfig>;
29
+ queue?: Partial<QueueConfig>;
30
+ }
31
+ export interface NetworkEngineConfig {
32
+ /** Bus to share with QueueStates so plugins can subscribe. Default: new HookBus(). */
33
+ hooks?: HookBus;
34
+ /** Default fetch function for all queues. Per-call override via ctx not supported
35
+ * (queue is bound to its fetch at creation). Default: globalThis.fetch. */
36
+ fetch?: FetchFn;
37
+ /** WebSocket factory for `connect()` (realtime). Default wraps globalThis.WebSocket.
38
+ * Injectable so tests supply a fake socket and the engine stays transport-agnostic. */
39
+ connect?: ConnectFn;
40
+ /** Pre-configured per-queue settings. Looked up by queueName at queue creation. */
41
+ queues?: Record<string, QueueSettings>;
42
+ }
43
+ /** Optional context for fetch/fetchStream. RequestContext + per-call overrides. */
44
+ export interface FetchOptions {
45
+ /** Routing key. If omitted, uses `req.provider/req.model` as fallback. */
46
+ queueName?: string;
47
+ priority?: number;
48
+ estimatedTokens?: number;
49
+ ctx?: Partial<RequestContext>;
50
+ }
51
+ export declare class NetworkEngine {
52
+ readonly hooks: HookBus;
53
+ private readonly fetchFn;
54
+ private readonly connectFn;
55
+ private readonly settings;
56
+ private readonly queues;
57
+ constructor(config?: NetworkEngineConfig);
58
+ /** Pre-configure (or reconfigure) a queue's settings.
59
+ * Throws if the queue already exists — settings are snapshotted at queue
60
+ * creation, so changes after that have no effect. To reconfigure an
61
+ * existing queue, call `dropQueue(name)` first. */
62
+ configureQueue(queueName: string, settings: QueueSettings): void;
63
+ /** Drop a queue (frees its state). In-flight requests on that queue continue
64
+ * but the next call with the same queueName creates a fresh queue. */
65
+ dropQueue(queueName: string): void;
66
+ /** Whether a queue has been created. */
67
+ hasQueue(queueName: string): boolean;
68
+ /** Names of all live queues. */
69
+ queueNames(): string[];
70
+ /** Get the underlying QueueState for a queueName (for tests / metrics).
71
+ * Returns null if not yet created. */
72
+ getQueueState(queueName: string): QueueState | null;
73
+ /** Numeric state of every live queue — for the States panel / metrics. */
74
+ snapshot(): import('./types').QueueSnapshot[];
75
+ /** Submit a request. */
76
+ fetch(req: HttpRequest, options?: FetchOptions): Promise<HttpResponse>;
77
+ /** Submit a streaming request. Yields SSE events. */
78
+ fetchStream(req: HttpRequest, options?: FetchOptions): AsyncIterable<SSEEvent>;
79
+ /** Open a realtime WebSocket connection. Engine-owned (auth via the request's
80
+ * protocols/headers, observability hooks) but QUEUE-EXEMPT: a persistent duplex
81
+ * socket has no per-call retry / rate-limit / idempotency, so it does not route
82
+ * through a QueueState. Sibling primitive to `fetch`. */
83
+ connect(req: WsRequest): RealtimeConnection;
84
+ /** Drop all queues. */
85
+ destroy(): void;
86
+ private getOrCreateQueue;
87
+ }
@@ -0,0 +1,14 @@
1
+ /** Error taxonomy — each error type gets different retry behavior.
2
+ * Lives in the network layer so QueueState can classify before hooks fire. */
3
+ export type ErrorKind = 'rate_limit' | 'auth' | 'context_overflow' | 'invalid_request' | 'server_error' | 'timeout' | 'network' | 'content_filter' | 'model_not_found' | 'quota_exceeded' | 'unsupported';
4
+ export declare class LLMError extends Error {
5
+ readonly kind: ErrorKind;
6
+ readonly provider: string;
7
+ readonly status?: number | undefined;
8
+ readonly retryable: boolean;
9
+ readonly retryAfterMs?: number | undefined;
10
+ readonly raw?: unknown | undefined;
11
+ constructor(message: string, kind: ErrorKind, provider: string, status?: number | undefined, retryable?: boolean, retryAfterMs?: number | undefined, raw?: unknown | undefined);
12
+ }
13
+ /** Map HTTP status + provider error body to our error taxonomy. */
14
+ export declare function classifyError(provider: string, status: number, body: unknown, headers: Record<string, string>): LLMError;
@@ -0,0 +1,41 @@
1
+ /** QueueState configuration: retry policy, queue priorities, and defaults. */
2
+ import type { HookBus } from '../bus/hook-bus';
3
+ import type { ErrorKind } from './errors';
4
+ import type { RateLimiterConfig } from './rate-limiter';
5
+ import type { QueueConfig } from './request-queue';
6
+ import type { FetchFn } from './types';
7
+ export interface RetryConfig {
8
+ maxRetries: number;
9
+ totalTimeoutMs: number;
10
+ attemptTimeoutMs: number;
11
+ backoff: BackoffConfig;
12
+ perKind?: Partial<Record<ErrorKind, ErrorRetryConfig>>;
13
+ }
14
+ export interface BackoffConfig {
15
+ initialMs: number;
16
+ maxMs: number;
17
+ multiplier: number;
18
+ jitter: number;
19
+ }
20
+ export interface ErrorRetryConfig {
21
+ retryable?: boolean;
22
+ maxRetries?: number;
23
+ fixedBackoffMs?: number;
24
+ }
25
+ export declare const DEFAULT_RETRY: RetryConfig;
26
+ export interface QueueStateConfig {
27
+ /** Routing identifier this queue is registered under. Carried in hook payloads. */
28
+ queueName: string;
29
+ fetch: FetchFn;
30
+ hooks: HookBus;
31
+ limits: RateLimiterConfig;
32
+ retry?: Partial<RetryConfig>;
33
+ queue?: Partial<QueueConfig>;
34
+ }
35
+ export declare const Priority: {
36
+ readonly RETRY: 0;
37
+ readonly INTERACTIVE: 1;
38
+ readonly BACKGROUND: 2;
39
+ readonly LOW: 3;
40
+ };
41
+ export declare function mergeRetry(overrides?: Partial<RetryConfig>): RetryConfig;
@@ -0,0 +1,45 @@
1
+ /** QueueState — owns queue + rate limiter + semaphore + retry for ONE queue.
2
+ *
3
+ * This is the per-queue body that NetworkEngine creates lazily. Today's
4
+ * llm-sdk packed all this inside ProviderExecutor (one executor per LLMClient,
5
+ * hence one queue per LLMClient); we extract it so a single NetworkEngine
6
+ * can host many queues keyed by `queueName` (e.g. "anthropic/claude-3-5",
7
+ * "openai/gpt-4o", "shared/cheap"). */
8
+ import type { QueueStateConfig } from './queue-state-config';
9
+ import type { HttpRequest, HttpResponse, SSEEvent } from './types';
10
+ export declare class QueueState {
11
+ readonly queueName: string;
12
+ private readonly fetchFn;
13
+ private readonly hooks;
14
+ private readonly rateLimiter;
15
+ private readonly semaphore;
16
+ private readonly queue;
17
+ private readonly retry;
18
+ private running;
19
+ /** Lifetime HTTP round-trips completed (bumped on each onRequestComplete). */
20
+ private processed;
21
+ /** Greatest depth ever observed (raised on enqueue). */
22
+ private peakDepth;
23
+ constructor(config: QueueStateConfig);
24
+ /** Point-in-time numeric state — depth, in-flight, rate-limit pressure. */
25
+ snapshot(): import('./types').QueueSnapshot;
26
+ /** Submit a request. Returns when the request completes (may wait in queue). */
27
+ submit(req: HttpRequest, priority?: number, estimatedTokens?: number): Promise<HttpResponse>;
28
+ /** Submit a streaming request. Yields SSE events. */
29
+ submitStream(req: HttpRequest, _priority?: number, estimatedTokens?: number): AsyncIterable<SSEEvent>;
30
+ private ensureProcessing;
31
+ private processLoop;
32
+ /** Last-resort safety net: executeWithRetry settles every entry itself, but if
33
+ * it ever throws from its pre-`try` setup (before releasing the semaphore),
34
+ * the entry's promise would otherwise NEVER settle — a silent hang. Release
35
+ * the slot so the queue can't deadlock, surface the bug via the existing error
36
+ * hook (V1 telemetry), and reject the caller so it fails fast and visibly. */
37
+ private settleOnWorkerCrash;
38
+ private executeWithRetry;
39
+ private handleRetry;
40
+ private calculateBackoff;
41
+ private executeOnce;
42
+ private waitForCapacity;
43
+ private emitRateLimitUpdate;
44
+ private emitErrorHooks;
45
+ }
@@ -0,0 +1,49 @@
1
+ /** Token bucket rate limiter for RPM/TPM/RPD tracking. */
2
+ export interface TokenBucketConfig {
3
+ /** Max tokens in bucket (e.g. 60 for 60 RPM). */
4
+ capacity: number;
5
+ /** Refill interval in ms. For RPM: 60_000 / capacity. */
6
+ refillIntervalMs: number;
7
+ }
8
+ export declare class TokenBucket {
9
+ private tokens;
10
+ private lastRefill;
11
+ private capacity;
12
+ private refillRate;
13
+ constructor(config: TokenBucketConfig);
14
+ /** Try to consume n tokens. Returns true if successful. */
15
+ tryConsume(n?: number): boolean;
16
+ /** How long to wait (ms) until n tokens are available. 0 if available now. */
17
+ waitTimeMs(n?: number): number;
18
+ /** Force-set tokens remaining (e.g. from rate limit headers). */
19
+ setRemaining(remaining: number): void;
20
+ /** Update capacity (e.g. discovered from headers). */
21
+ setCapacity(capacity: number): void;
22
+ /** Pause until a specific timestamp (e.g. from retry-after/reset headers). */
23
+ drainUntil(resetAt: number): void;
24
+ get available(): number;
25
+ private refill;
26
+ }
27
+ export interface RateLimiterConfig {
28
+ rpm: number | null;
29
+ tpm: number | null;
30
+ rpd: number | null;
31
+ concurrent: number;
32
+ }
33
+ /** Composite rate limiter managing RPM + TPM + RPD buckets. */
34
+ export declare class RateLimiter {
35
+ private rpmBucket;
36
+ private tpmBucket;
37
+ private rpdBucket;
38
+ constructor(config: RateLimiterConfig);
39
+ /** Check if a request with estimated tokens can proceed now. */
40
+ canProceed(estimatedTokens?: number): boolean;
41
+ /** How long to wait before a request can proceed (ms). */
42
+ waitTimeMs(estimatedTokens?: number): number;
43
+ /** Update state from provider response headers. */
44
+ updateFromHeaders(headers: Record<string, string>): void;
45
+ /** Mark as rate-limited for a duration (from 429 + retry-after). */
46
+ pause(durationMs: number): void;
47
+ get rpmAvailable(): number;
48
+ get tpmAvailable(): number;
49
+ }
@@ -0,0 +1,40 @@
1
+ /** RealtimeConnectionImpl — wraps a raw RealtimeSocket into the engine-owned
2
+ * RealtimeConnection: normalizes inbound frames (string → text, binary → bytes),
3
+ * fans out to adapter listeners, and emits observability hooks. This is the
4
+ * realtime sibling of QueueState's HTTP handling — except there is no queue: a
5
+ * live socket has no per-call retry / rate-limit / idempotency.
6
+ *
7
+ * Knows nothing about provider protocols. A RealtimeProviderAdapter sits on top
8
+ * and maps normalized frames ↔ provider event JSON. */
9
+ import type { HookBus } from '../bus/hook-bus';
10
+ import type { RealtimeConnection, RealtimeFrame, RealtimeSocket, WsRequest } from './types';
11
+ type FrameCb = (f: RealtimeFrame) => void;
12
+ type VoidCb = () => void;
13
+ type ErrCb = (e: Error) => void;
14
+ export interface RealtimeConnectionDeps {
15
+ socket: RealtimeSocket;
16
+ req: WsRequest;
17
+ hooks: HookBus;
18
+ }
19
+ export declare class RealtimeConnectionImpl implements RealtimeConnection {
20
+ private readonly socket;
21
+ private readonly req;
22
+ private readonly hooks;
23
+ private readonly messageCbs;
24
+ private readonly openCbs;
25
+ private readonly closeCbs;
26
+ private readonly errorCbs;
27
+ constructor(deps: RealtimeConnectionDeps);
28
+ get readyState(): number;
29
+ send(data: string | ArrayBufferLike | ArrayBufferView): void;
30
+ on(type: 'message', cb: FrameCb): () => void;
31
+ on(type: 'open' | 'close', cb: VoidCb): () => void;
32
+ on(type: 'error', cb: ErrCb): () => void;
33
+ close(code?: number, reason?: string): void;
34
+ private handleOpen;
35
+ private handleMessage;
36
+ private handleClose;
37
+ private handleError;
38
+ private emitFrameHook;
39
+ }
40
+ export {};
@@ -0,0 +1,40 @@
1
+ /** Priority request queue (min-heap). Lower priority = higher urgency.
2
+ * Same priority = FIFO. */
3
+ import type { HttpRequest, HttpResponse } from './types';
4
+ export interface QueueEntry {
5
+ id: string;
6
+ request: HttpRequest;
7
+ priority: number;
8
+ enqueuedAt: number;
9
+ deadline: number;
10
+ estimatedTokens: number;
11
+ attempt: number;
12
+ resolve: (res: HttpResponse) => void;
13
+ reject: (err: Error) => void;
14
+ }
15
+ export interface QueueConfig {
16
+ /** Max pending requests. Reject new ones if exceeded. */
17
+ maxSize: number;
18
+ /** Max time (ms) a request can wait in queue. */
19
+ timeoutMs: number;
20
+ }
21
+ export declare class RequestQueue {
22
+ private heap;
23
+ private readonly config;
24
+ private drainWaiters;
25
+ constructor(config?: Partial<QueueConfig>);
26
+ enqueue(request: HttpRequest, priority: number, estimatedTokens: number, attempt?: number): Promise<HttpResponse>;
27
+ dequeue(): QueueEntry | null;
28
+ peek(): QueueEntry | null;
29
+ waitForItem(): Promise<void>;
30
+ get length(): number;
31
+ private purgeExpired;
32
+ private notifyDrain;
33
+ private push;
34
+ private pop;
35
+ private bubbleUp;
36
+ private sinkDown;
37
+ private rebuildHeap;
38
+ /** Compare: lower priority first, then earlier enqueue time. */
39
+ private compare;
40
+ }
@@ -0,0 +1,12 @@
1
+ /** Counting semaphore for concurrency control. */
2
+ export declare class Semaphore {
3
+ private readonly max;
4
+ private current;
5
+ private readonly waiters;
6
+ constructor(max: number);
7
+ acquire(): Promise<void>;
8
+ release(): void;
9
+ get inFlight(): number;
10
+ get waiting(): number;
11
+ get available(): number;
12
+ }
@@ -0,0 +1,3 @@
1
+ /** Server-Sent Events parser. One implementation for all providers. */
2
+ import type { SSEEvent } from './types';
3
+ export declare function parseSSEStream(body: ReadableStream<Uint8Array>): AsyncIterable<SSEEvent>;
@@ -0,0 +1,127 @@
1
+ /** Network layer shared types. */
2
+ export type FetchFn = typeof globalThis.fetch;
3
+ /** Request submitted to NetworkEngine. The semantic layer (LLMClient) sets
4
+ * `provider` and `model` purely for hook observability; the routing key is
5
+ * `queueName` (set by LLMClient via formula or RequestContext override). */
6
+ export interface HttpRequest {
7
+ url: string;
8
+ method?: string;
9
+ headers: Record<string, string>;
10
+ body: unknown;
11
+ timeout?: number;
12
+ signal?: AbortSignal;
13
+ stream?: boolean;
14
+ provider: string;
15
+ model: string;
16
+ /** How to parse the response body. Default 'json' (LLM responses, image-gen
17
+ * with b64_json, video-status JSON). Use 'arraybuffer' for binary downloads
18
+ * (TTS audio bytes, video file bytes). 'text' for plain-text responses. */
19
+ responseType?: 'json' | 'arraybuffer' | 'text';
20
+ /** When the request body is already a Uint8Array / ArrayBuffer (binary
21
+ * upload like multipart) the queue should NOT JSON.stringify it. Default
22
+ * false → body is JSON.stringify'd. */
23
+ rawBody?: boolean;
24
+ /** Trace correlation — set by the caller (LLM client / media op) from the
25
+ * RequestContext so every network event can echo `sessionId:requestId`. */
26
+ trace?: TraceContext;
27
+ }
28
+ /** Raw HTTP response (post-fetch, pre-provider-parse). */
29
+ export interface HttpResponse {
30
+ status: number;
31
+ headers: Record<string, string>;
32
+ body: unknown;
33
+ }
34
+ /** SSE event passed up from streaming response. */
35
+ export interface SSEEvent {
36
+ event?: string;
37
+ data: string;
38
+ /** SSE `id:` field — used for resumption (Last-Event-ID). */
39
+ id?: string;
40
+ }
41
+ /** Correlation ids carried on a request so network events can be stitched to the
42
+ * LLM call end-to-end. `sessionId:requestId` is the OTel trace id. */
43
+ export interface TraceContext {
44
+ sessionId?: string;
45
+ requestId?: string;
46
+ callId?: string;
47
+ }
48
+ /** Point-in-time numeric state of one queue (for metrics / observability). */
49
+ export interface QueueSnapshot {
50
+ queueName: string;
51
+ /** Requests queued, not yet started. */
52
+ depth: number;
53
+ /** Requests currently executing (semaphore held). */
54
+ inFlight: number;
55
+ /** Requests blocked waiting for a concurrency slot. */
56
+ waiting: number;
57
+ /** ms until the next request may proceed under the rate limit (0 = free now). */
58
+ rateLimitWaitMs: number;
59
+ /** Whether the queue's process loop is active. */
60
+ running: boolean;
61
+ /** Lifetime count of HTTP round-trips completed on this queue. A persistent
62
+ * counter so an idle queue still shows evidence of past activity (depth /
63
+ * inFlight are instantaneous and read 0 between bursts). */
64
+ processed: number;
65
+ /** High-water mark: the greatest depth this queue has reached. */
66
+ peakDepth: number;
67
+ }
68
+ /** Per-call fetch options accepted by NetworkEngine.fetch / fetchStream.
69
+ * Re-declared here (vs. importing from engine.ts) to avoid a cycle when
70
+ * consumers (LLMClient) only need the function shape. */
71
+ export interface FetchOptionsLite {
72
+ queueName?: string;
73
+ priority?: number;
74
+ estimatedTokens?: number;
75
+ ctx?: Record<string, unknown>;
76
+ }
77
+ /** Function shape consumed by LLMClient. NetworkEngine.fetch.bind(engine)
78
+ * satisfies this; tests may provide simpler stubs. */
79
+ export type EngineFetch = (req: HttpRequest, options?: FetchOptionsLite) => Promise<HttpResponse>;
80
+ /** Streaming variant. */
81
+ export type EngineFetchStream = (req: HttpRequest, options?: FetchOptionsLite) => AsyncIterable<SSEEvent>;
82
+ /** A WebSocket open request. The semantic layer (a RealtimeProviderAdapter)
83
+ * builds `url` (including any `?key=` auth) and `protocols` (e.g. OpenAI's
84
+ * `openai-insecure-api-key.<key>` subprotocol). `provider`/`model` are carried
85
+ * for hook observability. */
86
+ export interface WsRequest {
87
+ url: string;
88
+ protocols?: string | string[];
89
+ /** Header auth, where the underlying socket impl supports it (Node `ws`, Bun).
90
+ * Browsers cannot set WS headers — providers that must run in a browser use
91
+ * subprotocol or query-param auth instead. */
92
+ headers?: Record<string, string>;
93
+ provider: string;
94
+ model: string;
95
+ }
96
+ /** Minimal WHATWG-WebSocket shape the engine depends on. Injectable so tests
97
+ * can supply a fake socket and the engine stays transport-agnostic. */
98
+ export interface RealtimeSocket {
99
+ send(data: string | ArrayBufferLike | ArrayBufferView): void;
100
+ close(code?: number, reason?: string): void;
101
+ addEventListener(type: 'open' | 'close' | 'error' | 'message', cb: (ev: unknown) => void): void;
102
+ readonly readyState: number;
103
+ }
104
+ /** Factory that opens a RealtimeSocket. Default wraps `globalThis.WebSocket`. */
105
+ export type ConnectFn = (url: string, opts?: {
106
+ protocols?: string | string[];
107
+ headers?: Record<string, string>;
108
+ }) => RealtimeSocket;
109
+ /** A normalized inbound frame surfaced to adapters: text or binary, never raw. */
110
+ export type RealtimeFrame = {
111
+ text: string;
112
+ } | {
113
+ binary: Uint8Array;
114
+ };
115
+ /** Engine-owned connection: normalized frames + lifecycle + hook emission.
116
+ * `on()` returns an unsubscribe function. */
117
+ export interface RealtimeConnection {
118
+ send(data: string | ArrayBufferLike | ArrayBufferView): void;
119
+ on(type: 'message', cb: (f: RealtimeFrame) => void): () => void;
120
+ on(type: 'open' | 'close', cb: () => void): () => void;
121
+ on(type: 'error', cb: (e: Error) => void): () => void;
122
+ close(code?: number, reason?: string): void;
123
+ readonly readyState: number;
124
+ }
125
+ /** Function shape consumed by RealtimeProviderAdapters. NetworkEngine.connect
126
+ * satisfies this. */
127
+ export type EngineConnect = (req: WsRequest) => RealtimeConnection;
@@ -0,0 +1,45 @@
1
+ /** Batcher — transparent batch optimization layer.
2
+ * Intercepts batchable requests via onBeforeSubmit, collects into batches,
3
+ * polls via Scheduler, delivers results back through the intercepted Promise. */
4
+ import type { HookBus } from '../../bus/hook-bus';
5
+ import type { EngineFetch } from '../../network/types';
6
+ import type { Persistence } from '../persistence/types';
7
+ import type { Scheduler } from '../scheduler/scheduler';
8
+ import type { BatchProviderAdapter, BatchStrategy } from './types';
9
+ export interface BatcherConfig {
10
+ hooks: HookBus;
11
+ persistence: Persistence;
12
+ scheduler: Scheduler;
13
+ strategy: BatchStrategy;
14
+ providers: Map<string, BatchProviderAdapter>;
15
+ /** Engine fetch — every adapter HTTP call dispatches through this so it
16
+ * inherits NetworkEngine queue semantics (rate limits, retry, hooks). */
17
+ fetch: EngineFetch;
18
+ }
19
+ export declare class Batcher {
20
+ private hooks;
21
+ private persistence;
22
+ private scheduler;
23
+ private strategy;
24
+ private providers;
25
+ private fetch;
26
+ /** Tracking requestors (agents + standalone LLMs) for shouldBatch decisions. */
27
+ private requestors;
28
+ /** Per-provider collection buffer with optional flush timer. */
29
+ private collecting;
30
+ /** Resolvers awaiting batch results. Lost on restart — restored runs route
31
+ * results to conversations via hooks instead of resolving Promises. */
32
+ private pendingResolvers;
33
+ private unsubs;
34
+ constructor(config: BatcherConfig);
35
+ destroy(): void;
36
+ /** Restore pending batches from persistence. Call on startup after scheduler.start(). */
37
+ restore(): Promise<void>;
38
+ poll(batchId: string): Promise<void>;
39
+ private handleBeforeSubmit;
40
+ private addToCollection;
41
+ private flushCollection;
42
+ private handleBatchComplete;
43
+ private countBatchableRequestors;
44
+ private getPendingCount;
45
+ }
@@ -0,0 +1,20 @@
1
+ /** Default batch strategy. */
2
+ import type { BatchStrategy } from './types';
3
+ export declare class DefaultBatchStrategy implements BatchStrategy {
4
+ collectionWindowMs: number;
5
+ minBatchSize: number;
6
+ maxBatchSize: number;
7
+ pollIntervalMs: number;
8
+ constructor(opts?: Partial<{
9
+ collectionWindowMs: number;
10
+ minBatchSize: number;
11
+ maxBatchSize: number;
12
+ pollIntervalMs: number;
13
+ }>);
14
+ shouldBatch(ctx: {
15
+ provider: string;
16
+ markedRequestorsCount: number;
17
+ pendingCount: number;
18
+ }): boolean;
19
+ estimateFirstPoll(batchSize: number): number;
20
+ }