@omnicross/core 0.1.0 → 0.1.2

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 (272) hide show
  1. package/dist/ApiConverter.cjs +24 -0
  2. package/dist/ApiConverter.d.cts +82 -0
  3. package/dist/ApiConverter.d.ts +82 -0
  4. package/dist/ApiConverter.js +24 -0
  5. package/dist/BuiltinToolExecutor-BluWyeob.d.ts +81 -0
  6. package/dist/BuiltinToolExecutor-CS2WpXhM.d.cts +81 -0
  7. package/dist/CompletionService-D3a47vdU.d.cts +213 -0
  8. package/dist/CompletionService-DdWaAxq0.d.ts +213 -0
  9. package/dist/{ProviderProxy-f_8ziIhW.d.cts → ProviderProxy-C-xqrkKi.d.ts} +7 -2
  10. package/dist/{ProviderProxy-vjt8sQQk.d.ts → ProviderProxy-CnMQYN59.d.cts} +7 -2
  11. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +27 -60
  12. package/dist/auth/GeminiCodeAssistProjectResolver.js +5 -9
  13. package/dist/builtin-web-fetch-77JZUZGM.cjs +100 -0
  14. package/dist/builtin-web-fetch-IGLBX2XY.js +100 -0
  15. package/dist/chunk-2DCNB7DF.cjs +514 -0
  16. package/dist/chunk-2FEVTJWG.js +4400 -0
  17. package/dist/chunk-3MEACFK3.js +193 -0
  18. package/dist/chunk-3OPYJG76.cjs +266 -0
  19. package/dist/chunk-46RLHI7D.js +0 -0
  20. package/dist/chunk-46ZIFWYG.cjs +277 -0
  21. package/dist/chunk-4NBS6KPV.cjs +43 -0
  22. package/dist/chunk-4VAVYUZS.cjs +991 -0
  23. package/dist/chunk-5ERIZW3D.js +44 -0
  24. package/dist/chunk-5HTVET6E.js +514 -0
  25. package/dist/chunk-5ZQBEOMD.js +764 -0
  26. package/dist/chunk-6VIXXLMX.cjs +14 -0
  27. package/dist/chunk-745DV5FL.js +147 -0
  28. package/dist/chunk-74TMJA7Z.js +53 -0
  29. package/dist/chunk-7VU7V2E4.js +0 -0
  30. package/dist/chunk-7YN22L2H.cjs +87 -0
  31. package/dist/chunk-A2YMUCBT.cjs +105 -0
  32. package/dist/chunk-AQ5TNQB7.js +13 -0
  33. package/dist/chunk-AVYJ4YBN.js +58 -0
  34. package/dist/chunk-C72S6TTV.cjs +49 -0
  35. package/dist/chunk-C7PSERMH.js +87 -0
  36. package/dist/chunk-CDHS2QDC.js +179 -0
  37. package/dist/chunk-DK4A7DLE.js +266 -0
  38. package/dist/chunk-DRWHTIIZ.js +13 -0
  39. package/dist/chunk-DWKQZ2SK.cjs +254 -0
  40. package/dist/chunk-E3WHL7CO.js +14 -0
  41. package/dist/chunk-EYZYXJTJ.cjs +1 -0
  42. package/dist/chunk-FMOBD2OQ.js +39 -0
  43. package/dist/chunk-FTQ7IQUC.js +991 -0
  44. package/dist/chunk-FZ46M34D.cjs +1 -0
  45. package/dist/chunk-G2FUJNA2.cjs +193 -0
  46. package/dist/chunk-G2UTNSGU.js +277 -0
  47. package/dist/chunk-GBHYAGX3.cjs +26 -0
  48. package/dist/chunk-GMMT7RVN.cjs +39 -0
  49. package/dist/chunk-H5JUT3KV.js +105 -0
  50. package/dist/chunk-HQP3K7PU.cjs +431 -0
  51. package/dist/chunk-JO5NLTLY.js +46 -0
  52. package/dist/chunk-JWC6APFQ.js +23 -0
  53. package/dist/chunk-KUU2RNG6.cjs +46 -0
  54. package/dist/chunk-LKZJEL6E.cjs +124 -0
  55. package/dist/chunk-MNYKI4CI.js +94 -0
  56. package/dist/chunk-MZNPGW5Q.js +26 -0
  57. package/dist/chunk-N3V2J5ZO.cjs +53 -0
  58. package/dist/chunk-NYUNU75A.cjs +44 -0
  59. package/dist/chunk-NZYN7C3P.cjs +179 -0
  60. package/dist/chunk-O466Y272.js +235 -0
  61. package/dist/chunk-PXUJF5HS.js +124 -0
  62. package/dist/chunk-QBZJ7P2T.cjs +13 -0
  63. package/dist/chunk-QOCNX236.js +46 -0
  64. package/dist/chunk-QXD4MV2X.cjs +23 -0
  65. package/dist/chunk-R3HK6R4B.cjs +13 -0
  66. package/dist/chunk-RSJ3TWJQ.cjs +186 -0
  67. package/dist/chunk-S4WBV25P.js +913 -0
  68. package/dist/chunk-SN3YWBX7.cjs +4400 -0
  69. package/dist/chunk-SPVWWUHX.cjs +46 -0
  70. package/dist/chunk-SUEGJ75D.cjs +764 -0
  71. package/dist/chunk-SVNDB62D.cjs +58 -0
  72. package/dist/chunk-UYPEN5XE.cjs +235 -0
  73. package/dist/chunk-V5KPWNYX.cjs +147 -0
  74. package/dist/chunk-VVEHS2LI.js +431 -0
  75. package/dist/chunk-XBSYYZIY.cjs +94 -0
  76. package/dist/chunk-YGXJGRFI.cjs +913 -0
  77. package/dist/chunk-YMFAJFQT.cjs +173 -0
  78. package/dist/chunk-Z7LUNECE.js +49 -0
  79. package/dist/chunk-Z7Y2NPHY.js +186 -0
  80. package/dist/chunk-ZJZAOKI7.js +254 -0
  81. package/dist/chunk-ZLX3KGXX.js +173 -0
  82. package/dist/chunk-ZSVQT3PW.js +43 -0
  83. package/dist/completion/ApiKeyPoolService.cjs +23 -48
  84. package/dist/completion/ApiKeyPoolService.d.cts +150 -2
  85. package/dist/completion/ApiKeyPoolService.d.ts +150 -2
  86. package/dist/completion/BuiltinToolExecutor.cjs +12 -0
  87. package/dist/completion/BuiltinToolExecutor.d.cts +4 -0
  88. package/dist/completion/BuiltinToolExecutor.d.ts +4 -0
  89. package/dist/completion/BuiltinToolExecutor.js +12 -0
  90. package/dist/completion/CompletionService.cjs +38 -0
  91. package/dist/completion/CompletionService.d.cts +22 -0
  92. package/dist/completion/CompletionService.d.ts +22 -0
  93. package/dist/completion/CompletionService.js +38 -0
  94. package/dist/completion/NativeSearchInjector.cjs +12 -0
  95. package/dist/completion/NativeSearchInjector.d.cts +42 -0
  96. package/dist/completion/NativeSearchInjector.d.ts +42 -0
  97. package/dist/completion/NativeSearchInjector.js +12 -0
  98. package/dist/completion/ProviderSearchInjector.cjs +60 -0
  99. package/dist/completion/ProviderSearchInjector.d.cts +47 -0
  100. package/dist/completion/ProviderSearchInjector.d.ts +47 -0
  101. package/dist/completion/ProviderSearchInjector.js +60 -0
  102. package/dist/completion/native-search-types.cjs +14 -0
  103. package/dist/completion/native-search-types.d.cts +3 -0
  104. package/dist/completion/native-search-types.d.ts +3 -0
  105. package/dist/completion/native-search-types.js +14 -0
  106. package/dist/completion/openrouter-headers.cjs +16 -0
  107. package/dist/completion/openrouter-headers.d.cts +44 -0
  108. package/dist/completion/openrouter-headers.d.ts +44 -0
  109. package/dist/completion/openrouter-headers.js +16 -0
  110. package/dist/completion/openrouter-models.cjs +29 -0
  111. package/dist/completion/openrouter-models.d.cts +27 -0
  112. package/dist/completion/openrouter-models.d.ts +27 -0
  113. package/dist/completion/openrouter-models.js +29 -0
  114. package/dist/completion/types.cjs +1 -0
  115. package/dist/completion/types.d.cts +3 -0
  116. package/dist/completion/types.d.ts +3 -0
  117. package/dist/completion/types.js +0 -0
  118. package/dist/completion/url-builder.cjs +24 -0
  119. package/dist/completion/url-builder.d.cts +87 -0
  120. package/dist/completion/url-builder.d.ts +87 -0
  121. package/dist/completion/url-builder.js +24 -0
  122. package/dist/completion.cjs +55 -3989
  123. package/dist/completion.d.cts +150 -8
  124. package/dist/completion.d.ts +150 -8
  125. package/dist/completion.js +63 -3953
  126. package/dist/index.cjs +197 -10428
  127. package/dist/index.d.cts +35 -91
  128. package/dist/index.d.ts +35 -91
  129. package/dist/index.js +125 -10267
  130. package/dist/logger-4GvQNzhE.d.cts +22 -0
  131. package/dist/logger-4GvQNzhE.d.ts +22 -0
  132. package/dist/outbound-api/routeResolver.cjs +11 -0
  133. package/dist/outbound-api/routeResolver.d.cts +19 -0
  134. package/dist/outbound-api/routeResolver.d.ts +19 -0
  135. package/dist/outbound-api/routeResolver.js +11 -0
  136. package/dist/outbound-api/subscriptionRegistryPort.cjs +7 -37
  137. package/dist/outbound-api/subscriptionRegistryPort.d.cts +7 -3
  138. package/dist/outbound-api/subscriptionRegistryPort.d.ts +7 -3
  139. package/dist/outbound-api/subscriptionRegistryPort.js +4 -8
  140. package/dist/outbound-api/types.cjs +1 -0
  141. package/dist/{types-CbCN2NQP.d.ts → outbound-api/types.d.cts} +18 -3
  142. package/dist/{types-CGGrKqC_.d.cts → outbound-api/types.d.ts} +18 -3
  143. package/dist/outbound-api/types.js +0 -0
  144. package/dist/outbound-api.cjs +35 -5220
  145. package/dist/outbound-api.d.cts +16 -88
  146. package/dist/outbound-api.d.ts +16 -88
  147. package/dist/outbound-api.js +54 -5193
  148. package/dist/pipeline/AuthSource.cjs +1 -0
  149. package/dist/pipeline/AuthSource.d.cts +101 -0
  150. package/dist/pipeline/AuthSource.d.ts +101 -0
  151. package/dist/pipeline/AuthSource.js +0 -0
  152. package/dist/pipeline/LlmConfigProviderAuth.cjs +8 -0
  153. package/dist/pipeline/LlmConfigProviderAuth.d.cts +87 -0
  154. package/dist/pipeline/LlmConfigProviderAuth.d.ts +87 -0
  155. package/dist/pipeline/LlmConfigProviderAuth.js +8 -0
  156. package/dist/pipeline/SubscriptionAuthSource.cjs +6 -128
  157. package/dist/pipeline/SubscriptionAuthSource.d.cts +165 -3
  158. package/dist/pipeline/SubscriptionAuthSource.d.ts +165 -3
  159. package/dist/pipeline/SubscriptionAuthSource.js +5 -99
  160. package/dist/pipeline/SubscriptionAuthStrategy.cjs +1 -18
  161. package/dist/pipeline/executeProviderCall.cjs +6 -0
  162. package/dist/pipeline/executeProviderCall.d.cts +149 -0
  163. package/dist/pipeline/executeProviderCall.d.ts +149 -0
  164. package/dist/pipeline/executeProviderCall.js +6 -0
  165. package/dist/pipeline/resolveProviderChain.cjs +6 -0
  166. package/dist/pipeline/resolveProviderChain.d.cts +58 -0
  167. package/dist/pipeline/resolveProviderChain.d.ts +58 -0
  168. package/dist/pipeline/resolveProviderChain.js +6 -0
  169. package/dist/pipeline/resolveSubscriptionChain.cjs +6 -0
  170. package/dist/pipeline/resolveSubscriptionChain.d.cts +68 -0
  171. package/dist/pipeline/resolveSubscriptionChain.d.ts +68 -0
  172. package/dist/pipeline/resolveSubscriptionChain.js +6 -0
  173. package/dist/ports/gemini-code-assist-resolver.cjs +7 -37
  174. package/dist/ports/gemini-code-assist-resolver.js +4 -8
  175. package/dist/ports/pricing-store.cjs +1 -0
  176. package/dist/ports/pricing-store.d.cts +50 -0
  177. package/dist/ports/pricing-store.d.ts +50 -0
  178. package/dist/ports/pricing-store.js +0 -0
  179. package/dist/ports/provider-config-source.cjs +1 -0
  180. package/dist/ports/provider-config-source.d.cts +51 -0
  181. package/dist/ports/provider-config-source.d.ts +51 -0
  182. package/dist/ports/provider-config-source.js +0 -0
  183. package/dist/ports/usage-event-store.cjs +1 -0
  184. package/dist/ports/usage-event-store.d.cts +29 -0
  185. package/dist/ports/usage-event-store.d.ts +29 -0
  186. package/dist/ports/usage-event-store.js +0 -0
  187. package/dist/ports/web-search-backend.cjs +1 -0
  188. package/dist/ports/web-search-backend.d.cts +29 -0
  189. package/dist/ports/web-search-backend.d.ts +29 -0
  190. package/dist/ports/web-search-backend.js +0 -0
  191. package/dist/ports.cjs +1 -18
  192. package/dist/ports.d.cts +16 -8
  193. package/dist/ports.d.ts +16 -8
  194. package/dist/provider-proxy/ProviderProxy.cjs +40 -0
  195. package/dist/provider-proxy/ProviderProxy.d.cts +17 -0
  196. package/dist/provider-proxy/ProviderProxy.d.ts +17 -0
  197. package/dist/provider-proxy/ProviderProxy.js +40 -0
  198. package/dist/provider-proxy/ingress/providerProxyShared.cjs +35 -2941
  199. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +7 -3
  200. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +7 -3
  201. package/dist/provider-proxy/ingress/providerProxyShared.js +41 -2914
  202. package/dist/provider-proxy/matchText.cjs +11 -72
  203. package/dist/provider-proxy/matchText.js +6 -39
  204. package/dist/provider-proxy/types.cjs +1 -18
  205. package/dist/provider-proxy/types.d.cts +407 -8
  206. package/dist/provider-proxy/types.d.ts +407 -8
  207. package/dist/provider-proxy.cjs +35 -4654
  208. package/dist/provider-proxy.d.cts +10 -6
  209. package/dist/provider-proxy.d.ts +10 -6
  210. package/dist/provider-proxy.js +39 -4627
  211. package/dist/routeResolver-BrbK6ja9.d.cts +88 -0
  212. package/dist/routeResolver-HE-ZO0fO.d.ts +88 -0
  213. package/dist/serializeError.cjs +5 -81
  214. package/dist/serializeError.js +3 -54
  215. package/dist/sse-parser.cjs +7 -455
  216. package/dist/sse-parser.js +4 -426
  217. package/dist/transformer/TransformerChainExecutor.cjs +4 -318
  218. package/dist/transformer/TransformerChainExecutor.js +4 -291
  219. package/dist/transformer/TransformerService.cjs +5 -289
  220. package/dist/transformer/TransformerService.js +3 -262
  221. package/dist/transformer/anthropicBetaInject.cjs +8 -0
  222. package/dist/transformer/anthropicBetaInject.d.cts +20 -0
  223. package/dist/transformer/anthropicBetaInject.d.ts +20 -0
  224. package/dist/transformer/anthropicBetaInject.js +8 -0
  225. package/dist/transformer/transformers/AnthropicTransformer.cjs +6 -0
  226. package/dist/transformer/transformers/AnthropicTransformer.d.cts +148 -0
  227. package/dist/transformer/transformers/AnthropicTransformer.d.ts +148 -0
  228. package/dist/transformer/transformers/AnthropicTransformer.js +6 -0
  229. package/dist/transformer/transformers/GeminiCodeAssistTransformer.cjs +4 -1106
  230. package/dist/transformer/transformers/GeminiCodeAssistTransformer.js +7 -1079
  231. package/dist/transformer/transformers/GeminiTransformer.cjs +4 -1010
  232. package/dist/transformer/transformers/GeminiTransformer.js +4 -983
  233. package/dist/transformer/transformers/OpenAIResponseTransformer.cjs +3 -535
  234. package/dist/transformer/transformers/OpenAIResponseTransformer.js +3 -510
  235. package/dist/transformer/transformers/OpenCodeGoTransformer.cjs +5 -72
  236. package/dist/transformer/transformers/OpenCodeGoTransformer.js +3 -45
  237. package/dist/transformer/transformers/ReasoningTransformer.cjs +6 -0
  238. package/dist/transformer/transformers/ReasoningTransformer.d.cts +47 -0
  239. package/dist/transformer/transformers/ReasoningTransformer.d.ts +47 -0
  240. package/dist/transformer/transformers/ReasoningTransformer.js +6 -0
  241. package/dist/transformer/transformers.cjs +39 -0
  242. package/dist/transformer/transformers.d.cts +100 -0
  243. package/dist/transformer/transformers.d.ts +100 -0
  244. package/dist/transformer/transformers.js +39 -0
  245. package/dist/transformer/types.cjs +1 -18
  246. package/dist/transformer.cjs +13 -3726
  247. package/dist/transformer.d.cts +8 -31
  248. package/dist/transformer.d.ts +8 -31
  249. package/dist/transformer.js +17 -3706
  250. package/dist/types-BScIHmPr.d.cts +153 -0
  251. package/dist/types-BScIHmPr.d.ts +153 -0
  252. package/dist/usage/pricing-engine.cjs +6 -0
  253. package/dist/usage/pricing-engine.d.cts +83 -0
  254. package/dist/usage/pricing-engine.d.ts +83 -0
  255. package/dist/usage/pricing-engine.js +6 -0
  256. package/dist/usage/usage-recorder.cjs +6 -0
  257. package/dist/usage/usage-recorder.d.cts +73 -0
  258. package/dist/usage/usage-recorder.d.ts +73 -0
  259. package/dist/usage/usage-recorder.js +6 -0
  260. package/dist/usage.cjs +11 -0
  261. package/dist/usage.d.cts +8 -0
  262. package/dist/usage.d.ts +8 -0
  263. package/dist/usage.js +11 -0
  264. package/package.json +3 -3
  265. package/dist/ApiKeyPoolService-BmMkau07.d.cts +0 -170
  266. package/dist/ApiKeyPoolService-BmMkau07.d.ts +0 -170
  267. package/dist/SubscriptionAuthSource-Cr4fVEYY.d.cts +0 -264
  268. package/dist/SubscriptionAuthSource-D89zmiSS.d.ts +0 -264
  269. package/dist/index-BTSmc9Sm.d.ts +0 -645
  270. package/dist/index-DXazdTzZ.d.cts +0 -645
  271. package/dist/types-DCzHkhJt.d.ts +0 -467
  272. package/dist/types-DZIQbgp0.d.cts +0 -467
@@ -0,0 +1,213 @@
1
+ import { ThinkLevel } from '@omnicross/contracts/completion-types';
2
+ import { LLMProvider } from '@omnicross/contracts/llm-config';
3
+ import { C as CorePaths, U as UsageEventSink } from './usage-event-sink-BX7FE1NL.js';
4
+ import { L as Logger } from './logger-4GvQNzhE.js';
5
+ import { ProviderConfigSource } from './ports/provider-config-source.js';
6
+ import { UsageRecorderImport } from './provider-proxy/types.js';
7
+ import { O as OpenAITool, A as AnthropicTool, G as GeminiTools, M as McpToolProvider, B as BuiltinToolExecutor } from './BuiltinToolExecutor-BluWyeob.js';
8
+ import { C as CompletionOptions, S as StreamCallbacks, a as CompletionResult } from './types-BScIHmPr.js';
9
+ import { ApiKeyPoolService } from './completion/ApiKeyPoolService.js';
10
+ import { MCPTool } from '@omnicross/contracts/mcp-types';
11
+
12
+ /**
13
+ * VisionFallbackProvider — serving-core port for image-to-text fallback.
14
+ *
15
+ * When the active completion model lacks vision capability but a message
16
+ * carries images, `CompletionService.applyVisionFallback` delegates to this
17
+ * port to turn the images into a text description (which is then appended to
18
+ * the message content) before stripping the image attachments.
19
+ *
20
+ * The concrete implementation is built ON TOP OF CompletionService, so it
21
+ * lives in the embedding host and is injected DOWN into the serving core via
22
+ * `setVisionFallbackProvider` at bootstrap (instead of the core importing
23
+ * upward).
24
+ *
25
+ * @module completion/VisionFallbackProvider
26
+ */
27
+ /**
28
+ * Describe a batch of images as text using an auxiliary vision-capable model.
29
+ *
30
+ * @param images Image data URLs to describe (`{ data: 'data:<mime>;base64,…' }`).
31
+ * @param context Free-form context (the surrounding user message content).
32
+ * @param model The resolved vision aux ModelRef (`"providerId,modelId"`).
33
+ * @returns A textual description, or an empty / sentinel string when
34
+ * unavailable. Callers MUST tolerate `''` and
35
+ * `'[Image description unavailable]'`.
36
+ */
37
+ interface VisionFallbackProvider {
38
+ describeImages(images: {
39
+ data: string;
40
+ }[], context: string, model: string): Promise<string>;
41
+ }
42
+
43
+ /**
44
+ * ToolHandler - Handles streaming completion with MCP tool support
45
+ *
46
+ * Extracted from CompletionService to isolate the agentic loop logic
47
+ * that handles tool calls: LLM -> execute tools -> LLM again until done.
48
+ */
49
+
50
+ /** Extended options for tool-based completion */
51
+ interface StreamWithToolsOptions extends CompletionOptions {
52
+ tools: OpenAITool[] | AnthropicTool[] | GeminiTools;
53
+ mcpTools?: MCPTool[];
54
+ }
55
+ /** Extended callbacks for tool-based completion */
56
+ interface StreamWithToolsCallbacks extends StreamCallbacks {
57
+ onToolCall?: (toolCall: {
58
+ id: string;
59
+ name: string;
60
+ args: unknown;
61
+ }) => void;
62
+ onToolResult?: (toolId: string, result: unknown) => void;
63
+ }
64
+
65
+ /**
66
+ * CompletionService - Handles completion API calls
67
+ *
68
+ * This service provides a unified interface for making completion API calls
69
+ * to different providers, handling format conversion as needed.
70
+ * Supports transformer chains for advanced request/response transformation.
71
+ *
72
+ * This is a thin facade that delegates to domain-specific handlers:
73
+ * - DirectApiHandler: Non-streaming API calls (OpenAI, Anthropic, Gemini)
74
+ * - StreamHandler: SSE-based streaming (OpenAI, Anthropic, Gemini)
75
+ * - TransformerHandler: Transformer chain-based completion
76
+ * - ToolHandler: Agentic tool-calling loop
77
+ * - ThinkingResolver: Thinking budget and max tokens resolution
78
+ */
79
+
80
+ declare class CompletionService {
81
+ private paths;
82
+ private llmConfig;
83
+ private logger;
84
+ private apiKeyPool;
85
+ private usageRecorder;
86
+ private usageEventSink;
87
+ private visionFallbackProvider;
88
+ constructor(paths: CorePaths, llmConfig: ProviderConfigSource, logger: Logger);
89
+ /**
90
+ * Set the API key pool service for multi-key load balancing.
91
+ * When set, keys are resolved via the pool instead of directly from the provider.
92
+ */
93
+ setApiKeyPool(pool: ApiKeyPoolService): void;
94
+ /**
95
+ * Set the usage recorder so completion paths can persist token/cost stats.
96
+ * Optional — when unset, all calls succeed but nothing is recorded.
97
+ */
98
+ setUsageRecorder(recorder: UsageRecorderImport): void;
99
+ /**
100
+ * Set the usage-event sink so completion paths can push live usage events
101
+ * (context-meter, aggregate recorder) into the in-process hub. Injected DOWN
102
+ * at bootstrap with `getUsageEventHub()` immediately after construction, so
103
+ * emission is unconditional in production. Optional — when unset (unit-test
104
+ * constructors), the emit calls no-op, identical to `usageRecorder`.
105
+ */
106
+ setUsageEventSink(sink: UsageEventSink): void;
107
+ /**
108
+ * Set the vision-fallback provider used by `applyVisionFallback` to describe
109
+ * images for non-vision models. Injected DOWN by the host at bootstrap
110
+ * (the host's impl is built on top of CompletionService).
111
+ * Optional — when unset, `applyVisionFallback` strips images instead.
112
+ */
113
+ setVisionFallbackProvider(provider: VisionFallbackProvider): void;
114
+ /**
115
+ * Get provider by ID
116
+ * Delegates to the `ProviderConfigSource` which maintains its own in-memory cache.
117
+ */
118
+ getProvider(providerId: string): Promise<LLMProvider | null>;
119
+ /**
120
+ * Send a completion request
121
+ */
122
+ complete(options: CompletionOptions): Promise<CompletionResult>;
123
+ /**
124
+ * Send a streaming completion request
125
+ */
126
+ completeStream(options: CompletionOptions, callbacks: StreamCallbacks): Promise<void>;
127
+ /**
128
+ * Get available models for a provider
129
+ */
130
+ getAvailableModels(providerId: string): Promise<string[]>;
131
+ /**
132
+ * Test provider connection with a specific model.
133
+ * Sends "Hello" and returns the AI response, duration, etc.
134
+ */
135
+ testModel(providerId: string, modelId: string): Promise<{
136
+ success: boolean;
137
+ message: string;
138
+ response?: string;
139
+ model: string;
140
+ durationMs?: number;
141
+ }>;
142
+ /**
143
+ * Check if any messages contain images and the model lacks vision capability.
144
+ * If so, use the auxiliary vision model to describe images as text and remove
145
+ * the image attachments from the messages.
146
+ *
147
+ * Mutates options.messages in-place.
148
+ */
149
+ private applyVisionFallback;
150
+ /**
151
+ * Resolve API key for a request with priority:
152
+ * 1. Coding Plan override (if enabled)
153
+ * 2. API key pool (session-affinity weighted round-robin)
154
+ * 3. Legacy single key from provider config
155
+ */
156
+ private resolveApiKeyForRequest;
157
+ /**
158
+ * Extract HTTP status code from error messages like "API error (429): ..."
159
+ */
160
+ private extractHttpStatus;
161
+ /**
162
+ * Dispatch a non-streaming completion to the appropriate handler.
163
+ */
164
+ private callDirectHandler;
165
+ /**
166
+ * Dispatch a streaming completion to the appropriate handler.
167
+ */
168
+ private callStreamHandler;
169
+ /**
170
+ * Resolve API key (handle environment variable references)
171
+ */
172
+ resolveApiKey(apiKey: string): string;
173
+ /**
174
+ * Resolve effective max_tokens value with priority:
175
+ * 1. Session settings (if provided)
176
+ * 2. Global model parameters (if enabled)
177
+ * 3. Model's maxTokens from provider config
178
+ * 4. Discovered models cache (from API)
179
+ * 5. undefined - let API use its default
180
+ */
181
+ resolveEffectiveMaxTokens(providerId: string, modelId: string, sessionMaxTokens?: number): Promise<number | undefined>;
182
+ /**
183
+ * Get required max_tokens for providers that need it (e.g., Anthropic)
184
+ * Falls back to DEFAULT_MAX_TOKENS if no value is configured
185
+ */
186
+ getRequiredMaxTokens(providerId: string, modelId: string, sessionMaxTokens?: number): Promise<number>;
187
+ /**
188
+ * Calculate thinking budget and adjust max_tokens for the provider
189
+ */
190
+ resolveThinkingBudget(providerId: string, modelId: string, maxTokens: number, thinkLevel: ThinkLevel): Promise<{
191
+ adjustedMaxTokens: number;
192
+ thinkingBudget: number | undefined;
193
+ thinkingConfig: {
194
+ type?: 'enabled' | 'disabled';
195
+ budget_tokens?: number;
196
+ } | undefined;
197
+ }>;
198
+ /**
199
+ * Send a completion request using transformer chain
200
+ */
201
+ completeWithTransformers(options: CompletionOptions): Promise<CompletionResult>;
202
+ /**
203
+ * Send a streaming completion request using transformer chain
204
+ */
205
+ completeStreamWithTransformers(options: CompletionOptions, callbacks: StreamCallbacks): Promise<void>;
206
+ /**
207
+ * Stream completion with MCP tools support (direct API call)
208
+ * Implements agentic loop: calls LLM -> executes tools -> calls LLM again until done
209
+ */
210
+ streamWithTools(options: StreamWithToolsOptions, callbacks: StreamWithToolsCallbacks, mcpService?: McpToolProvider, builtinExecutor?: BuiltinToolExecutor): Promise<void>;
211
+ }
212
+
213
+ export { CompletionService as C, type VisionFallbackProvider as V };
@@ -1,4 +1,4 @@
1
- import { g as RouteContext, a as ProviderProxyDeps } from './types-DZIQbgp0.cjs';
1
+ import { RouteContext, ProviderProxyDeps } from './provider-proxy/types.js';
2
2
 
3
3
  /**
4
4
  * ProviderProxyRouteMap — the per-run `Map<token, RouteContext>` with crypto
@@ -82,6 +82,11 @@ declare class ProviderProxyRouteMap {
82
82
  * @module provider-proxy/ProviderProxy
83
83
  */
84
84
 
85
+ /**
86
+ * True for IPv4/IPv6 loopback peer addresses. Exported so the isolation gate
87
+ * ("the listener refuses non-loopback origins") can be unit-asserted.
88
+ */
89
+ declare function isLoopbackAddress(addr: string | undefined): boolean;
85
90
  declare class ProviderProxy {
86
91
  private readonly deps;
87
92
  private server;
@@ -117,4 +122,4 @@ declare class ProviderProxy {
117
122
  routeCount(): number;
118
123
  }
119
124
 
120
- export { DEFAULT_ROUTE_IDLE_MS as D, ProviderProxy as P, ProviderProxyRouteMap as a };
125
+ export { DEFAULT_ROUTE_IDLE_MS as D, ProviderProxy as P, ProviderProxyRouteMap as a, isLoopbackAddress as i };
@@ -1,4 +1,4 @@
1
- import { g as RouteContext, a as ProviderProxyDeps } from './types-DCzHkhJt.js';
1
+ import { RouteContext, ProviderProxyDeps } from './provider-proxy/types.cjs';
2
2
 
3
3
  /**
4
4
  * ProviderProxyRouteMap — the per-run `Map<token, RouteContext>` with crypto
@@ -82,6 +82,11 @@ declare class ProviderProxyRouteMap {
82
82
  * @module provider-proxy/ProviderProxy
83
83
  */
84
84
 
85
+ /**
86
+ * True for IPv4/IPv6 loopback peer addresses. Exported so the isolation gate
87
+ * ("the listener refuses non-loopback origins") can be unit-asserted.
88
+ */
89
+ declare function isLoopbackAddress(addr: string | undefined): boolean;
85
90
  declare class ProviderProxy {
86
91
  private readonly deps;
87
92
  private server;
@@ -117,4 +122,4 @@ declare class ProviderProxy {
117
122
  routeCount(): number;
118
123
  }
119
124
 
120
- export { DEFAULT_ROUTE_IDLE_MS as D, ProviderProxy as P, ProviderProxyRouteMap as a };
125
+ export { DEFAULT_ROUTE_IDLE_MS as D, ProviderProxy as P, ProviderProxyRouteMap as a, isLoopbackAddress as i };
@@ -1,40 +1,8 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
19
2
 
20
- // src/auth/GeminiCodeAssistProjectResolver.ts
21
- var GeminiCodeAssistProjectResolver_exports = {};
22
- __export(GeminiCodeAssistProjectResolver_exports, {
23
- GeminiCodeAssistHandshakeError: () => GeminiCodeAssistHandshakeError,
24
- GeminiCodeAssistProjectResolver: () => GeminiCodeAssistProjectResolver,
25
- getGeminiCodeAssistProjectResolver: () => getGeminiCodeAssistProjectResolver
26
- });
27
- module.exports = __toCommonJS(GeminiCodeAssistProjectResolver_exports);
28
3
 
29
- // src/transformer/transformers/GeminiCodeAssistTransformer.ts
30
- var DEFAULT_CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
31
- var DEFAULT_CODE_ASSIST_API_VERSION = "v1internal";
32
- function resolveCodeAssistEndpoint() {
33
- return (process.env.CODE_ASSIST_ENDPOINT || DEFAULT_CODE_ASSIST_ENDPOINT).replace(/\/+$/, "");
34
- }
35
- function resolveCodeAssistApiVersion() {
36
- return process.env.CODE_ASSIST_API_VERSION || DEFAULT_CODE_ASSIST_API_VERSION;
37
- }
4
+ var _chunkRSJ3TWJQcjs = require('../chunk-RSJ3TWJQ.cjs');
5
+ require('../chunk-YGXJGRFI.cjs');
38
6
 
39
7
  // src/auth/GeminiCodeAssistProjectResolver.ts
40
8
  var FREE_TIER_ID = "free-tier";
@@ -48,18 +16,18 @@ var GeminiCodeAssistHandshakeError = class extends Error {
48
16
  this.code = code;
49
17
  this.name = "GeminiCodeAssistHandshakeError";
50
18
  }
51
- status;
52
- code;
19
+
20
+
53
21
  };
54
- var GeminiCodeAssistProjectResolver = class {
55
- constructor(fetchImpl = (url, init) => fetch(url, init)) {
22
+ var GeminiCodeAssistProjectResolver = (_class = class {
23
+ constructor(fetchImpl = (url, init) => fetch(url, init)) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
56
24
  this.fetchImpl = fetchImpl;
57
25
  }
58
- fetchImpl;
26
+
59
27
  /** account access token → resolved project id (undefined = free-tier, no project). */
60
- cache = /* @__PURE__ */ new Map();
28
+ __init() {this.cache = /* @__PURE__ */ new Map()}
61
29
  /** In-flight handshakes so concurrent callers share one round-trip. */
62
- inflight = /* @__PURE__ */ new Map();
30
+ __init2() {this.inflight = /* @__PURE__ */ new Map()}
63
31
  /** Test/diagnostic helper — clear the cached resolution for an account. */
64
32
  clearCache() {
65
33
  this.cache.clear();
@@ -86,7 +54,7 @@ var GeminiCodeAssistProjectResolver = class {
86
54
  return run;
87
55
  }
88
56
  codeAssistUrl(method) {
89
- return `${resolveCodeAssistEndpoint()}/${resolveCodeAssistApiVersion()}:${method}`;
57
+ return `${_chunkRSJ3TWJQcjs.resolveCodeAssistEndpoint.call(void 0, )}/${_chunkRSJ3TWJQcjs.resolveCodeAssistApiVersion.call(void 0, )}:${method}`;
90
58
  }
91
59
  /** Seed project id from env; reject a purely-numeric value (project NUMBER). */
92
60
  seedProjectId() {
@@ -105,11 +73,11 @@ var GeminiCodeAssistProjectResolver = class {
105
73
  duetProject: seededProject || void 0
106
74
  }
107
75
  });
108
- if (load.currentTier?.id) {
76
+ if (_optionalChain([load, 'access', _ => _.currentTier, 'optionalAccess', _2 => _2.id])) {
109
77
  return load.cloudaicompanionProject || void 0;
110
78
  }
111
- const defaultTier = load.allowedTiers?.find((t) => t.isDefault);
112
- const tierId = defaultTier?.id ?? LEGACY_TIER_ID;
79
+ const defaultTier = _optionalChain([load, 'access', _3 => _3.allowedTiers, 'optionalAccess', _4 => _4.find, 'call', _5 => _5((t) => t.isDefault)]);
80
+ const tierId = _nullishCoalesce(_optionalChain([defaultTier, 'optionalAccess', _6 => _6.id]), () => ( LEGACY_TIER_ID));
113
81
  const isFreeish = tierId === FREE_TIER_ID || tierId === LEGACY_TIER_ID;
114
82
  const onboardProject = isFreeish ? void 0 : seededProject || void 0;
115
83
  let lro = await this.postCodeAssist("onboardUser", accessToken, {
@@ -130,11 +98,11 @@ var GeminiCodeAssistProjectResolver = class {
130
98
  }
131
99
  if (lro.error) {
132
100
  throw new GeminiCodeAssistHandshakeError(
133
- `Code Assist onboardUser failed: ${lro.error.message ?? "unknown"}`,
134
- lro.error.code ?? 500
101
+ `Code Assist onboardUser failed: ${_nullishCoalesce(lro.error.message, () => ( "unknown"))}`,
102
+ _nullishCoalesce(lro.error.code, () => ( 500))
135
103
  );
136
104
  }
137
- return lro.response?.cloudaicompanionProject?.id || void 0;
105
+ return _optionalChain([lro, 'access', _7 => _7.response, 'optionalAccess', _8 => _8.cloudaicompanionProject, 'optionalAccess', _9 => _9.id]) || void 0;
138
106
  }
139
107
  /** POST a Code Assist method, surfacing the documented hard failures clearly. */
140
108
  async postCodeAssist(method, accessToken, body) {
@@ -173,13 +141,13 @@ var GeminiCodeAssistProjectResolver = class {
173
141
  let detailMessage = "";
174
142
  try {
175
143
  const errBody = await res.json();
176
- detailCode = errBody.error?.status;
177
- detailMessage = errBody.error?.message ?? "";
178
- } catch {
144
+ detailCode = _optionalChain([errBody, 'access', _10 => _10.error, 'optionalAccess', _11 => _11.status]);
145
+ detailMessage = _nullishCoalesce(_optionalChain([errBody, 'access', _12 => _12.error, 'optionalAccess', _13 => _13.message]), () => ( ""));
146
+ } catch (e) {
179
147
  }
180
148
  if (res.status === 403) {
181
149
  throw new GeminiCodeAssistHandshakeError(
182
- `Code Assist ${method} denied (403 ${detailCode ?? "PERMISSION_DENIED"}): ${detailMessage || "enable the Cloud AI Companion API and grant the required role"}`,
150
+ `Code Assist ${method} denied (403 ${_nullishCoalesce(detailCode, () => ( "PERMISSION_DENIED"))}): ${detailMessage || "enable the Cloud AI Companion API and grant the required role"}`,
183
151
  403,
184
152
  detailCode
185
153
  );
@@ -197,7 +165,7 @@ var GeminiCodeAssistProjectResolver = class {
197
165
  detailCode
198
166
  );
199
167
  }
200
- };
168
+ }, _class);
201
169
  function delay(ms) {
202
170
  return new Promise((resolve) => {
203
171
  setTimeout(resolve, ms);
@@ -210,9 +178,8 @@ function getGeminiCodeAssistProjectResolver() {
210
178
  }
211
179
  return _resolverSingleton;
212
180
  }
213
- // Annotate the CommonJS export names for ESM import in node:
214
- 0 && (module.exports = {
215
- GeminiCodeAssistHandshakeError,
216
- GeminiCodeAssistProjectResolver,
217
- getGeminiCodeAssistProjectResolver
218
- });
181
+
182
+
183
+
184
+
185
+ exports.GeminiCodeAssistHandshakeError = GeminiCodeAssistHandshakeError; exports.GeminiCodeAssistProjectResolver = GeminiCodeAssistProjectResolver; exports.getGeminiCodeAssistProjectResolver = getGeminiCodeAssistProjectResolver;
@@ -1,12 +1,8 @@
1
- // src/transformer/transformers/GeminiCodeAssistTransformer.ts
2
- var DEFAULT_CODE_ASSIST_ENDPOINT = "https://cloudcode-pa.googleapis.com";
3
- var DEFAULT_CODE_ASSIST_API_VERSION = "v1internal";
4
- function resolveCodeAssistEndpoint() {
5
- return (process.env.CODE_ASSIST_ENDPOINT || DEFAULT_CODE_ASSIST_ENDPOINT).replace(/\/+$/, "");
6
- }
7
- function resolveCodeAssistApiVersion() {
8
- return process.env.CODE_ASSIST_API_VERSION || DEFAULT_CODE_ASSIST_API_VERSION;
9
- }
1
+ import {
2
+ resolveCodeAssistApiVersion,
3
+ resolveCodeAssistEndpoint
4
+ } from "../chunk-Z7Y2NPHY.js";
5
+ import "../chunk-S4WBV25P.js";
10
6
 
11
7
  // src/auth/GeminiCodeAssistProjectResolver.ts
12
8
  var FREE_TIER_ID = "free-tier";
@@ -0,0 +1,100 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/completion/builtin-web-fetch.ts
2
+ var _readability = require('@mozilla/readability');
3
+ var _jsdom = require('jsdom');
4
+ var _turndown = require('turndown'); var _turndown2 = _interopRequireDefault(_turndown);
5
+ var FETCH_TIMEOUT_MS = 15e3;
6
+ var MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
7
+ var MAX_REDIRECTS = 5;
8
+ var CHROME_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
9
+ var FETCH_HEADERS = {
10
+ "User-Agent": CHROME_UA,
11
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
12
+ "Accept-Language": "en-US,en;q=0.9"
13
+ };
14
+ var turndown = new (0, _turndown2.default)({
15
+ headingStyle: "atx",
16
+ codeBlockStyle: "fenced",
17
+ bulletListMarker: "-"
18
+ });
19
+ async function fetchAndExtractUrl(url, maxChars) {
20
+ const controller = new AbortController();
21
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
22
+ try {
23
+ const res = await fetchWithRedirectLimit(url, controller.signal);
24
+ clearTimeout(timer);
25
+ const contentType = _nullishCoalesce(res.headers.get("content-type"), () => ( ""));
26
+ const rawText = await readBodyWithLimit(res);
27
+ let text;
28
+ if (contentType.includes("json")) {
29
+ try {
30
+ text = JSON.stringify(JSON.parse(rawText), null, 2);
31
+ } catch (e) {
32
+ text = rawText;
33
+ }
34
+ } else if (contentType.includes("html")) {
35
+ text = extractHtml(rawText, res.url || url);
36
+ } else {
37
+ text = rawText;
38
+ }
39
+ return text.length > maxChars ? text.slice(0, maxChars) + "\n\n[Content truncated]" : text;
40
+ } finally {
41
+ clearTimeout(timer);
42
+ }
43
+ }
44
+ function extractHtml(html, url) {
45
+ const dom = new (0, _jsdom.JSDOM)(html, { url });
46
+ const doc = dom.window.document;
47
+ for (const sel of ["script", "style", "noscript", "nav", "footer", "aside", "iframe"]) {
48
+ doc.querySelectorAll(sel).forEach((el) => el.remove());
49
+ }
50
+ const reader = new (0, _readability.Readability)(doc);
51
+ const article = reader.parse();
52
+ if (_optionalChain([article, 'optionalAccess', _ => _.content])) {
53
+ return turndown.turndown(article.content).replace(/\n{3,}/g, "\n\n");
54
+ }
55
+ const body = _optionalChain([doc, 'access', _2 => _2.body, 'optionalAccess', _3 => _3.textContent]) || "";
56
+ return body.replace(/\s+/g, " ").trim();
57
+ }
58
+ async function fetchWithRedirectLimit(url, signal) {
59
+ let currentUrl = url;
60
+ for (let i = 0; i < MAX_REDIRECTS; i++) {
61
+ const res = await fetch(currentUrl, { signal, redirect: "manual", headers: FETCH_HEADERS });
62
+ if (res.status >= 300 && res.status < 400) {
63
+ const location = res.headers.get("location");
64
+ if (!location) return res;
65
+ currentUrl = new URL(location, currentUrl).href;
66
+ continue;
67
+ }
68
+ Object.defineProperty(res, "url", { value: currentUrl, writable: false });
69
+ return res;
70
+ }
71
+ throw new Error(`Too many redirects (>${MAX_REDIRECTS})`);
72
+ }
73
+ async function readBodyWithLimit(res) {
74
+ const reader = _optionalChain([res, 'access', _4 => _4.body, 'optionalAccess', _5 => _5.getReader, 'call', _6 => _6()]);
75
+ if (!reader) return "";
76
+ const chunks = [];
77
+ let totalBytes = 0;
78
+ while (true) {
79
+ const { done, value } = await reader.read();
80
+ if (done) break;
81
+ totalBytes += value.byteLength;
82
+ if (totalBytes > MAX_RESPONSE_BYTES) {
83
+ reader.cancel();
84
+ break;
85
+ }
86
+ chunks.push(value);
87
+ }
88
+ const combined = new Uint8Array(totalBytes > MAX_RESPONSE_BYTES ? MAX_RESPONSE_BYTES : totalBytes);
89
+ let offset = 0;
90
+ for (const chunk of chunks) {
91
+ const len = Math.min(chunk.byteLength, combined.byteLength - offset);
92
+ combined.set(chunk.subarray(0, len), offset);
93
+ offset += len;
94
+ if (offset >= combined.byteLength) break;
95
+ }
96
+ return new TextDecoder("utf-8", { fatal: false }).decode(combined);
97
+ }
98
+
99
+
100
+ exports.fetchAndExtractUrl = fetchAndExtractUrl;
@@ -0,0 +1,100 @@
1
+ // src/completion/builtin-web-fetch.ts
2
+ import { Readability } from "@mozilla/readability";
3
+ import { JSDOM } from "jsdom";
4
+ import TurndownService from "turndown";
5
+ var FETCH_TIMEOUT_MS = 15e3;
6
+ var MAX_RESPONSE_BYTES = 5 * 1024 * 1024;
7
+ var MAX_REDIRECTS = 5;
8
+ var CHROME_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36";
9
+ var FETCH_HEADERS = {
10
+ "User-Agent": CHROME_UA,
11
+ Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
12
+ "Accept-Language": "en-US,en;q=0.9"
13
+ };
14
+ var turndown = new TurndownService({
15
+ headingStyle: "atx",
16
+ codeBlockStyle: "fenced",
17
+ bulletListMarker: "-"
18
+ });
19
+ async function fetchAndExtractUrl(url, maxChars) {
20
+ const controller = new AbortController();
21
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
22
+ try {
23
+ const res = await fetchWithRedirectLimit(url, controller.signal);
24
+ clearTimeout(timer);
25
+ const contentType = res.headers.get("content-type") ?? "";
26
+ const rawText = await readBodyWithLimit(res);
27
+ let text;
28
+ if (contentType.includes("json")) {
29
+ try {
30
+ text = JSON.stringify(JSON.parse(rawText), null, 2);
31
+ } catch {
32
+ text = rawText;
33
+ }
34
+ } else if (contentType.includes("html")) {
35
+ text = extractHtml(rawText, res.url || url);
36
+ } else {
37
+ text = rawText;
38
+ }
39
+ return text.length > maxChars ? text.slice(0, maxChars) + "\n\n[Content truncated]" : text;
40
+ } finally {
41
+ clearTimeout(timer);
42
+ }
43
+ }
44
+ function extractHtml(html, url) {
45
+ const dom = new JSDOM(html, { url });
46
+ const doc = dom.window.document;
47
+ for (const sel of ["script", "style", "noscript", "nav", "footer", "aside", "iframe"]) {
48
+ doc.querySelectorAll(sel).forEach((el) => el.remove());
49
+ }
50
+ const reader = new Readability(doc);
51
+ const article = reader.parse();
52
+ if (article?.content) {
53
+ return turndown.turndown(article.content).replace(/\n{3,}/g, "\n\n");
54
+ }
55
+ const body = doc.body?.textContent || "";
56
+ return body.replace(/\s+/g, " ").trim();
57
+ }
58
+ async function fetchWithRedirectLimit(url, signal) {
59
+ let currentUrl = url;
60
+ for (let i = 0; i < MAX_REDIRECTS; i++) {
61
+ const res = await fetch(currentUrl, { signal, redirect: "manual", headers: FETCH_HEADERS });
62
+ if (res.status >= 300 && res.status < 400) {
63
+ const location = res.headers.get("location");
64
+ if (!location) return res;
65
+ currentUrl = new URL(location, currentUrl).href;
66
+ continue;
67
+ }
68
+ Object.defineProperty(res, "url", { value: currentUrl, writable: false });
69
+ return res;
70
+ }
71
+ throw new Error(`Too many redirects (>${MAX_REDIRECTS})`);
72
+ }
73
+ async function readBodyWithLimit(res) {
74
+ const reader = res.body?.getReader();
75
+ if (!reader) return "";
76
+ const chunks = [];
77
+ let totalBytes = 0;
78
+ while (true) {
79
+ const { done, value } = await reader.read();
80
+ if (done) break;
81
+ totalBytes += value.byteLength;
82
+ if (totalBytes > MAX_RESPONSE_BYTES) {
83
+ reader.cancel();
84
+ break;
85
+ }
86
+ chunks.push(value);
87
+ }
88
+ const combined = new Uint8Array(totalBytes > MAX_RESPONSE_BYTES ? MAX_RESPONSE_BYTES : totalBytes);
89
+ let offset = 0;
90
+ for (const chunk of chunks) {
91
+ const len = Math.min(chunk.byteLength, combined.byteLength - offset);
92
+ combined.set(chunk.subarray(0, len), offset);
93
+ offset += len;
94
+ if (offset >= combined.byteLength) break;
95
+ }
96
+ return new TextDecoder("utf-8", { fatal: false }).decode(combined);
97
+ }
98
+ export {
99
+ fetchAndExtractUrl
100
+ };