@ctxprotocol/sdk 0.8.2 → 0.8.4

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.
@@ -9,9 +9,19 @@ interface ContextClientOptions {
9
9
  apiKey: string;
10
10
  /**
11
11
  * Base URL for the Context Protocol API
12
- * @default "https://ctxprotocol.com"
12
+ * @default "https://www.ctxprotocol.com"
13
13
  */
14
14
  baseUrl?: string;
15
+ /**
16
+ * Request timeout for non-streaming API calls in milliseconds.
17
+ * @default 300000
18
+ */
19
+ requestTimeoutMs?: number;
20
+ /**
21
+ * Request timeout for establishing streaming API calls in milliseconds.
22
+ * @default 600000
23
+ */
24
+ streamTimeoutMs?: number;
15
25
  }
16
26
  /**
17
27
  * An individual MCP tool exposed by a tool listing
@@ -287,6 +297,8 @@ interface ExecutionResult<T = unknown> {
287
297
  /** Execution duration in milliseconds */
288
298
  durationMs: number;
289
299
  }
300
+ /** Supported orchestration depth modes for query execution. */
301
+ type QueryDepth = "fast" | "auto" | "deep";
290
302
  /**
291
303
  * Options for the agentic query endpoint (pay-per-response).
292
304
  *
@@ -319,12 +331,80 @@ interface QueryOptions {
319
331
  * Useful for large payload workflows where inline JSON is not ideal.
320
332
  */
321
333
  includeDataUrl?: boolean;
334
+ /**
335
+ * Include machine-readable developer trace output for this query response.
336
+ * When enabled, the server may return timeline data describing retries,
337
+ * fallbacks, loop checks, and intermediate recovery behavior.
338
+ */
339
+ includeDeveloperTrace?: boolean;
340
+ /**
341
+ * Query orchestration depth mode:
342
+ * - `fast`: lower-latency path
343
+ * - `auto`: server decides between fast/deep
344
+ * - `deep`: full completeness-oriented path
345
+ */
346
+ queryDepth?: QueryDepth;
322
347
  /**
323
348
  * Optional idempotency key (UUID recommended).
324
349
  * Reuse the same key when retrying the same logical request.
325
350
  */
326
351
  idempotencyKey?: string;
327
352
  }
353
+ /**
354
+ * Tool reference attached to developer trace timeline steps.
355
+ */
356
+ interface QueryDeveloperTraceToolRef {
357
+ id?: string;
358
+ name?: string;
359
+ method?: string;
360
+ [key: string]: unknown;
361
+ }
362
+ /**
363
+ * Loop metadata attached to developer trace timeline steps.
364
+ */
365
+ interface QueryDeveloperTraceLoopInfo {
366
+ name?: string;
367
+ iteration?: number;
368
+ maxIterations?: number;
369
+ [key: string]: unknown;
370
+ }
371
+ /**
372
+ * A single developer-trace timeline step.
373
+ */
374
+ interface QueryDeveloperTraceStep {
375
+ stepType?: string;
376
+ event?: string;
377
+ status?: string;
378
+ message?: string;
379
+ timestampMs?: number;
380
+ tool?: QueryDeveloperTraceToolRef;
381
+ attempt?: number;
382
+ loop?: QueryDeveloperTraceLoopInfo;
383
+ metadata?: Record<string, unknown>;
384
+ [key: string]: unknown;
385
+ }
386
+ /**
387
+ * Aggregate counters that summarize developer-trace behavior.
388
+ */
389
+ interface QueryDeveloperTraceSummary {
390
+ toolCalls?: number;
391
+ retryCount?: number;
392
+ selfHealCount?: number;
393
+ fallbackCount?: number;
394
+ failureCount?: number;
395
+ recoveryCount?: number;
396
+ completionChecks?: number;
397
+ loopCount?: number;
398
+ [key: string]: unknown;
399
+ }
400
+ /**
401
+ * Developer Mode trace payload returned per query response (opt-in).
402
+ */
403
+ interface QueryDeveloperTrace {
404
+ summary?: QueryDeveloperTraceSummary;
405
+ timeline?: QueryDeveloperTraceStep[];
406
+ [key: string]: unknown;
407
+ }
328
408
  /**
329
409
  * Information about a tool that was used during a query response
330
410
  */
@@ -364,6 +444,8 @@ interface QueryResult {
364
444
  data?: unknown;
365
445
  /** Optional blob URL for persisted execution data (when includeDataUrl=true) */
366
446
  dataUrl?: string;
447
+ /** Optional machine-readable Developer Mode trace payload */
448
+ developerTrace?: QueryDeveloperTrace;
367
449
  }
368
450
  /**
369
451
  * Successful response from the /api/v1/query endpoint
@@ -376,6 +458,7 @@ interface QueryApiSuccessResponse {
376
458
  durationMs: number;
377
459
  data?: unknown;
378
460
  dataUrl?: string;
461
+ developerTrace?: QueryDeveloperTrace;
379
462
  }
380
463
  /**
381
464
  * Raw API response from the query endpoint
@@ -395,6 +478,11 @@ interface QueryStreamTextDeltaEvent {
395
478
  type: "text-delta";
396
479
  delta: string;
397
480
  }
481
+ /** Emitted when the server streams developer trace updates/chunks */
482
+ interface QueryStreamDeveloperTraceEvent {
483
+ type: "developer-trace";
484
+ trace: QueryDeveloperTrace;
485
+ }
398
486
  /** Emitted when the full response is complete */
399
487
  interface QueryStreamDoneEvent {
400
488
  type: "done";
@@ -403,7 +491,7 @@ interface QueryStreamDoneEvent {
403
491
  /**
404
492
  * Union of all events emitted during a streaming query
405
493
  */
406
- type QueryStreamEvent = QueryStreamToolStatusEvent | QueryStreamTextDeltaEvent | QueryStreamDoneEvent;
494
+ type QueryStreamEvent = QueryStreamToolStatusEvent | QueryStreamTextDeltaEvent | QueryStreamDeveloperTraceEvent | QueryStreamDoneEvent;
407
495
  /**
408
496
  * Specific error codes returned by the Context Protocol API
409
497
  */
@@ -515,6 +603,10 @@ declare class Tools {
515
603
  declare class Query {
516
604
  private client;
517
605
  constructor(client: ContextClient);
606
+ private buildSyntheticTraceFromRunResult;
607
+ private buildSyntheticTraceFromStreamStatus;
608
+ private mergeDeveloperTrace;
609
+ private parseStreamEvent;
518
610
  /**
519
611
  * Run an agentic query and wait for the full response.
520
612
  *
@@ -554,6 +646,7 @@ declare class Query {
554
646
  * Event types:
555
647
  * - `tool-status` — A tool started executing or changed status
556
648
  * - `text-delta` — A chunk of the AI response text
649
+ * - `developer-trace` — Runtime trace metadata (when includeDeveloperTrace=true)
557
650
  * - `done` — The full response is complete (includes final `QueryResult`)
558
651
  *
559
652
  * @param options - Query options or a plain string question
@@ -569,6 +662,9 @@ declare class Query {
569
662
  * case "text-delta":
570
663
  * process.stdout.write(event.delta);
571
664
  * break;
665
+ * case "developer-trace":
666
+ * console.log("Trace summary:", event.trace.summary);
667
+ * break;
572
668
  * case "done":
573
669
  * console.log("\nCost:", event.result.cost.totalCostUsd);
574
670
  * break;
@@ -607,6 +703,8 @@ declare class Query {
607
703
  declare class ContextClient {
608
704
  private readonly apiKey;
609
705
  private readonly baseUrl;
706
+ private readonly requestTimeoutMs;
707
+ private readonly streamTimeoutMs;
610
708
  private _closed;
611
709
  /**
612
710
  * Discovery resource for searching tools
@@ -629,7 +727,9 @@ declare class ContextClient {
629
727
  *
630
728
  * @param options - Client configuration options
631
729
  * @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
632
- * @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
730
+ * @param options.baseUrl - Optional base URL override (defaults to https://www.ctxprotocol.com)
731
+ * @param options.requestTimeoutMs - Optional timeout for non-streaming requests (default 300000ms)
732
+ * @param options.streamTimeoutMs - Optional timeout for establishing stream requests (default 600000ms)
633
733
  */
634
734
  constructor(options: ContextClientOptions);
635
735
  /**
@@ -639,7 +739,7 @@ declare class ContextClient {
639
739
  close(): void;
640
740
  /**
641
741
  * Internal method for making authenticated HTTP requests
642
- * Includes timeout (30s) and retry with exponential backoff for transient errors
742
+ * Includes timeout and retry with exponential backoff for transient errors
643
743
  *
644
744
  * @internal
645
745
  */
@@ -647,10 +747,11 @@ declare class ContextClient {
647
747
  /**
648
748
  * Internal method for making authenticated HTTP requests that returns
649
749
  * the raw Response object. Used for streaming endpoints (SSE).
750
+ * Includes a configurable timeout for stream setup.
650
751
  *
651
752
  * @internal
652
753
  */
653
754
  _fetchRaw(endpoint: string, options?: RequestInit): Promise<Response>;
654
755
  }
655
756
 
656
- export { ContextClient, type ContextClientOptions, ContextError, type ContextErrorCode, Discovery, type ExecuteApiErrorResponse, type ExecuteApiResponse, type ExecuteApiSuccessResponse, type ExecuteOptions, type ExecuteSessionApiResponse, type ExecuteSessionApiSuccessResponse, type ExecuteSessionResult, type ExecuteSessionSpend, type ExecuteSessionStartOptions, type ExecuteSessionStatus, type ExecutionResult, type McpTool, type McpToolMeta, type McpToolRateLimitHints, Query, type QueryApiResponse, type QueryApiSuccessResponse, type QueryCost, type QueryOptions, type QueryResult, type QueryStreamDoneEvent, type QueryStreamEvent, type QueryStreamTextDeltaEvent, type QueryStreamToolStatusEvent, type QueryToolUsage, type SearchOptions, type SearchResponse, type Tool, Tools };
757
+ export { ContextClient, type ContextClientOptions, ContextError, type ContextErrorCode, Discovery, type ExecuteApiErrorResponse, type ExecuteApiResponse, type ExecuteApiSuccessResponse, type ExecuteOptions, type ExecuteSessionApiResponse, type ExecuteSessionApiSuccessResponse, type ExecuteSessionResult, type ExecuteSessionSpend, type ExecuteSessionStartOptions, type ExecuteSessionStatus, type ExecutionResult, type McpTool, type McpToolMeta, type McpToolRateLimitHints, Query, type QueryApiResponse, type QueryApiSuccessResponse, type QueryCost, type QueryDeveloperTrace, type QueryDeveloperTraceLoopInfo, type QueryDeveloperTraceStep, type QueryDeveloperTraceSummary, type QueryDeveloperTraceToolRef, type QueryOptions, type QueryResult, type QueryStreamDeveloperTraceEvent, type QueryStreamDoneEvent, type QueryStreamEvent, type QueryStreamTextDeltaEvent, type QueryStreamToolStatusEvent, type QueryToolUsage, type SearchOptions, type SearchResponse, type Tool, Tools };
@@ -226,6 +226,114 @@ var Query = class {
226
226
  constructor(client) {
227
227
  this.client = client;
228
228
  }
229
+ buildSyntheticTraceFromRunResult(params) {
230
+ const timeline = params.toolsUsed.map((tool, index) => ({
231
+ stepType: "tool-call",
232
+ event: "tool-call",
233
+ status: "success",
234
+ timestampMs: index,
235
+ tool: {
236
+ id: tool.id,
237
+ name: tool.name
238
+ },
239
+ metadata: {
240
+ skillCalls: tool.skillCalls,
241
+ synthetic: true
242
+ }
243
+ }));
244
+ const toolCalls = params.toolsUsed.reduce(
245
+ (sum, tool) => sum + Math.max(tool.skillCalls, 0),
246
+ 0
247
+ );
248
+ return {
249
+ summary: {
250
+ toolCalls,
251
+ retryCount: 0,
252
+ selfHealCount: 0,
253
+ fallbackCount: 0,
254
+ failureCount: 0,
255
+ recoveryCount: 0,
256
+ completionChecks: 0,
257
+ loopCount: 0
258
+ },
259
+ timeline,
260
+ source: "sdk-fallback",
261
+ synthetic: true,
262
+ reason: "backend_trace_missing",
263
+ durationMs: params.durationMs
264
+ };
265
+ }
266
+ buildSyntheticTraceFromStreamStatus(params) {
267
+ const timeline = params.statusTimeline.map((entry, index) => ({
268
+ stepType: "tool-status",
269
+ event: "tool-status",
270
+ status: entry.status,
271
+ timestampMs: index,
272
+ tool: entry.tool.name || entry.tool.id ? {
273
+ id: entry.tool.id || void 0,
274
+ name: entry.tool.name || void 0
275
+ } : void 0,
276
+ metadata: { synthetic: true }
277
+ }));
278
+ const toolCallsFromUsage = params.toolsUsed.reduce(
279
+ (sum, tool) => sum + Math.max(tool.skillCalls, 0),
280
+ 0
281
+ );
282
+ const toolCallsFromStatus = params.statusTimeline.filter(
283
+ (entry) => entry.status === "tool-complete"
284
+ ).length;
285
+ const toolCalls = toolCallsFromUsage > 0 ? toolCallsFromUsage : toolCallsFromStatus;
286
+ const retryCount = params.statusTimeline.filter(
287
+ (entry) => /(retry|fix|reflect|recover)/i.test(entry.status)
288
+ ).length;
289
+ const completionChecks = params.statusTimeline.filter(
290
+ (entry) => /complet/i.test(entry.status)
291
+ ).length;
292
+ return {
293
+ summary: {
294
+ toolCalls,
295
+ retryCount,
296
+ selfHealCount: retryCount,
297
+ fallbackCount: 0,
298
+ failureCount: 0,
299
+ recoveryCount: 0,
300
+ completionChecks,
301
+ loopCount: retryCount
302
+ },
303
+ timeline,
304
+ source: "sdk-fallback",
305
+ synthetic: true,
306
+ reason: "backend_trace_missing",
307
+ durationMs: params.durationMs
308
+ };
309
+ }
310
+ mergeDeveloperTrace(first, second) {
311
+ if (!first) return second;
312
+ if (!second) return first;
313
+ const firstTimeline = Array.isArray(first.timeline) ? first.timeline : [];
314
+ const secondTimeline = Array.isArray(second.timeline) ? second.timeline : [];
315
+ const mergedTimeline = [...firstTimeline, ...secondTimeline];
316
+ return {
317
+ ...first,
318
+ ...second,
319
+ summary: {
320
+ ...typeof first.summary === "object" && first.summary ? first.summary : {},
321
+ ...typeof second.summary === "object" && second.summary ? second.summary : {}
322
+ },
323
+ ...mergedTimeline.length > 0 ? { timeline: mergedTimeline } : {}
324
+ };
325
+ }
326
+ parseStreamEvent(rawData) {
327
+ const parsed = JSON.parse(rawData);
328
+ if (!parsed || typeof parsed !== "object") {
329
+ return void 0;
330
+ }
331
+ const event = parsed;
332
+ if (typeof event.type !== "string") {
333
+ return void 0;
334
+ }
335
+ return event;
336
+ }
229
337
  /**
230
338
  * Run an agentic query and wait for the full response.
231
339
  *
@@ -271,6 +379,8 @@ var Query = class {
271
379
  modelId: opts.modelId,
272
380
  includeData: opts.includeData,
273
381
  includeDataUrl: opts.includeDataUrl,
382
+ includeDeveloperTrace: opts.includeDeveloperTrace,
383
+ queryDepth: opts.queryDepth,
274
384
  stream: false
275
385
  })
276
386
  }
@@ -284,13 +394,18 @@ var Query = class {
284
394
  );
285
395
  }
286
396
  if (response.success) {
397
+ const developerTrace = response.developerTrace ?? (opts.includeDeveloperTrace ? this.buildSyntheticTraceFromRunResult({
398
+ toolsUsed: response.toolsUsed,
399
+ durationMs: response.durationMs
400
+ }) : void 0);
287
401
  return {
288
402
  response: response.response,
289
403
  toolsUsed: response.toolsUsed,
290
404
  cost: response.cost,
291
405
  durationMs: response.durationMs,
292
406
  data: response.data,
293
- dataUrl: response.dataUrl
407
+ dataUrl: response.dataUrl,
408
+ developerTrace
294
409
  };
295
410
  }
296
411
  throw new ContextError("Unexpected response format from query API");
@@ -302,6 +417,7 @@ var Query = class {
302
417
  * Event types:
303
418
  * - `tool-status` — A tool started executing or changed status
304
419
  * - `text-delta` — A chunk of the AI response text
420
+ * - `developer-trace` — Runtime trace metadata (when includeDeveloperTrace=true)
305
421
  * - `done` — The full response is complete (includes final `QueryResult`)
306
422
  *
307
423
  * @param options - Query options or a plain string question
@@ -317,6 +433,9 @@ var Query = class {
317
433
  * case "text-delta":
318
434
  * process.stdout.write(event.delta);
319
435
  * break;
436
+ * case "developer-trace":
437
+ * console.log("Trace summary:", event.trace.summary);
438
+ * break;
320
439
  * case "done":
321
440
  * console.log("\nCost:", event.result.cost.totalCostUsd);
322
441
  * break;
@@ -336,6 +455,8 @@ var Query = class {
336
455
  modelId: opts.modelId,
337
456
  includeData: opts.includeData,
338
457
  includeDataUrl: opts.includeDataUrl,
458
+ includeDeveloperTrace: opts.includeDeveloperTrace,
459
+ queryDepth: opts.queryDepth,
339
460
  stream: true
340
461
  })
341
462
  });
@@ -346,6 +467,45 @@ var Query = class {
346
467
  const reader = body.getReader();
347
468
  const decoder = new TextDecoder();
348
469
  let buffer = "";
470
+ let aggregatedTrace;
471
+ const statusTimeline = [];
472
+ const parseAndHydrateEvent = (rawData) => {
473
+ const event = this.parseStreamEvent(rawData);
474
+ if (!event) {
475
+ return void 0;
476
+ }
477
+ if (event.type === "developer-trace") {
478
+ aggregatedTrace = this.mergeDeveloperTrace(aggregatedTrace, event.trace);
479
+ return event;
480
+ }
481
+ if (event.type === "tool-status") {
482
+ statusTimeline.push({
483
+ status: event.status,
484
+ tool: {
485
+ id: event.tool.id,
486
+ name: event.tool.name
487
+ }
488
+ });
489
+ return event;
490
+ }
491
+ if (event.type === "done") {
492
+ let mergedTrace = this.mergeDeveloperTrace(
493
+ aggregatedTrace,
494
+ event.result.developerTrace
495
+ );
496
+ if (!mergedTrace && opts.includeDeveloperTrace) {
497
+ mergedTrace = this.buildSyntheticTraceFromStreamStatus({
498
+ statusTimeline,
499
+ toolsUsed: event.result.toolsUsed,
500
+ durationMs: event.result.durationMs
501
+ });
502
+ }
503
+ if (mergedTrace) {
504
+ event.result.developerTrace = mergedTrace;
505
+ }
506
+ }
507
+ return event;
508
+ };
349
509
  try {
350
510
  while (true) {
351
511
  const { done, value } = await reader.read();
@@ -359,7 +519,10 @@ var Query = class {
359
519
  const data = trimmed.slice(6);
360
520
  if (data === "[DONE]") return;
361
521
  try {
362
- yield JSON.parse(data);
522
+ const event = parseAndHydrateEvent(data);
523
+ if (event) {
524
+ yield event;
525
+ }
363
526
  } catch {
364
527
  }
365
528
  }
@@ -369,7 +532,10 @@ var Query = class {
369
532
  const data = buffer.trim().slice(6);
370
533
  if (data !== "[DONE]") {
371
534
  try {
372
- yield JSON.parse(data);
535
+ const event = parseAndHydrateEvent(data);
536
+ if (event) {
537
+ yield event;
538
+ }
373
539
  } catch {
374
540
  }
375
541
  }
@@ -381,9 +547,14 @@ var Query = class {
381
547
  };
382
548
 
383
549
  // src/client/client.ts
550
+ var DEFAULT_BASE_URL = "https://www.ctxprotocol.com";
551
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
552
+ var DEFAULT_STREAM_TIMEOUT_MS = 6e5;
384
553
  var ContextClient = class {
385
554
  apiKey;
386
555
  baseUrl;
556
+ requestTimeoutMs;
557
+ streamTimeoutMs;
387
558
  _closed = false;
388
559
  /**
389
560
  * Discovery resource for searching tools
@@ -406,14 +577,26 @@ var ContextClient = class {
406
577
  *
407
578
  * @param options - Client configuration options
408
579
  * @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
409
- * @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
580
+ * @param options.baseUrl - Optional base URL override (defaults to https://www.ctxprotocol.com)
581
+ * @param options.requestTimeoutMs - Optional timeout for non-streaming requests (default 300000ms)
582
+ * @param options.streamTimeoutMs - Optional timeout for establishing stream requests (default 600000ms)
410
583
  */
411
584
  constructor(options) {
412
585
  if (!options.apiKey) {
413
586
  throw new ContextError("API key is required");
414
587
  }
588
+ const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
589
+ const streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;
590
+ if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) {
591
+ throw new ContextError("requestTimeoutMs must be a positive number");
592
+ }
593
+ if (!Number.isFinite(streamTimeoutMs) || streamTimeoutMs <= 0) {
594
+ throw new ContextError("streamTimeoutMs must be a positive number");
595
+ }
415
596
  this.apiKey = options.apiKey;
416
- this.baseUrl = (options.baseUrl ?? "https://ctxprotocol.com").replace(/\/$/, "");
597
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
598
+ this.requestTimeoutMs = requestTimeoutMs;
599
+ this.streamTimeoutMs = streamTimeoutMs;
417
600
  this.discovery = new Discovery(this);
418
601
  this.tools = new Tools(this);
419
602
  this.query = new Query(this);
@@ -427,7 +610,7 @@ var ContextClient = class {
427
610
  }
428
611
  /**
429
612
  * Internal method for making authenticated HTTP requests
430
- * Includes timeout (30s) and retry with exponential backoff for transient errors
613
+ * Includes timeout and retry with exponential backoff for transient errors
431
614
  *
432
615
  * @internal
433
616
  */
@@ -437,7 +620,7 @@ var ContextClient = class {
437
620
  }
438
621
  const url = `${this.baseUrl}${endpoint}`;
439
622
  const maxRetries = 3;
440
- const timeoutMs = 3e4;
623
+ const timeoutMs = this.requestTimeoutMs;
441
624
  let lastError;
442
625
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
443
626
  const controller = new AbortController();
@@ -505,6 +688,7 @@ var ContextClient = class {
505
688
  /**
506
689
  * Internal method for making authenticated HTTP requests that returns
507
690
  * the raw Response object. Used for streaming endpoints (SSE).
691
+ * Includes a configurable timeout for stream setup.
508
692
  *
509
693
  * @internal
510
694
  */
@@ -513,14 +697,32 @@ var ContextClient = class {
513
697
  throw new ContextError("Client has been closed");
514
698
  }
515
699
  const url = `${this.baseUrl}${endpoint}`;
516
- const response = await fetch(url, {
517
- ...options,
518
- headers: {
519
- "Content-Type": "application/json",
520
- Authorization: `Bearer ${this.apiKey}`,
521
- ...options.headers
700
+ const controller = new AbortController();
701
+ const timeout = setTimeout(() => controller.abort(), this.streamTimeoutMs);
702
+ let response;
703
+ try {
704
+ response = await fetch(url, {
705
+ ...options,
706
+ signal: controller.signal,
707
+ headers: {
708
+ "Content-Type": "application/json",
709
+ Authorization: `Bearer ${this.apiKey}`,
710
+ ...options.headers
711
+ }
712
+ });
713
+ } catch (error) {
714
+ clearTimeout(timeout);
715
+ const lastError = error instanceof Error ? error : new Error(String(error));
716
+ if (lastError.name === "AbortError") {
717
+ throw new ContextError(
718
+ `Streaming request timed out after ${this.streamTimeoutMs / 1e3}s`,
719
+ void 0,
720
+ 408
721
+ );
522
722
  }
523
- });
723
+ throw new ContextError(lastError.message);
724
+ }
725
+ clearTimeout(timeout);
524
726
  if (!response.ok) {
525
727
  let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
526
728
  let errorCode;