@wrongstack/providers 0.107.2 → 0.119.1
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 +106 -2
- package/dist/index.js +194 -9
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
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,125 @@ var WireAdapter = class {
|
|
|
597
660
|
const text = await safeText(httpRes);
|
|
598
661
|
throw this.translateError(httpRes.status, text);
|
|
599
662
|
}
|
|
600
|
-
|
|
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(() => {
|
|
758
|
+
});
|
|
759
|
+
const elapsedMs = Date.now() - startTime;
|
|
760
|
+
throw new StreamHangError({
|
|
761
|
+
providerId,
|
|
762
|
+
model,
|
|
763
|
+
hangTimeoutMs: timeout,
|
|
764
|
+
bytesReceived,
|
|
765
|
+
elapsedMs
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
const { done, value } = result;
|
|
769
|
+
if (done) {
|
|
770
|
+
controller.close();
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
if (value) {
|
|
774
|
+
bytesReceived += value.length;
|
|
775
|
+
}
|
|
776
|
+
controller.enqueue(value);
|
|
777
|
+
},
|
|
778
|
+
cancel(reason) {
|
|
779
|
+
reader.cancel(reason);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
601
782
|
}
|
|
602
783
|
/** Per-request headers. `apiKey` is already in scope — call `super.buildHeaders` first. */
|
|
603
784
|
buildHeaders(_req) {
|
|
@@ -611,6 +792,9 @@ var WireAdapter = class {
|
|
|
611
792
|
return parseProviderHttpError(this.id, status, body);
|
|
612
793
|
}
|
|
613
794
|
};
|
|
795
|
+
function isNodeReadable2(b) {
|
|
796
|
+
return !!b && typeof b === "object" && typeof b.pipe === "function" && typeof b.on === "function";
|
|
797
|
+
}
|
|
614
798
|
|
|
615
799
|
// src/anthropic.ts
|
|
616
800
|
var DEFAULT_BASE = "https://api.anthropic.com";
|
|
@@ -628,7 +812,7 @@ var AnthropicProvider = class extends WireAdapter {
|
|
|
628
812
|
capabilities = capabilitiesForFamily("anthropic");
|
|
629
813
|
opts;
|
|
630
814
|
constructor(opts) {
|
|
631
|
-
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE, opts.fetchImpl);
|
|
815
|
+
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE, opts.fetchImpl, opts.streamOpts);
|
|
632
816
|
this.opts = opts;
|
|
633
817
|
}
|
|
634
818
|
buildUrl(_req) {
|
|
@@ -787,7 +971,7 @@ var GoogleProvider = class extends WireAdapter {
|
|
|
787
971
|
id;
|
|
788
972
|
capabilities;
|
|
789
973
|
constructor(opts) {
|
|
790
|
-
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl);
|
|
974
|
+
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE2, opts.fetchImpl, opts.streamOpts);
|
|
791
975
|
this.id = opts.id ?? "google";
|
|
792
976
|
this.capabilities = capabilitiesForFamily("google", {
|
|
793
977
|
...opts.capabilities
|
|
@@ -1111,7 +1295,7 @@ var OpenAIProvider = class extends WireAdapter {
|
|
|
1111
1295
|
capabilities;
|
|
1112
1296
|
opts;
|
|
1113
1297
|
constructor(opts) {
|
|
1114
|
-
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl);
|
|
1298
|
+
super(opts.apiKey, opts.baseUrl ?? DEFAULT_BASE3, opts.fetchImpl, opts.streamOpts);
|
|
1115
1299
|
this.opts = opts;
|
|
1116
1300
|
this.id = opts.id ?? "openai";
|
|
1117
1301
|
this.capabilities = capabilitiesForFamily("openai", {
|
|
@@ -1330,7 +1514,8 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
|
|
|
1330
1514
|
systemPrompt: !opts.quirks?.systemAsMessage,
|
|
1331
1515
|
...opts.capabilities
|
|
1332
1516
|
}),
|
|
1333
|
-
quirks: opts.quirks
|
|
1517
|
+
quirks: opts.quirks,
|
|
1518
|
+
streamOpts: opts.streamOpts
|
|
1334
1519
|
});
|
|
1335
1520
|
this.extraHeaders = opts.headers;
|
|
1336
1521
|
this.urlOverride = opts.urlOverride;
|
|
@@ -1363,7 +1548,7 @@ var WireFormatProvider = class extends WireAdapter {
|
|
|
1363
1548
|
capabilities;
|
|
1364
1549
|
cfg;
|
|
1365
1550
|
constructor(cfg, opts) {
|
|
1366
|
-
super(opts.apiKey, opts.baseUrl ?? cfg.defaultBaseUrl, opts.fetchImpl);
|
|
1551
|
+
super(opts.apiKey, opts.baseUrl ?? cfg.defaultBaseUrl, opts.fetchImpl, opts.streamOpts);
|
|
1367
1552
|
this.id = cfg.id;
|
|
1368
1553
|
this.capabilities = cfg.capabilities;
|
|
1369
1554
|
this.cfg = cfg;
|
|
@@ -2329,6 +2514,6 @@ function validateQuirks(providerId, quirks) {
|
|
|
2329
2514
|
});
|
|
2330
2515
|
}
|
|
2331
2516
|
|
|
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 };
|
|
2517
|
+
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
2518
|
//# sourceMappingURL=index.js.map
|
|
2334
2519
|
//# sourceMappingURL=index.js.map
|