@wrongstack/providers 0.109.1 → 0.141.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.
package/dist/index.d.ts CHANGED
@@ -21,12 +21,35 @@ interface SSEMessage {
21
21
  }
22
22
  declare function parseSSE(body: ReadableStream<Uint8Array> | NodeJS.ReadableStream | null): AsyncIterable<SSEMessage>;
23
23
 
24
+ /** Configuration for WireAdapter stream-level debugging and hang detection. */
25
+ interface WireAdapterStreamOptions {
26
+ /**
27
+ * When true, accumulate per-chunk stats into the shared debug-sink
28
+ * (stream-debug-state.ts). The sink batches every 200 ms and pushes to
29
+ * a registered callback. The CLI default callback writes to stderr; the
30
+ * TUI replaces it with a reducer dispatch that renders in StatusBar line 3,
31
+ * keeping all output inside Ink's layout.
32
+ *
33
+ * Controlled by WRONGSTACK_DEBUG_STREAM=1 env var or the runtime
34
+ * /settings debug-stream toggle.
35
+ */
36
+ debugStream?: boolean | undefined;
37
+ /**
38
+ * Maximum time (ms) to wait for the next chunk of data before declaring
39
+ * a stream hang. Default: 60_000 (60 seconds). Set to 0 to disable.
40
+ * When a hang is detected, a StreamHangError is thrown so the agent
41
+ * loop can retry the iteration.
42
+ */
43
+ streamHangTimeoutMs?: number | undefined;
44
+ }
24
45
  /**
25
46
  * Shared HTTP mechanics for streaming providers.
26
47
  * Providers extend this to get:
27
48
  * - canonical error handling (ProviderError with retryable flag)
28
49
  * - SSE body parsing via parseSSE()
29
50
  * - abort signal wiring
51
+ * - optional raw-stream debug logging
52
+ * - optional stream hang detection
30
53
  *
31
54
  * Subclasses implement the abstract members to provide their specific wire format.
32
55
  */
@@ -36,13 +59,32 @@ declare abstract class WireAdapter implements Provider {
36
59
  readonly fetchImpl: typeof fetch;
37
60
  abstract readonly id: string;
38
61
  abstract readonly capabilities: Capabilities;
39
- constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch);
62
+ protected readonly debugStream: boolean;
63
+ protected readonly streamHangTimeoutMs: number;
64
+ constructor(apiKey: string, baseUrl: string, fetchImpl?: typeof fetch, streamOpts?: WireAdapterStreamOptions);
40
65
  complete(req: Request, opts: {
41
66
  signal: AbortSignal;
42
67
  }): Promise<Response>;
43
68
  stream(req: Request, opts: {
44
69
  signal: AbortSignal;
45
70
  }): AsyncIterable<StreamEvent>;
71
+ /**
72
+ * Wrap a readable stream body to log a compact status line per incoming
73
+ * byte chunk to stderr. This is a diagnostic tool for tracking stream
74
+ * activity — chunk count, sizes, and inter-chunk deltas — without
75
+ * printing payload contents.
76
+ */
77
+ private wrapDebugStream;
78
+ private wrapDebugNodeStream;
79
+ private wrapDebugWebStream;
80
+ /**
81
+ * Wrap a readable stream to detect hangs — when no data arrives for
82
+ * longer than `streamHangTimeoutMs`. When a hang is detected, throws
83
+ * `StreamHangError` so the caller can retry or fall back.
84
+ */
85
+ private wrapWithHangDetection;
86
+ private wrapHangNodeStream;
87
+ private wrapHangWebStream;
46
88
  /** HTTP endpoint for this provider's chat completions / messages API. */
47
89
  protected abstract buildUrl(req: Request): string;
48
90
  /** Per-request headers. `apiKey` is already in scope — call `super.buildHeaders` first. */
@@ -61,6 +103,8 @@ interface AnthropicProviderOptions {
61
103
  apiVersion?: string | undefined;
62
104
  beta?: string[] | undefined;
63
105
  fetchImpl?: typeof fetch | undefined;
106
+ /** Raw stream debugging and hang-detection options. */
107
+ streamOpts?: WireAdapterStreamOptions | undefined;
64
108
  }
65
109
  declare class AnthropicProvider extends WireAdapter {
66
110
  readonly id = "anthropic";
@@ -135,6 +179,8 @@ interface OpenAIProviderOptions {
135
179
  } | undefined;
136
180
  id?: string | undefined;
137
181
  capabilities?: Partial<Capabilities> | undefined;
182
+ /** Raw stream debugging and hang-detection options. */
183
+ streamOpts?: WireAdapterStreamOptions | undefined;
138
184
  }
139
185
  declare class OpenAIProvider extends WireAdapter {
140
186
  readonly id: string;
@@ -179,6 +225,8 @@ interface OpenAICompatibleOptions {
179
225
  * URL structures (e.g. Google with model-in-path, Anthropic with /v1/messages).
180
226
  */
181
227
  urlOverride?: ((baseUrl: string, req: Request) => string) | undefined;
228
+ /** Raw stream debugging and hang-detection options. */
229
+ streamOpts?: WireAdapterStreamOptions | undefined;
182
230
  }
183
231
  declare class OpenAICompatibleProvider extends OpenAIProvider {
184
232
  private readonly extraHeaders?;
@@ -212,6 +260,8 @@ interface GoogleProviderOptions {
212
260
  fetchImpl?: typeof fetch | undefined;
213
261
  id?: string | undefined;
214
262
  capabilities?: Partial<Capabilities> | undefined;
263
+ /** Raw stream debugging and hang-detection options. */
264
+ streamOpts?: WireAdapterStreamOptions | undefined;
215
265
  }
216
266
  declare class GoogleProvider extends WireAdapter {
217
267
  readonly id: string;
@@ -225,6 +275,59 @@ declare class GoogleProvider extends WireAdapter {
225
275
  private buildGenConfig;
226
276
  }
227
277
 
278
+ /**
279
+ * Singleton gate for stream debug logging.
280
+ *
281
+ * WireAdapter reads this on every stream() call, so runtime toggles
282
+ * (via /settings debug-stream on|off) take effect on the next request
283
+ * without recreating provider instances.
284
+ *
285
+ * When enabled, WireAdapter accumulates per-chunk stats and pushes them
286
+ * through a registered callback. In CLI (non-TUI) mode the default
287
+ * callback writes a compact status line to stderr. The TUI replaces
288
+ * the callback with one that dispatches to its reducer so the debug
289
+ * info renders inside Ink's StatusBar line 3 instead of bypassing it.
290
+ *
291
+ * The CLI boot path seeds this from config.debugStream at startup.
292
+ */
293
+ interface DebugStreamStats {
294
+ /** Monotonic chunk counter, resets per-stream. */
295
+ chunkCount: number;
296
+ /** Bytes of the most recent chunk. */
297
+ lastChunkSize: number;
298
+ /** Millisecond delta since the PREVIOUS chunk (reveals think gaps). */
299
+ lastDeltaMs: number;
300
+ /** Cumulative bytes received for this stream. */
301
+ totalBytes: number;
302
+ /** ISO timestamp of the most recent chunk. */
303
+ lastChunkAt: string;
304
+ }
305
+ type DebugStreamCallback = (stats: DebugStreamStats) => void;
306
+ /** Check whether raw SSE stream debugging is currently active. */
307
+ declare function isDebugStreamEnabled(): boolean;
308
+ /** Flip the stream debug flag at runtime. Persisted separately via ConfigStore. */
309
+ declare function setDebugStreamEnabled(enabled: boolean): void;
310
+ /**
311
+ * Register a callback that receives THROTTLED debug-chunk stats (~5 Hz).
312
+ * WireAdapter calls `pushDebugChunkStats()` on every raw chunk; this module
313
+ * batches them and calls `cb` at most once per THROTTLE_MS.
314
+ *
315
+ * Pass `null` to restore the default stderr behaviour.
316
+ */
317
+ declare function setDebugStreamCallback(cb: DebugStreamCallback | null): void;
318
+ /**
319
+ * Called by WireAdapter on every raw chunk. Not throttled — call it as
320
+ * often as chunks arrive; it's cheap (a few integer assigns + a debounced
321
+ * setTimeout). The registered callback receives aggregated stats at most
322
+ * once per THROTTLE_MS.
323
+ */
324
+ declare function pushDebugChunkStats(bytes: number, deltaMs: number): void;
325
+ /**
326
+ * Default callback: write a compact status line to stderr (used in CLI /
327
+ * headless mode where Ink isn't painting the terminal).
328
+ */
329
+ declare function defaultDebugStreamCallback(stats: DebugStreamStats): void;
330
+
228
331
  /**
229
332
  * Declarative wire-format definition. Sufficient to add a new HTTP+SSE
230
333
  * provider without subclassing `WireAdapter` — the boilerplate (HTTP errors,
@@ -287,6 +390,7 @@ declare class WireFormatProvider<S = Record<string, unknown>> extends WireAdapte
287
390
  apiKey: string;
288
391
  baseUrl?: string | undefined;
289
392
  fetchImpl?: typeof fetch | undefined;
393
+ streamOpts?: WireAdapterStreamOptions | undefined;
290
394
  });
291
395
  protected buildUrl(req: Request): string;
292
396
  protected buildHeaders(req: Request): Record<string, string>;
@@ -497,4 +601,4 @@ declare function buildProviderFactoriesFromRegistry(opts: BuildFactoriesOptions)
497
601
  */
498
602
  declare function makeProviderFromConfig(id: string, cfg: ProviderConfig): Provider;
499
603
 
500
- export { AnthropicProvider, type AnthropicProviderOptions, type BuildFactoriesOptions, CAPABILITIES_BY_FAMILY, type CompatibilityQuirks, type ConvertOptions, GoogleProvider, type GoogleProviderOptions, type OpenAIChoice, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OpenAIMessage, OpenAIProvider, type OpenAIProviderOptions, type OpenAIToolCall, WireAdapter, type WireFactoryOptions, type WireFormatConfig, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
604
+ export { AnthropicProvider, type AnthropicProviderOptions, type BuildFactoriesOptions, CAPABILITIES_BY_FAMILY, type CompatibilityQuirks, type ConvertOptions, type DebugStreamCallback, type DebugStreamStats, GoogleProvider, type GoogleProviderOptions, type OpenAIChoice, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OpenAIMessage, OpenAIProvider, type OpenAIProviderOptions, type OpenAIToolCall, WireAdapter, type WireAdapterStreamOptions, type WireFactoryOptions, type WireFormatConfig, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defaultDebugStreamCallback, defineWireFormat, googleWireFormat, isDebugStreamEnabled, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, pushDebugChunkStats, setDebugStreamCallback, setDebugStreamEnabled, toolsToAnthropic, toolsToOpenAI };
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { expectDefined, ProviderError, safeParse, sanitizeJsonString, WrongStackError, ERROR_CODES } from '@wrongstack/core';
1
+ import { expectDefined, ProviderError, StreamHangError, safeParse, sanitizeJsonString, WrongStackError, ERROR_CODES } from '@wrongstack/core';
2
+ import { Readable } from 'stream';
2
3
  import { randomUUID } from 'crypto';
3
4
 
4
5
  var __defProp = Object.defineProperty;
@@ -539,6 +540,60 @@ function toolsToAnthropic(tools) {
539
540
  }
540
541
  }));
541
542
  }
543
+
544
+ // src/stream-debug-state.ts
545
+ var _debugStreamEnabled = false;
546
+ var _debugStreamCallback = null;
547
+ var _throttleTimer = null;
548
+ var _pendingStats = null;
549
+ var THROTTLE_MS = 200;
550
+ function _flush() {
551
+ if (_pendingStats && _debugStreamCallback) {
552
+ _debugStreamCallback({ ..._pendingStats });
553
+ _pendingStats = null;
554
+ }
555
+ _throttleTimer = null;
556
+ }
557
+ function _scheduleFlush() {
558
+ if (_throttleTimer) return;
559
+ _throttleTimer = setTimeout(_flush, THROTTLE_MS);
560
+ if (_throttleTimer.unref) _throttleTimer.unref();
561
+ }
562
+ function isDebugStreamEnabled() {
563
+ return _debugStreamEnabled;
564
+ }
565
+ function setDebugStreamEnabled(enabled) {
566
+ _debugStreamEnabled = enabled;
567
+ }
568
+ function setDebugStreamCallback(cb) {
569
+ if (_throttleTimer) {
570
+ clearTimeout(_throttleTimer);
571
+ _flush();
572
+ }
573
+ _debugStreamCallback = cb;
574
+ }
575
+ function pushDebugChunkStats(bytes, deltaMs) {
576
+ if (!_debugStreamEnabled) return;
577
+ _pendingStats = {
578
+ chunkCount: (_pendingStats?.chunkCount ?? 0) + 1,
579
+ lastChunkSize: bytes,
580
+ lastDeltaMs: deltaMs,
581
+ totalBytes: (_pendingStats?.totalBytes ?? 0) + bytes,
582
+ lastChunkAt: (/* @__PURE__ */ new Date()).toISOString()
583
+ };
584
+ _scheduleFlush();
585
+ }
586
+ function defaultDebugStreamCallback(stats) {
587
+ process.stderr.write(
588
+ `[DEBUG-STREAM] chunk #${stats.chunkCount} (${stats.lastChunkSize}B, +${stats.lastDeltaMs}ms) \xB7 ${fmtBytes(stats.totalBytes)} total \xB7 ${stats.lastChunkAt}
589
+ `
590
+ );
591
+ }
592
+ function fmtBytes(n) {
593
+ if (n < 1024) return `${n}B`;
594
+ if (n < 1048576) return `${(n / 1024).toFixed(1)}KB`;
595
+ return `${(n / 1048576).toFixed(1)}MB`;
596
+ }
542
597
  function validateResponse(res) {
543
598
  const r = res;
544
599
  if (r === void 0 || typeof r.ok !== "boolean" || typeof r.status !== "number") {
@@ -558,16 +613,24 @@ async function safeText(res) {
558
613
  return "";
559
614
  }
560
615
  }
616
+ function logRawChunk(_providerId, _chunkIndex, bytes, deltaMs) {
617
+ pushDebugChunkStats(bytes.length, deltaMs);
618
+ }
619
+ var DEFAULT_STREAM_HANG_TIMEOUT_MS = 6e4;
561
620
  var WireAdapter = class {
562
- constructor(apiKey, baseUrl, fetchImpl = fetch) {
621
+ constructor(apiKey, baseUrl, fetchImpl = fetch, streamOpts = {}) {
563
622
  this.apiKey = apiKey;
564
623
  this.baseUrl = baseUrl;
565
624
  this.fetchImpl = fetchImpl;
566
625
  if (!apiKey) throw new Error(`${this.constructor.name}: apiKey required`);
626
+ this.debugStream = streamOpts.debugStream ?? false;
627
+ this.streamHangTimeoutMs = streamOpts.streamHangTimeoutMs ?? DEFAULT_STREAM_HANG_TIMEOUT_MS;
567
628
  }
568
629
  apiKey;
569
630
  baseUrl;
570
631
  fetchImpl;
632
+ debugStream;
633
+ streamHangTimeoutMs;
571
634
  async complete(req, opts) {
572
635
  const { aggregateStream: aggregateStream2 } = await Promise.resolve().then(() => (init_aggregate(), aggregate_exports));
573
636
  return aggregateStream2(this.stream(req, opts));
@@ -597,7 +660,124 @@ var WireAdapter = class {
597
660
  const text = await safeText(httpRes);
598
661
  throw this.translateError(httpRes.status, text);
599
662
  }
600
- yield* this.parseStream(httpRes.body, req.model);
663
+ let sseBody = httpRes.body;
664
+ if (!sseBody) {
665
+ return;
666
+ }
667
+ if (this.debugStream || isDebugStreamEnabled()) {
668
+ sseBody = this.wrapDebugStream(sseBody);
669
+ }
670
+ if (this.streamHangTimeoutMs > 0) {
671
+ sseBody = this.wrapWithHangDetection(sseBody, req.model);
672
+ }
673
+ yield* this.parseStream(sseBody, req.model);
674
+ }
675
+ /**
676
+ * Wrap a readable stream body to log a compact status line per incoming
677
+ * byte chunk to stderr. This is a diagnostic tool for tracking stream
678
+ * activity — chunk count, sizes, and inter-chunk deltas — without
679
+ * printing payload contents.
680
+ */
681
+ wrapDebugStream(body) {
682
+ if (isNodeReadable2(body)) {
683
+ return this.wrapDebugNodeStream(body);
684
+ }
685
+ return this.wrapDebugWebStream(body);
686
+ }
687
+ wrapDebugNodeStream(body) {
688
+ let lastChunkTime = Date.now();
689
+ let chunkIndex = 0;
690
+ const providerId = this.id;
691
+ return Readable.from(
692
+ (async function* () {
693
+ for await (const chunk of body) {
694
+ const bytes = typeof chunk === "string" ? new TextEncoder().encode(chunk) : new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
695
+ const now = Date.now();
696
+ logRawChunk(providerId, chunkIndex++, bytes, now - lastChunkTime);
697
+ lastChunkTime = now;
698
+ yield chunk;
699
+ }
700
+ })()
701
+ );
702
+ }
703
+ wrapDebugWebStream(body) {
704
+ let lastChunkTime = Date.now();
705
+ let chunkIndex = 0;
706
+ const self = this;
707
+ const reader = body.getReader();
708
+ return new ReadableStream({
709
+ async pull(controller) {
710
+ const { done, value } = await reader.read();
711
+ if (done) {
712
+ controller.close();
713
+ return;
714
+ }
715
+ if (value) {
716
+ const now = Date.now();
717
+ logRawChunk(self.id, chunkIndex++, value, now - lastChunkTime);
718
+ lastChunkTime = now;
719
+ }
720
+ controller.enqueue(value);
721
+ },
722
+ cancel(reason) {
723
+ reader.cancel(reason);
724
+ }
725
+ });
726
+ }
727
+ /**
728
+ * Wrap a readable stream to detect hangs — when no data arrives for
729
+ * longer than `streamHangTimeoutMs`. When a hang is detected, throws
730
+ * `StreamHangError` so the caller can retry or fall back.
731
+ */
732
+ wrapWithHangDetection(body, model) {
733
+ if (isNodeReadable2(body)) {
734
+ return this.wrapHangNodeStream(body, model);
735
+ }
736
+ return this.wrapHangWebStream(body, model);
737
+ }
738
+ wrapHangNodeStream(body, model) {
739
+ const webStream = Readable.toWeb(body);
740
+ const wrappedWeb = this.wrapHangWebStream(webStream, model);
741
+ return Readable.fromWeb(wrappedWeb);
742
+ }
743
+ wrapHangWebStream(body, model) {
744
+ const startTime = Date.now();
745
+ let bytesReceived = 0;
746
+ const timeout = this.streamHangTimeoutMs;
747
+ const providerId = this.id;
748
+ const reader = body.getReader();
749
+ return new ReadableStream({
750
+ async pull(controller) {
751
+ const readPromise = reader.read();
752
+ const timeoutPromise = new Promise((resolve) => {
753
+ setTimeout(() => resolve({ timedOut: true }), timeout);
754
+ });
755
+ const result = await Promise.race([readPromise, timeoutPromise]);
756
+ if ("timedOut" in result && result.timedOut) {
757
+ reader.cancel("stream hang detected").catch((err) => console.debug(`[wire-adapter] cancel after stream hang failed: ${err}`));
758
+ const elapsedMs = Date.now() - startTime;
759
+ throw new StreamHangError({
760
+ providerId,
761
+ model,
762
+ hangTimeoutMs: timeout,
763
+ bytesReceived,
764
+ elapsedMs
765
+ });
766
+ }
767
+ const { done, value } = result;
768
+ if (done) {
769
+ controller.close();
770
+ return;
771
+ }
772
+ if (value) {
773
+ bytesReceived += value.length;
774
+ }
775
+ controller.enqueue(value);
776
+ },
777
+ cancel(reason) {
778
+ reader.cancel(reason);
779
+ }
780
+ });
601
781
  }
602
782
  /** Per-request headers. `apiKey` is already in scope — call `super.buildHeaders` first. */
603
783
  buildHeaders(_req) {
@@ -611,6 +791,9 @@ var WireAdapter = class {
611
791
  return parseProviderHttpError(this.id, status, body);
612
792
  }
613
793
  };
794
+ function isNodeReadable2(b) {
795
+ return !!b && typeof b === "object" && typeof b.pipe === "function" && typeof b.on === "function";
796
+ }
614
797
 
615
798
  // src/anthropic.ts
616
799
  var DEFAULT_BASE = "https://api.anthropic.com";
@@ -628,7 +811,7 @@ var AnthropicProvider = class extends WireAdapter {
628
811
  capabilities = capabilitiesForFamily("anthropic");
629
812
  opts;
630
813
  constructor(opts) {
631
- super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE, opts.fetchImpl);
814
+ super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE, opts.fetchImpl, opts.streamOpts);
632
815
  this.opts = opts;
633
816
  }
634
817
  buildUrl(_req) {
@@ -787,7 +970,7 @@ var GoogleProvider = class extends WireAdapter {
787
970
  id;
788
971
  capabilities;
789
972
  constructor(opts) {
790
- super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl);
973
+ super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl, opts.streamOpts);
791
974
  this.id = opts.id ?? "google";
792
975
  this.capabilities = capabilitiesForFamily("google", {
793
976
  ...opts.capabilities
@@ -1111,7 +1294,7 @@ var OpenAIProvider = class extends WireAdapter {
1111
1294
  capabilities;
1112
1295
  opts;
1113
1296
  constructor(opts) {
1114
- super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl);
1297
+ super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl, opts.streamOpts);
1115
1298
  this.opts = opts;
1116
1299
  this.id = opts.id ?? "openai";
1117
1300
  this.capabilities = capabilitiesForFamily("openai", {
@@ -1330,7 +1513,8 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
1330
1513
  systemPrompt: !opts.quirks?.systemAsMessage,
1331
1514
  ...opts.capabilities
1332
1515
  }),
1333
- quirks: opts.quirks
1516
+ quirks: opts.quirks,
1517
+ streamOpts: opts.streamOpts
1334
1518
  });
1335
1519
  this.extraHeaders = opts.headers;
1336
1520
  this.urlOverride = opts.urlOverride;
@@ -1363,7 +1547,7 @@ var WireFormatProvider = class extends WireAdapter {
1363
1547
  capabilities;
1364
1548
  cfg;
1365
1549
  constructor(cfg, opts) {
1366
- super(opts.apiKey, opts.baseUrl ?? cfg.defaultBaseUrl, opts.fetchImpl);
1550
+ super(opts.apiKey, opts.baseUrl ?? cfg.defaultBaseUrl, opts.fetchImpl, opts.streamOpts);
1367
1551
  this.id = cfg.id;
1368
1552
  this.capabilities = cfg.capabilities;
1369
1553
  this.cfg = cfg;
@@ -2290,6 +2474,8 @@ function makeProvider(p, cfg) {
2290
2474
  });
2291
2475
  case "google":
2292
2476
  return new GoogleProvider({ id: p.id, apiKey: expectDefined(apiKey), baseUrl });
2477
+ default:
2478
+ throw new Error(`Unknown provider family: ${String(family)}`);
2293
2479
  }
2294
2480
  }
2295
2481
  function makeProviderFromConfig(id, cfg) {
@@ -2329,6 +2515,6 @@ function validateQuirks(providerId, quirks) {
2329
2515
  });
2330
2516
  }
2331
2517
 
2332
- export { AnthropicProvider, CAPABILITIES_BY_FAMILY, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
2518
+ export { AnthropicProvider, CAPABILITIES_BY_FAMILY, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, capabilitiesForFamily, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defaultDebugStreamCallback, defineWireFormat, googleWireFormat, isDebugStreamEnabled, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, pushDebugChunkStats, setDebugStreamCallback, setDebugStreamEnabled, toolsToAnthropic, toolsToOpenAI };
2333
2519
  //# sourceMappingURL=index.js.map
2334
2520
  //# sourceMappingURL=index.js.map