@omnicross/core 0.1.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 (114) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +57 -0
  3. package/README.md +15 -0
  4. package/dist/ApiKeyPoolService-BmMkau07.d.cts +170 -0
  5. package/dist/ApiKeyPoolService-BmMkau07.d.ts +170 -0
  6. package/dist/ProviderProxy-f_8ziIhW.d.cts +120 -0
  7. package/dist/ProviderProxy-vjt8sQQk.d.ts +120 -0
  8. package/dist/SubscriptionAuthSource-Cr4fVEYY.d.cts +264 -0
  9. package/dist/SubscriptionAuthSource-D89zmiSS.d.ts +264 -0
  10. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +218 -0
  11. package/dist/auth/GeminiCodeAssistProjectResolver.d.cts +68 -0
  12. package/dist/auth/GeminiCodeAssistProjectResolver.d.ts +68 -0
  13. package/dist/auth/GeminiCodeAssistProjectResolver.js +189 -0
  14. package/dist/completion/ApiKeyPoolService.cjs +331 -0
  15. package/dist/completion/ApiKeyPoolService.d.cts +2 -0
  16. package/dist/completion/ApiKeyPoolService.d.ts +2 -0
  17. package/dist/completion/ApiKeyPoolService.js +306 -0
  18. package/dist/completion.cjs +4027 -0
  19. package/dist/completion.d.cts +17 -0
  20. package/dist/completion.d.ts +17 -0
  21. package/dist/completion.js +3983 -0
  22. package/dist/index-BTSmc9Sm.d.ts +645 -0
  23. package/dist/index-DXazdTzZ.d.cts +645 -0
  24. package/dist/index.cjs +10428 -0
  25. package/dist/index.d.cts +128 -0
  26. package/dist/index.d.ts +128 -0
  27. package/dist/index.js +10339 -0
  28. package/dist/outbound-api/subscriptionRegistryPort.cjs +38 -0
  29. package/dist/outbound-api/subscriptionRegistryPort.d.cts +73 -0
  30. package/dist/outbound-api/subscriptionRegistryPort.d.ts +73 -0
  31. package/dist/outbound-api/subscriptionRegistryPort.js +12 -0
  32. package/dist/outbound-api.cjs +5264 -0
  33. package/dist/outbound-api.d.cts +320 -0
  34. package/dist/outbound-api.d.ts +320 -0
  35. package/dist/outbound-api.js +5218 -0
  36. package/dist/pipeline/SubscriptionAuthSource.cjs +131 -0
  37. package/dist/pipeline/SubscriptionAuthSource.d.cts +3 -0
  38. package/dist/pipeline/SubscriptionAuthSource.d.ts +3 -0
  39. package/dist/pipeline/SubscriptionAuthSource.js +103 -0
  40. package/dist/pipeline/SubscriptionAuthStrategy.cjs +18 -0
  41. package/dist/pipeline/SubscriptionAuthStrategy.d.cts +61 -0
  42. package/dist/pipeline/SubscriptionAuthStrategy.d.ts +61 -0
  43. package/dist/pipeline/SubscriptionAuthStrategy.js +0 -0
  44. package/dist/ports/gemini-code-assist-resolver.cjs +38 -0
  45. package/dist/ports/gemini-code-assist-resolver.d.cts +26 -0
  46. package/dist/ports/gemini-code-assist-resolver.d.ts +26 -0
  47. package/dist/ports/gemini-code-assist-resolver.js +12 -0
  48. package/dist/ports.cjs +18 -0
  49. package/dist/ports.d.cts +15 -0
  50. package/dist/ports.d.ts +15 -0
  51. package/dist/ports.js +0 -0
  52. package/dist/provider-proxy/ingress/providerProxyShared.cjs +2958 -0
  53. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +77 -0
  54. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +77 -0
  55. package/dist/provider-proxy/ingress/providerProxyShared.js +2925 -0
  56. package/dist/provider-proxy/matchText.cjs +73 -0
  57. package/dist/provider-proxy/matchText.d.cts +47 -0
  58. package/dist/provider-proxy/matchText.d.ts +47 -0
  59. package/dist/provider-proxy/matchText.js +45 -0
  60. package/dist/provider-proxy/types.cjs +18 -0
  61. package/dist/provider-proxy/types.d.cts +12 -0
  62. package/dist/provider-proxy/types.d.ts +12 -0
  63. package/dist/provider-proxy/types.js +0 -0
  64. package/dist/provider-proxy.cjs +4667 -0
  65. package/dist/provider-proxy.d.cts +69 -0
  66. package/dist/provider-proxy.d.ts +69 -0
  67. package/dist/provider-proxy.js +4636 -0
  68. package/dist/serializeError.cjs +82 -0
  69. package/dist/serializeError.d.cts +24 -0
  70. package/dist/serializeError.d.ts +24 -0
  71. package/dist/serializeError.js +57 -0
  72. package/dist/sse-parser.cjs +456 -0
  73. package/dist/sse-parser.d.cts +143 -0
  74. package/dist/sse-parser.d.ts +143 -0
  75. package/dist/sse-parser.js +430 -0
  76. package/dist/transformer/TransformerChainExecutor.cjs +321 -0
  77. package/dist/transformer/TransformerChainExecutor.d.cts +104 -0
  78. package/dist/transformer/TransformerChainExecutor.d.ts +104 -0
  79. package/dist/transformer/TransformerChainExecutor.js +294 -0
  80. package/dist/transformer/TransformerService.cjs +290 -0
  81. package/dist/transformer/TransformerService.d.cts +138 -0
  82. package/dist/transformer/TransformerService.d.ts +138 -0
  83. package/dist/transformer/TransformerService.js +265 -0
  84. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +1115 -0
  85. package/dist/transformer/transformers/GeminiCodeAssistTransformer.d.cts +102 -0
  86. package/dist/transformer/transformers/GeminiCodeAssistTransformer.d.ts +102 -0
  87. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +1085 -0
  88. package/dist/transformer/transformers/GeminiTransformer.cjs +1013 -0
  89. package/dist/transformer/transformers/GeminiTransformer.d.cts +70 -0
  90. package/dist/transformer/transformers/GeminiTransformer.d.ts +70 -0
  91. package/dist/transformer/transformers/GeminiTransformer.js +986 -0
  92. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +538 -0
  93. package/dist/transformer/transformers/OpenAIResponseTransformer.d.cts +53 -0
  94. package/dist/transformer/transformers/OpenAIResponseTransformer.d.ts +53 -0
  95. package/dist/transformer/transformers/OpenAIResponseTransformer.js +513 -0
  96. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +73 -0
  97. package/dist/transformer/transformers/OpenCodeGoTransformer.d.cts +51 -0
  98. package/dist/transformer/transformers/OpenCodeGoTransformer.d.ts +51 -0
  99. package/dist/transformer/transformers/OpenCodeGoTransformer.js +48 -0
  100. package/dist/transformer/types.cjs +18 -0
  101. package/dist/transformer/types.d.cts +405 -0
  102. package/dist/transformer/types.d.ts +405 -0
  103. package/dist/transformer/types.js +0 -0
  104. package/dist/transformer.cjs +3736 -0
  105. package/dist/transformer.d.cts +33 -0
  106. package/dist/transformer.d.ts +33 -0
  107. package/dist/transformer.js +3712 -0
  108. package/dist/types-CGGrKqC_.d.cts +142 -0
  109. package/dist/types-CbCN2NQP.d.ts +142 -0
  110. package/dist/types-DCzHkhJt.d.ts +467 -0
  111. package/dist/types-DZIQbgp0.d.cts +467 -0
  112. package/dist/usage-event-sink-BX7FE1NL.d.cts +59 -0
  113. package/dist/usage-event-sink-BX7FE1NL.d.ts +59 -0
  114. package/package.json +62 -0
@@ -0,0 +1,645 @@
1
+ import { MessageBlock } from '@omnicross/contracts/message-blocks';
2
+ import { SimpleChatMessage, ThinkLevel, SimpleChatAudio, SimpleChatVideo, AnthropicMessage, OpenAIMessage } from '@omnicross/contracts/completion-types';
3
+ import { LLMProvider, OpenRouterProviderRouting } from '@omnicross/contracts/llm-config';
4
+ import { C as CorePaths, U as UsageEventSink } from './usage-event-sink-BX7FE1NL.cjs';
5
+ import { L as Logger, A as ApiKeyPoolService } from './ApiKeyPoolService-BmMkau07.cjs';
6
+ import { W as WebSearchBackend, P as ProviderConfigSource, U as UsageRecorderImport } from './types-DZIQbgp0.cjs';
7
+ import { MCPCallToolResponse, MCPTool } from '@omnicross/contracts/mcp-types';
8
+ import { resolveProviderEndpoint as resolveProviderEndpoint$1 } from '@omnicross/contracts/endpoint-resolver';
9
+
10
+ /**
11
+ * Native Search Types
12
+ *
13
+ * Type definitions for provider-native web search capabilities.
14
+ * Used by NativeSearchInjector to detect and configure built-in
15
+ * search for OpenAI, Anthropic, Google, xAI, and OpenRouter.
16
+ *
17
+ * @module completion/native-search-types
18
+ */
19
+
20
+ /** Providers that support native/built-in web search */
21
+ type NativeSearchProvider = 'openai' | 'anthropic' | 'google' | 'xai' | 'openrouter';
22
+ /** Result of detecting native search support for a model */
23
+ interface NativeSearchDetectionResult {
24
+ /** Whether the model supports native search */
25
+ supported: boolean;
26
+ /** Which native provider to use, if supported */
27
+ nativeProvider: NativeSearchProvider | null;
28
+ }
29
+ /** Native search tool names that should NOT be executed locally */
30
+ declare const NATIVE_SEARCH_TOOL_NAMES: string[];
31
+ /** User-facing configuration for native search */
32
+ interface NativeSearchUserConfig {
33
+ /** Whether native search is enabled */
34
+ enabled: boolean;
35
+ /** Max search results / uses (maps to provider-specific settings) */
36
+ maxResults?: number;
37
+ /** Domains to block (Anthropic) */
38
+ blockedDomains?: string[];
39
+ /** xAI search mode override */
40
+ searchMode?: 'on' | 'off' | 'auto';
41
+ /** xAI search sources */
42
+ sources?: Array<{
43
+ type: 'web' | 'x' | 'news';
44
+ }>;
45
+ }
46
+ /**
47
+ * Request body augmentation produced by NativeSearchInjector.
48
+ *
49
+ * - `additionalTools`: Appended to the tools array in the request body.
50
+ * - `bodyFields`: Merged into the top-level request body.
51
+ */
52
+ interface NativeSearchAugmentation {
53
+ /** Extra tools to append (OpenAI web_search, Anthropic web_search_20250305, Gemini grounding) */
54
+ additionalTools?: unknown[];
55
+ /** Top-level body fields (xAI search_parameters, OpenRouter plugins, OpenAI web_search_options) */
56
+ bodyFields?: Record<string, unknown>;
57
+ }
58
+
59
+ /**
60
+ * Completion Service Types
61
+ *
62
+ * Type definitions for completion options, results, and callbacks.
63
+ */
64
+
65
+ interface CompletionOptions {
66
+ providerId: string;
67
+ model: string;
68
+ messages: SimpleChatMessage[];
69
+ maxTokens?: number;
70
+ temperature?: number;
71
+ stream?: boolean;
72
+ /** Thinking effort level for reasoning models */
73
+ thinkLevel?: ThinkLevel;
74
+ /** Native search augmentation to apply to the request body */
75
+ nativeSearchAugmentation?: NativeSearchAugmentation;
76
+ /** Session ID for API key pool affinity (preserves prompt cache) and usage attribution. */
77
+ sessionId?: string;
78
+ /**
79
+ * Assistant-message id this request is producing — used to attribute
80
+ * recorded usage rows back to host messages. Optional; if absent the row is
81
+ * still recorded but won't be linked.
82
+ */
83
+ messageId?: string;
84
+ /**
85
+ * Parent message id (for subagent-style nested calls). Best-effort: callers
86
+ * that know the parent should fill this; otherwise leave unset.
87
+ */
88
+ parentMessageId?: string;
89
+ /**
90
+ * Opt into the Anthropic 1M-context tier for this request. The transformer
91
+ * pipeline (and any direct Anthropic-format paths) inject the
92
+ * `'context-1m-2025-08-07'` beta into the outbound request body when this
93
+ * is true AND the resolved model is in the 1M-capable allowlist.
94
+ */
95
+ useExtendedContext?: boolean;
96
+ }
97
+ interface CompletionResult {
98
+ success: boolean;
99
+ message?: SimpleChatMessage;
100
+ error?: string;
101
+ usage?: {
102
+ promptTokens: number;
103
+ completionTokens: number;
104
+ totalTokens: number;
105
+ };
106
+ /** Provider finish reason (e.g. 'stop', 'tool_use', 'max_tokens') */
107
+ finishReason?: string;
108
+ }
109
+ interface StreamCallbacks {
110
+ onStart?: (messageId: string) => void;
111
+ onDelta?: (content: string) => void;
112
+ onReasoning?: (reasoning: string) => void;
113
+ onAudio?: (audio: SimpleChatAudio) => void;
114
+ onVideo?: (video: SimpleChatVideo) => void;
115
+ /** Called when a new content block is created (thinking, text, tool_use, tool_result) */
116
+ onBlock?: (block: MessageBlock) => void;
117
+ onDone?: (message: SimpleChatMessage, usage?: CompletionResult['usage'], metrics?: {
118
+ completionTokens: number;
119
+ timeCompletionMs: number;
120
+ timeFirstTokenMs?: number;
121
+ }) => void;
122
+ onError?: (error: string) => void;
123
+ }
124
+ /**
125
+ * API format type for determining endpoint structure
126
+ */
127
+ type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response';
128
+
129
+ /**
130
+ * Core-owned tool-shape types.
131
+ *
132
+ * The structural tool definitions (`OpenAITool`, `AnthropicTool`,
133
+ * `GeminiTools`) are pure data shapes with no host dependency — hoisted here
134
+ * (verbatim from the host `tools/mcp-users/ToolsLoader.ts`) so the serving core
135
+ * names no host module. The host `ToolsLoader.ts` re-exports these from
136
+ * `@omnicross/core`, keeping every existing host consumer unchanged.
137
+ *
138
+ * `McpToolProvider` is the narrow structural port for the single `callTool`
139
+ * method the completion tool-loop consumes from the host's concrete
140
+ * `McpService`. The concrete `McpService` instance is injected at the existing
141
+ * seam and satisfies this port structurally (type-only — no runtime coupling).
142
+ */
143
+
144
+ /**
145
+ * OpenAI-compatible tool definition
146
+ */
147
+ interface OpenAITool {
148
+ type: 'function';
149
+ function: {
150
+ name: string;
151
+ description: string;
152
+ parameters: Record<string, any>;
153
+ };
154
+ }
155
+ /**
156
+ * Anthropic tool definition
157
+ */
158
+ interface AnthropicTool {
159
+ name: string;
160
+ description: string;
161
+ input_schema: Record<string, any>;
162
+ }
163
+ /**
164
+ * Google Gemini tool definition
165
+ * Gemini REST API expects tools wrapped in functionDeclarations
166
+ */
167
+ type GeminiTools = Array<{
168
+ functionDeclarations: Array<{
169
+ name: string;
170
+ description: string;
171
+ parameters: Record<string, any>;
172
+ }>;
173
+ }>;
174
+ /**
175
+ * Narrow structural port for the host MCP tool provider — only the `callTool`
176
+ * method the serving-core tool-loop dispatches to. The host's concrete
177
+ * `McpService` satisfies this structurally.
178
+ */
179
+ interface McpToolProvider {
180
+ callTool(serverId: string, toolName: string, args: unknown, callId: string): Promise<MCPCallToolResponse>;
181
+ }
182
+
183
+ /**
184
+ * BuiltinToolExecutor — Executes built-in tools (web_search, web_fetch)
185
+ * for the non-agent chat pipeline.
186
+ *
187
+ * Built-in tools use `serverId: 'builtin'` in MCPTool metadata and are
188
+ * dispatched here instead of going through McpService.callTool().
189
+ */
190
+
191
+ declare class BuiltinToolExecutor {
192
+ private webSearch;
193
+ constructor(webSearch: WebSearchBackend);
194
+ execute(toolName: string, args: Record<string, unknown>): Promise<MCPCallToolResponse>;
195
+ private executeWebSearch;
196
+ private resolveProviderChain;
197
+ private executeWebFetch;
198
+ }
199
+ /** Get the built-in MCPTool definitions for web search tools. */
200
+ declare function getBuiltinSearchTools(): MCPTool[];
201
+
202
+ /**
203
+ * ToolHandler - Handles streaming completion with MCP tool support
204
+ *
205
+ * Extracted from CompletionService to isolate the agentic loop logic
206
+ * that handles tool calls: LLM -> execute tools -> LLM again until done.
207
+ */
208
+
209
+ /** Extended options for tool-based completion */
210
+ interface StreamWithToolsOptions extends CompletionOptions {
211
+ tools: OpenAITool[] | AnthropicTool[] | GeminiTools;
212
+ mcpTools?: MCPTool[];
213
+ }
214
+ /** Extended callbacks for tool-based completion */
215
+ interface StreamWithToolsCallbacks extends StreamCallbacks {
216
+ onToolCall?: (toolCall: {
217
+ id: string;
218
+ name: string;
219
+ args: unknown;
220
+ }) => void;
221
+ onToolResult?: (toolId: string, result: unknown) => void;
222
+ }
223
+
224
+ /**
225
+ * VisionFallbackProvider — serving-core port for image-to-text fallback.
226
+ *
227
+ * When the active completion model lacks vision capability but a message
228
+ * carries images, `CompletionService.applyVisionFallback` delegates to this
229
+ * port to turn the images into a text description (which is then appended to
230
+ * the message content) before stripping the image attachments.
231
+ *
232
+ * The concrete implementation is built ON TOP OF CompletionService, so it
233
+ * lives in the embedding host and is injected DOWN into the serving core via
234
+ * `setVisionFallbackProvider` at bootstrap (instead of the core importing
235
+ * upward).
236
+ *
237
+ * @module completion/VisionFallbackProvider
238
+ */
239
+ /**
240
+ * Describe a batch of images as text using an auxiliary vision-capable model.
241
+ *
242
+ * @param images Image data URLs to describe (`{ data: 'data:<mime>;base64,…' }`).
243
+ * @param context Free-form context (the surrounding user message content).
244
+ * @param model The resolved vision aux ModelRef (`"providerId,modelId"`).
245
+ * @returns A textual description, or an empty / sentinel string when
246
+ * unavailable. Callers MUST tolerate `''` and
247
+ * `'[Image description unavailable]'`.
248
+ */
249
+ interface VisionFallbackProvider {
250
+ describeImages(images: {
251
+ data: string;
252
+ }[], context: string, model: string): Promise<string>;
253
+ }
254
+
255
+ /**
256
+ * CompletionService - Handles completion API calls
257
+ *
258
+ * This service provides a unified interface for making completion API calls
259
+ * to different providers, handling format conversion as needed.
260
+ * Supports transformer chains for advanced request/response transformation.
261
+ *
262
+ * This is a thin facade that delegates to domain-specific handlers:
263
+ * - DirectApiHandler: Non-streaming API calls (OpenAI, Anthropic, Gemini)
264
+ * - StreamHandler: SSE-based streaming (OpenAI, Anthropic, Gemini)
265
+ * - TransformerHandler: Transformer chain-based completion
266
+ * - ToolHandler: Agentic tool-calling loop
267
+ * - ThinkingResolver: Thinking budget and max tokens resolution
268
+ */
269
+
270
+ declare class CompletionService {
271
+ private paths;
272
+ private llmConfig;
273
+ private logger;
274
+ private apiKeyPool;
275
+ private usageRecorder;
276
+ private usageEventSink;
277
+ private visionFallbackProvider;
278
+ constructor(paths: CorePaths, llmConfig: ProviderConfigSource, logger: Logger);
279
+ /**
280
+ * Set the API key pool service for multi-key load balancing.
281
+ * When set, keys are resolved via the pool instead of directly from the provider.
282
+ */
283
+ setApiKeyPool(pool: ApiKeyPoolService): void;
284
+ /**
285
+ * Set the usage recorder so completion paths can persist token/cost stats.
286
+ * Optional — when unset, all calls succeed but nothing is recorded.
287
+ */
288
+ setUsageRecorder(recorder: UsageRecorderImport): void;
289
+ /**
290
+ * Set the usage-event sink so completion paths can push live usage events
291
+ * (context-meter, aggregate recorder) into the in-process hub. Injected DOWN
292
+ * at bootstrap with `getUsageEventHub()` immediately after construction, so
293
+ * emission is unconditional in production. Optional — when unset (unit-test
294
+ * constructors), the emit calls no-op, identical to `usageRecorder`.
295
+ */
296
+ setUsageEventSink(sink: UsageEventSink): void;
297
+ /**
298
+ * Set the vision-fallback provider used by `applyVisionFallback` to describe
299
+ * images for non-vision models. Injected DOWN by the host at bootstrap
300
+ * (the host's impl is built on top of CompletionService).
301
+ * Optional — when unset, `applyVisionFallback` strips images instead.
302
+ */
303
+ setVisionFallbackProvider(provider: VisionFallbackProvider): void;
304
+ /**
305
+ * Get provider by ID
306
+ * Delegates to the `ProviderConfigSource` which maintains its own in-memory cache.
307
+ */
308
+ getProvider(providerId: string): Promise<LLMProvider | null>;
309
+ /**
310
+ * Send a completion request
311
+ */
312
+ complete(options: CompletionOptions): Promise<CompletionResult>;
313
+ /**
314
+ * Send a streaming completion request
315
+ */
316
+ completeStream(options: CompletionOptions, callbacks: StreamCallbacks): Promise<void>;
317
+ /**
318
+ * Get available models for a provider
319
+ */
320
+ getAvailableModels(providerId: string): Promise<string[]>;
321
+ /**
322
+ * Test provider connection with a specific model.
323
+ * Sends "Hello" and returns the AI response, duration, etc.
324
+ */
325
+ testModel(providerId: string, modelId: string): Promise<{
326
+ success: boolean;
327
+ message: string;
328
+ response?: string;
329
+ model: string;
330
+ durationMs?: number;
331
+ }>;
332
+ /**
333
+ * Check if any messages contain images and the model lacks vision capability.
334
+ * If so, use the auxiliary vision model to describe images as text and remove
335
+ * the image attachments from the messages.
336
+ *
337
+ * Mutates options.messages in-place.
338
+ */
339
+ private applyVisionFallback;
340
+ /**
341
+ * Resolve API key for a request with priority:
342
+ * 1. Coding Plan override (if enabled)
343
+ * 2. API key pool (session-affinity weighted round-robin)
344
+ * 3. Legacy single key from provider config
345
+ */
346
+ private resolveApiKeyForRequest;
347
+ /**
348
+ * Extract HTTP status code from error messages like "API error (429): ..."
349
+ */
350
+ private extractHttpStatus;
351
+ /**
352
+ * Dispatch a non-streaming completion to the appropriate handler.
353
+ */
354
+ private callDirectHandler;
355
+ /**
356
+ * Dispatch a streaming completion to the appropriate handler.
357
+ */
358
+ private callStreamHandler;
359
+ /**
360
+ * Resolve API key (handle environment variable references)
361
+ */
362
+ resolveApiKey(apiKey: string): string;
363
+ /**
364
+ * Resolve effective max_tokens value with priority:
365
+ * 1. Session settings (if provided)
366
+ * 2. Global model parameters (if enabled)
367
+ * 3. Model's maxTokens from provider config
368
+ * 4. Discovered models cache (from API)
369
+ * 5. undefined - let API use its default
370
+ */
371
+ resolveEffectiveMaxTokens(providerId: string, modelId: string, sessionMaxTokens?: number): Promise<number | undefined>;
372
+ /**
373
+ * Get required max_tokens for providers that need it (e.g., Anthropic)
374
+ * Falls back to DEFAULT_MAX_TOKENS if no value is configured
375
+ */
376
+ getRequiredMaxTokens(providerId: string, modelId: string, sessionMaxTokens?: number): Promise<number>;
377
+ /**
378
+ * Calculate thinking budget and adjust max_tokens for the provider
379
+ */
380
+ resolveThinkingBudget(providerId: string, modelId: string, maxTokens: number, thinkLevel: ThinkLevel): Promise<{
381
+ adjustedMaxTokens: number;
382
+ thinkingBudget: number | undefined;
383
+ thinkingConfig: {
384
+ type?: 'enabled' | 'disabled';
385
+ budget_tokens?: number;
386
+ } | undefined;
387
+ }>;
388
+ /**
389
+ * Send a completion request using transformer chain
390
+ */
391
+ completeWithTransformers(options: CompletionOptions): Promise<CompletionResult>;
392
+ /**
393
+ * Send a streaming completion request using transformer chain
394
+ */
395
+ completeStreamWithTransformers(options: CompletionOptions, callbacks: StreamCallbacks): Promise<void>;
396
+ /**
397
+ * Stream completion with MCP tools support (direct API call)
398
+ * Implements agentic loop: calls LLM -> executes tools -> calls LLM again until done
399
+ */
400
+ streamWithTools(options: StreamWithToolsOptions, callbacks: StreamWithToolsCallbacks, mcpService?: McpToolProvider, builtinExecutor?: BuiltinToolExecutor): Promise<void>;
401
+ }
402
+
403
+ /**
404
+ * StreamEventBuffer — per-streamId event queue for streamed completion delivery.
405
+ *
406
+ * Closes the subscribe-vs-emit race between a producer that starts the LLM call
407
+ * asynchronously and a consumer that only attaches its listener after awaiting a
408
+ * reply. Events emitted before `attach(streamId)` is called are queued and
409
+ * replayed in order on attach.
410
+ */
411
+ /**
412
+ * Minimal structural sender — the subset of an Electron `WebContents` (or any
413
+ * IPC channel) this buffer actually uses. Kept LOCAL so core has zero electron
414
+ * dependency; the host passes any object satisfying this shape.
415
+ */
416
+ interface StreamSender {
417
+ isDestroyed(): boolean;
418
+ send(channel: string, payload: StreamEvent): void;
419
+ }
420
+ type StreamEventType = 'start' | 'delta' | 'reasoning' | 'tool_call' | 'tool_result' | 'tool_use' | 'block' | 'search_start' | 'search_result' | 'done' | 'error' | 'abort';
421
+ interface StreamEvent {
422
+ type: StreamEventType;
423
+ [key: string]: unknown;
424
+ }
425
+ /**
426
+ * Register a new stream. Called by the engine / handler immediately after the
427
+ * `streamId` is created, before any `emit`. Idempotent re-registration replaces
428
+ * the sender (covers the rare case of the engine retrying with the same id).
429
+ */
430
+ declare function register(streamId: string, sender: StreamSender): void;
431
+ /**
432
+ * Emit an event for `streamId`. Forwards directly if the client has attached;
433
+ * otherwise queues until `attach` is called. Bounded at QUEUE_CAP — overflow
434
+ * evicts the oldest non-terminal event.
435
+ */
436
+ declare function emit(streamId: string, event: StreamEvent): void;
437
+ /**
438
+ * The client announced readiness via the `completion:stream:subscribe` IPC. Drains
439
+ * the queue synchronously to the bound sender, then flips to direct-forward mode.
440
+ * Returns the number of events drained for diagnostic purposes.
441
+ */
442
+ declare function attach(streamId: string): {
443
+ ok: boolean;
444
+ drained: number;
445
+ };
446
+ /**
447
+ * Mark a stream finished. If the client has already attached, release
448
+ * synchronously. Otherwise defer one tick so a late `subscribe` arriving on the
449
+ * heels of the `done`/`error` event still drains the queue before cleanup.
450
+ */
451
+ declare function release(streamId: string): void;
452
+
453
+ /**
454
+ * API URL Building Utilities
455
+ *
456
+ * Functions for building correct API URLs based on provider format.
457
+ */
458
+
459
+ /**
460
+ * Resolve API format from provider configuration
461
+ *
462
+ * Priority:
463
+ * 1. apiFormat (v3 preferred field)
464
+ * 2. chatApiFormat (legacy v3 field)
465
+ * 3. apiType if it's an explicit format (claudecode/anthropic/google)
466
+ * 4. Default to openai
467
+ *
468
+ * Note: This enables implicit routing - the API format determines which
469
+ * transformer is automatically applied without explicit router configuration.
470
+ */
471
+ declare function resolveApiFormat(provider: LLMProvider): ApiFormat;
472
+ /**
473
+ * Build OpenAI Chat Completions API URL
474
+ * Handles various input formats:
475
+ * - https://api.openai.com → https://api.openai.com/v1/chat/completions
476
+ * - https://api.openai.com/v1/chat/completions → unchanged
477
+ * - https://api.deepseek.com/v1 → https://api.deepseek.com/v1/chat/completions
478
+ * - https://api.z.ai/api/coding/paas/v4 → https://api.z.ai/api/coding/paas/v4/chat/completions
479
+ */
480
+ declare function buildOpenAIApiUrl(baseUrl: string): string;
481
+ /**
482
+ * Build Anthropic Messages API URL
483
+ * Handles various input formats:
484
+ * - https://api.anthropic.com → https://api.anthropic.com/v1/messages
485
+ * - https://api.anthropic.com/v1/messages → unchanged
486
+ * - https://api.z.ai/api/anthropic → https://api.z.ai/api/anthropic/v1/messages
487
+ * - https://api.z.ai/api/anthropic/v2 → https://api.z.ai/api/anthropic/v2/messages
488
+ */
489
+ declare function buildAnthropicApiUrl(baseUrl: string): string;
490
+ /**
491
+ * Build Google Gemini API URL
492
+ * Gemini uses a dynamic URL structure: /v1beta/models/{model}:generateContent or :streamGenerateContent
493
+ * @param baseUrl - Base URL (e.g., https://generativelanguage.googleapis.com)
494
+ * @param model - Model name (e.g., gemini-2.0-flash)
495
+ * @param stream - Whether to use streaming endpoint
496
+ */
497
+ declare function buildGeminiApiUrl(baseUrl: string, model: string, stream: boolean): string;
498
+ /**
499
+ * Normalize Azure OpenAI endpoint
500
+ * Strips trailing /, /openai, /openai/v1 etc.
501
+ */
502
+ declare function normalizeAzureEndpoint(endpoint: string): string;
503
+ /**
504
+ * Build Azure OpenAI API URL
505
+ * Format: {endpoint}/openai/deployments/{deploymentName}/chat/completions?api-version={version}
506
+ * @param baseUrl - Azure endpoint (e.g., https://my-resource.openai.azure.com)
507
+ * @param model - Deployment name (used as model in Azure)
508
+ * @param apiVersion - API version (e.g., 2024-08-01-preview)
509
+ */
510
+ declare function buildAzureOpenAIApiUrl(baseUrl: string, model: string, apiVersion: string): string;
511
+ /**
512
+ * Build OpenAI Responses API URL
513
+ * Format: {baseUrl}/v1/responses
514
+ */
515
+ declare function buildOpenAIResponseApiUrl(baseUrl: string): string;
516
+
517
+ declare const resolveProviderEndpoint: typeof resolveProviderEndpoint$1;
518
+ /**
519
+ * Build API URL based on provider format and options
520
+ * This is the main entry point for URL building
521
+ */
522
+ declare function buildProviderApiUrl(provider: LLMProvider, options?: {
523
+ model?: string;
524
+ stream?: boolean;
525
+ }): string;
526
+
527
+ /**
528
+ * Request Header Building Utilities
529
+ *
530
+ * Functions for building correct request headers based on provider format.
531
+ */
532
+
533
+ /**
534
+ * Get request headers based on provider format
535
+ */
536
+ declare function getProviderHeaders(provider: LLMProvider, apiKey: string): Record<string, string>;
537
+
538
+ /**
539
+ * Message Format Conversion Utilities
540
+ *
541
+ * Functions for converting SimpleChatMessage to different API formats.
542
+ */
543
+
544
+ /**
545
+ * Convert SimpleChatMessage to OpenAI-compatible format (covers OpenAI, OpenRouter,
546
+ * and other OpenAI-compatible providers — DO NOT call from Anthropic / Gemini paths,
547
+ * which have their own converters above).
548
+ *
549
+ * - Text only: { role, content: string }
550
+ * - With media: { role, content: [{ type: "text" | "image_url" | "input_audio" | "video_url", ... }] }
551
+ *
552
+ * Audio is emitted as `input_audio` with base64 + format (the standard OpenAI / OpenRouter
553
+ * shape). Video is emitted as `video_url`: HTTPS URLs pass through; local data is sent as a
554
+ * `data:<mime>;base64,...` URL with a 25 MB cap before the request is even built.
555
+ */
556
+ declare function convertMessageToOpenAI(msg: SimpleChatMessage): OpenAIMessage;
557
+ /**
558
+ * Convert SimpleChatMessage to Anthropic format (with vision support)
559
+ * Anthropic format:
560
+ * - Text only: { role, content: string }
561
+ * - With images: { role, content: [{ type: "text", text: "..." }, { type: "image", source: { type: "base64", media_type: "...", data: "..." } }] }
562
+ */
563
+ declare function convertMessageToAnthropic(msg: SimpleChatMessage): AnthropicMessage;
564
+ /**
565
+ * Minimal Gemini part shape for the simple-chat DIRECT path (text + inline
566
+ * media only), serialized with the official REST JSON casing
567
+ * (`inlineData` / `mimeType`).
568
+ *
569
+ * NOT the same wire model as the transformer pipeline's full `GeminiPart`
570
+ * union in `transformer/transformers/utils/gemini.util.ts` (function calls /
571
+ * file data, snake_case alias keys). The two paths intentionally serialize
572
+ * differently — do not merge them blindly.
573
+ */
574
+ interface SimpleChatGeminiPart {
575
+ text?: string;
576
+ inlineData?: {
577
+ mimeType: string;
578
+ data: string;
579
+ };
580
+ }
581
+ /** Gemini message for the simple-chat direct path. */
582
+ interface SimpleChatGeminiMessage {
583
+ role: string;
584
+ parts: SimpleChatGeminiPart[];
585
+ }
586
+ /**
587
+ * Convert SimpleChatMessage to Gemini format (with vision support)
588
+ * Gemini format:
589
+ * - { role: "user"|"model", parts: [{ text: "..." }, { inlineData: { mimeType: "...", data: "..." } }] }
590
+ */
591
+ declare function convertMessageToGemini(msg: SimpleChatMessage): SimpleChatGeminiMessage;
592
+
593
+ /**
594
+ * OpenRouter Provider Utilities
595
+ *
596
+ * Functions for handling OpenRouter-specific configuration and routing.
597
+ */
598
+
599
+ /**
600
+ * Get OpenRouter provider routing config from model configuration
601
+ * Returns the provider routing config if the provider is OpenRouter and model has config
602
+ */
603
+ declare function getOpenRouterProviderConfig(provider: LLMProvider, modelId: string): OpenRouterProviderRouting | undefined;
604
+ /**
605
+ * Add OpenRouter provider routing to request body if applicable
606
+ */
607
+ declare function addOpenRouterProviderToRequest(requestBody: Record<string, unknown>, provider: LLMProvider, modelId: string): Record<string, unknown>;
608
+
609
+ /**
610
+ * Native Search Injector
611
+ *
612
+ * Detects provider-native web search support and builds request body
613
+ * augmentations for OpenAI, Anthropic, Google, xAI, and OpenRouter.
614
+ *
615
+ * This module does NOT execute searches — it only prepares the request
616
+ * so the LLM provider's server-side search runs automatically.
617
+ *
618
+ * @module completion/NativeSearchInjector
619
+ */
620
+
621
+ /**
622
+ * Detect whether a model supports provider-native web search.
623
+ *
624
+ * Detection order:
625
+ * 1. OpenRouter — detected by provider base URL, not model pattern.
626
+ * 2. xAI — detected by base URL containing `x.ai` or `grok`.
627
+ * 3. Model-pattern match against known providers (OpenAI, Anthropic, Google).
628
+ * 4. If `userExplicit` is true, fall back to API format mapping even
629
+ * when the model ID doesn't match known patterns (user opted-in).
630
+ */
631
+ declare function detectNativeSearch(modelId: string, apiFormat: ApiFormat, provider: LLMProvider, userExplicit?: boolean): NativeSearchDetectionResult;
632
+ /**
633
+ * Build a {@link NativeSearchAugmentation} for the given provider.
634
+ * Returns `null` if the provider is unknown or config is disabled.
635
+ */
636
+ declare function buildNativeSearchAugmentation(nativeProvider: NativeSearchProvider, config: NativeSearchUserConfig, _apiFormat: ApiFormat, modelId: string): NativeSearchAugmentation | null;
637
+ /**
638
+ * Merge an augmentation into the request body **in-place**.
639
+ *
640
+ * - `additionalTools` are appended to the existing `tools` array.
641
+ * - `bodyFields` are shallow-merged into the top-level body.
642
+ */
643
+ declare function applyAugmentation(requestBody: Record<string, unknown>, augmentation: NativeSearchAugmentation): Record<string, unknown>;
644
+
645
+ export { type AnthropicTool as A, BuiltinToolExecutor as B, type CompletionOptions as C, emit as D, getBuiltinSearchTools as E, getOpenRouterProviderConfig as F, type GeminiTools as G, getProviderHeaders as H, normalizeAzureEndpoint as I, register as J, release as K, resolveApiFormat as L, type McpToolProvider as M, NATIVE_SEARCH_TOOL_NAMES as N, type OpenAITool as O, resolveProviderEndpoint as P, type SimpleChatGeminiMessage as S, type VisionFallbackProvider as V, type ApiFormat as a, type CompletionResult as b, CompletionService as c, type NativeSearchAugmentation as d, type NativeSearchDetectionResult as e, type NativeSearchProvider as f, type NativeSearchUserConfig as g, type SimpleChatGeminiPart as h, type StreamCallbacks as i, type StreamEvent as j, type StreamEventType as k, type StreamSender as l, addOpenRouterProviderToRequest as m, applyAugmentation as n, attach as o, buildAnthropicApiUrl as p, buildAzureOpenAIApiUrl as q, buildGeminiApiUrl as r, buildNativeSearchAugmentation as s, buildOpenAIApiUrl as t, buildOpenAIResponseApiUrl as u, buildProviderApiUrl as v, convertMessageToAnthropic as w, convertMessageToGemini as x, convertMessageToOpenAI as y, detectNativeSearch as z };