@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.
- package/README.md +33 -5
- package/dist/client/index.cjs +216 -14
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +106 -5
- package/dist/client/index.d.ts +106 -5
- package/dist/client/index.js +216 -14
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +216 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +216 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,12 +101,15 @@ console.log(result.session); // methodPrice, spent, remaining, maxSpend, ...
|
|
|
101
101
|
const answer = await client.query.run({
|
|
102
102
|
query: "What are the top whale movements on Base?",
|
|
103
103
|
modelId: "glm-model", // optional: choose a supported model
|
|
104
|
+
queryDepth: "deep", // optional: fast | auto | deep
|
|
104
105
|
includeDataUrl: true, // optional: persist full execution data to blob
|
|
106
|
+
includeDeveloperTrace: true, // optional: include machine-readable runtime trace
|
|
105
107
|
});
|
|
106
108
|
console.log(answer.response); // AI-synthesized answer
|
|
107
109
|
console.log(answer.toolsUsed); // Which tools were used
|
|
108
110
|
console.log(answer.cost); // Cost breakdown
|
|
109
111
|
console.log(answer.dataUrl); // Optional blob URL with full data
|
|
112
|
+
console.log(answer.developerTrace?.summary); // retries/toolCalls/loops summary
|
|
110
113
|
```
|
|
111
114
|
|
|
112
115
|
> Mixed listings are first-class: one listing can expose methods to both surfaces. Methods without `_meta.pricing.executeUsd` remain query-only until priced.
|
|
@@ -298,10 +301,12 @@ If you can answer without a tool, just respond normally.`;
|
|
|
298
301
|
|
|
299
302
|
### Client Options
|
|
300
303
|
|
|
301
|
-
| Option
|
|
302
|
-
|
|
|
303
|
-
| `apiKey`
|
|
304
|
-
| `baseUrl`
|
|
304
|
+
| Option | Type | Required | Default | Description |
|
|
305
|
+
| ------------------ | -------- | -------- | ------------------------------ | --------------------------------------------- |
|
|
306
|
+
| `apiKey` | `string` | Yes | — | Your Context Protocol API key |
|
|
307
|
+
| `baseUrl` | `string` | No | `https://www.ctxprotocol.com` | API base URL (for development) |
|
|
308
|
+
| `requestTimeoutMs` | `number` | No | `300000` | Timeout for non-streaming API calls |
|
|
309
|
+
| `streamTimeoutMs` | `number` | No | `600000` | Timeout for establishing streaming API calls |
|
|
305
310
|
|
|
306
311
|
```typescript
|
|
307
312
|
// Production
|
|
@@ -313,6 +318,8 @@ const client = new ContextClient({
|
|
|
313
318
|
const client = new ContextClient({
|
|
314
319
|
apiKey: "sk_test_...",
|
|
315
320
|
baseUrl: "http://localhost:3000",
|
|
321
|
+
requestTimeoutMs: 420_000,
|
|
322
|
+
streamTimeoutMs: 840_000,
|
|
316
323
|
});
|
|
317
324
|
```
|
|
318
325
|
|
|
@@ -395,6 +402,11 @@ const closed = await client.tools.closeSession("sess_123");
|
|
|
395
402
|
|
|
396
403
|
Run an agentic query. The server discovers answer-safe tools, executes the full pipeline (up to 100 MCP calls per response turn), applies model-aware mediator/data budgeting, and returns an AI-synthesized answer.
|
|
397
404
|
|
|
405
|
+
`queryDepth` controls orchestration depth:
|
|
406
|
+
- `fast`: lower-latency path for simple lookups.
|
|
407
|
+
- `auto`: server routes to either `fast` or `deep` from query intent + selected tool complexity.
|
|
408
|
+
- `deep`: completeness-oriented path (default when omitted).
|
|
409
|
+
|
|
398
410
|
```typescript
|
|
399
411
|
// Simple string
|
|
400
412
|
const answer = await client.query.run("What are the top whale movements on Base?");
|
|
@@ -404,8 +416,10 @@ const answer = await client.query.run({
|
|
|
404
416
|
query: "Analyze whale activity on Base",
|
|
405
417
|
tools: ["tool-uuid-1", "tool-uuid-2"], // optional — auto-discover if omitted
|
|
406
418
|
modelId: "kimi-model-thinking", // optional
|
|
419
|
+
queryDepth: "auto", // optional: fast | auto | deep
|
|
407
420
|
includeData: true, // optional: include execution data inline
|
|
408
421
|
includeDataUrl: true, // optional: include blob URL for full data
|
|
422
|
+
includeDeveloperTrace: true, // optional: include Developer Mode trace
|
|
409
423
|
});
|
|
410
424
|
|
|
411
425
|
console.log(answer.response); // AI-synthesized text
|
|
@@ -414,14 +428,26 @@ console.log(answer.cost); // { modelCostUsd, toolCostUsd, totalCostUsd }
|
|
|
414
428
|
console.log(answer.durationMs); // Total time
|
|
415
429
|
console.log(answer.data); // Optional execution data (when includeData=true)
|
|
416
430
|
console.log(answer.dataUrl); // Optional blob URL (when includeDataUrl=true)
|
|
431
|
+
console.log(answer.developerTrace?.summary); // Optional trace summary (retries/toolCalls/loops)
|
|
417
432
|
```
|
|
418
433
|
|
|
434
|
+
When retrieval-first synthesis rollout is enabled server-side, full-data or truncation-sensitive query requests can switch to retrieval-first context assembly using private stage artifacts and canonical execution data slices. `includeData` and `includeDataUrl` continue to reference the same canonical dataset used for synthesis.
|
|
435
|
+
|
|
419
436
|
#### `client.query.stream(options)`
|
|
420
437
|
|
|
421
438
|
Same as `run()` but streams events in real-time via SSE.
|
|
422
439
|
|
|
440
|
+
Event types:
|
|
441
|
+
- `tool-status`
|
|
442
|
+
- `text-delta`
|
|
443
|
+
- `developer-trace` (when `includeDeveloperTrace=true`)
|
|
444
|
+
- `done`
|
|
445
|
+
|
|
423
446
|
```typescript
|
|
424
|
-
for await (const event of client.query.stream(
|
|
447
|
+
for await (const event of client.query.stream({
|
|
448
|
+
query: "What are the top whale movements?",
|
|
449
|
+
queryDepth: "fast",
|
|
450
|
+
})) {
|
|
425
451
|
switch (event.type) {
|
|
426
452
|
case "tool-status":
|
|
427
453
|
console.log(`Tool ${event.tool.name}: ${event.status}`);
|
|
@@ -456,6 +482,7 @@ import type {
|
|
|
456
482
|
// Query types (pay-per-response)
|
|
457
483
|
QueryOptions,
|
|
458
484
|
QueryResult,
|
|
485
|
+
QueryDeveloperTrace,
|
|
459
486
|
QueryCost,
|
|
460
487
|
QueryStreamEvent,
|
|
461
488
|
ContextErrorCode,
|
|
@@ -533,6 +560,7 @@ interface QueryResult {
|
|
|
533
560
|
durationMs: number;
|
|
534
561
|
data?: unknown; // Optional execution data (includeData=true)
|
|
535
562
|
dataUrl?: string; // Optional blob URL (includeDataUrl=true)
|
|
563
|
+
developerTrace?: QueryDeveloperTrace; // Optional machine-readable runtime trace
|
|
536
564
|
}
|
|
537
565
|
```
|
|
538
566
|
|
package/dist/client/index.cjs
CHANGED
|
@@ -228,6 +228,114 @@ var Query = class {
|
|
|
228
228
|
constructor(client) {
|
|
229
229
|
this.client = client;
|
|
230
230
|
}
|
|
231
|
+
buildSyntheticTraceFromRunResult(params) {
|
|
232
|
+
const timeline = params.toolsUsed.map((tool, index) => ({
|
|
233
|
+
stepType: "tool-call",
|
|
234
|
+
event: "tool-call",
|
|
235
|
+
status: "success",
|
|
236
|
+
timestampMs: index,
|
|
237
|
+
tool: {
|
|
238
|
+
id: tool.id,
|
|
239
|
+
name: tool.name
|
|
240
|
+
},
|
|
241
|
+
metadata: {
|
|
242
|
+
skillCalls: tool.skillCalls,
|
|
243
|
+
synthetic: true
|
|
244
|
+
}
|
|
245
|
+
}));
|
|
246
|
+
const toolCalls = params.toolsUsed.reduce(
|
|
247
|
+
(sum, tool) => sum + Math.max(tool.skillCalls, 0),
|
|
248
|
+
0
|
|
249
|
+
);
|
|
250
|
+
return {
|
|
251
|
+
summary: {
|
|
252
|
+
toolCalls,
|
|
253
|
+
retryCount: 0,
|
|
254
|
+
selfHealCount: 0,
|
|
255
|
+
fallbackCount: 0,
|
|
256
|
+
failureCount: 0,
|
|
257
|
+
recoveryCount: 0,
|
|
258
|
+
completionChecks: 0,
|
|
259
|
+
loopCount: 0
|
|
260
|
+
},
|
|
261
|
+
timeline,
|
|
262
|
+
source: "sdk-fallback",
|
|
263
|
+
synthetic: true,
|
|
264
|
+
reason: "backend_trace_missing",
|
|
265
|
+
durationMs: params.durationMs
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
buildSyntheticTraceFromStreamStatus(params) {
|
|
269
|
+
const timeline = params.statusTimeline.map((entry, index) => ({
|
|
270
|
+
stepType: "tool-status",
|
|
271
|
+
event: "tool-status",
|
|
272
|
+
status: entry.status,
|
|
273
|
+
timestampMs: index,
|
|
274
|
+
tool: entry.tool.name || entry.tool.id ? {
|
|
275
|
+
id: entry.tool.id || void 0,
|
|
276
|
+
name: entry.tool.name || void 0
|
|
277
|
+
} : void 0,
|
|
278
|
+
metadata: { synthetic: true }
|
|
279
|
+
}));
|
|
280
|
+
const toolCallsFromUsage = params.toolsUsed.reduce(
|
|
281
|
+
(sum, tool) => sum + Math.max(tool.skillCalls, 0),
|
|
282
|
+
0
|
|
283
|
+
);
|
|
284
|
+
const toolCallsFromStatus = params.statusTimeline.filter(
|
|
285
|
+
(entry) => entry.status === "tool-complete"
|
|
286
|
+
).length;
|
|
287
|
+
const toolCalls = toolCallsFromUsage > 0 ? toolCallsFromUsage : toolCallsFromStatus;
|
|
288
|
+
const retryCount = params.statusTimeline.filter(
|
|
289
|
+
(entry) => /(retry|fix|reflect|recover)/i.test(entry.status)
|
|
290
|
+
).length;
|
|
291
|
+
const completionChecks = params.statusTimeline.filter(
|
|
292
|
+
(entry) => /complet/i.test(entry.status)
|
|
293
|
+
).length;
|
|
294
|
+
return {
|
|
295
|
+
summary: {
|
|
296
|
+
toolCalls,
|
|
297
|
+
retryCount,
|
|
298
|
+
selfHealCount: retryCount,
|
|
299
|
+
fallbackCount: 0,
|
|
300
|
+
failureCount: 0,
|
|
301
|
+
recoveryCount: 0,
|
|
302
|
+
completionChecks,
|
|
303
|
+
loopCount: retryCount
|
|
304
|
+
},
|
|
305
|
+
timeline,
|
|
306
|
+
source: "sdk-fallback",
|
|
307
|
+
synthetic: true,
|
|
308
|
+
reason: "backend_trace_missing",
|
|
309
|
+
durationMs: params.durationMs
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
mergeDeveloperTrace(first, second) {
|
|
313
|
+
if (!first) return second;
|
|
314
|
+
if (!second) return first;
|
|
315
|
+
const firstTimeline = Array.isArray(first.timeline) ? first.timeline : [];
|
|
316
|
+
const secondTimeline = Array.isArray(second.timeline) ? second.timeline : [];
|
|
317
|
+
const mergedTimeline = [...firstTimeline, ...secondTimeline];
|
|
318
|
+
return {
|
|
319
|
+
...first,
|
|
320
|
+
...second,
|
|
321
|
+
summary: {
|
|
322
|
+
...typeof first.summary === "object" && first.summary ? first.summary : {},
|
|
323
|
+
...typeof second.summary === "object" && second.summary ? second.summary : {}
|
|
324
|
+
},
|
|
325
|
+
...mergedTimeline.length > 0 ? { timeline: mergedTimeline } : {}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
parseStreamEvent(rawData) {
|
|
329
|
+
const parsed = JSON.parse(rawData);
|
|
330
|
+
if (!parsed || typeof parsed !== "object") {
|
|
331
|
+
return void 0;
|
|
332
|
+
}
|
|
333
|
+
const event = parsed;
|
|
334
|
+
if (typeof event.type !== "string") {
|
|
335
|
+
return void 0;
|
|
336
|
+
}
|
|
337
|
+
return event;
|
|
338
|
+
}
|
|
231
339
|
/**
|
|
232
340
|
* Run an agentic query and wait for the full response.
|
|
233
341
|
*
|
|
@@ -273,6 +381,8 @@ var Query = class {
|
|
|
273
381
|
modelId: opts.modelId,
|
|
274
382
|
includeData: opts.includeData,
|
|
275
383
|
includeDataUrl: opts.includeDataUrl,
|
|
384
|
+
includeDeveloperTrace: opts.includeDeveloperTrace,
|
|
385
|
+
queryDepth: opts.queryDepth,
|
|
276
386
|
stream: false
|
|
277
387
|
})
|
|
278
388
|
}
|
|
@@ -286,13 +396,18 @@ var Query = class {
|
|
|
286
396
|
);
|
|
287
397
|
}
|
|
288
398
|
if (response.success) {
|
|
399
|
+
const developerTrace = response.developerTrace ?? (opts.includeDeveloperTrace ? this.buildSyntheticTraceFromRunResult({
|
|
400
|
+
toolsUsed: response.toolsUsed,
|
|
401
|
+
durationMs: response.durationMs
|
|
402
|
+
}) : void 0);
|
|
289
403
|
return {
|
|
290
404
|
response: response.response,
|
|
291
405
|
toolsUsed: response.toolsUsed,
|
|
292
406
|
cost: response.cost,
|
|
293
407
|
durationMs: response.durationMs,
|
|
294
408
|
data: response.data,
|
|
295
|
-
dataUrl: response.dataUrl
|
|
409
|
+
dataUrl: response.dataUrl,
|
|
410
|
+
developerTrace
|
|
296
411
|
};
|
|
297
412
|
}
|
|
298
413
|
throw new ContextError("Unexpected response format from query API");
|
|
@@ -304,6 +419,7 @@ var Query = class {
|
|
|
304
419
|
* Event types:
|
|
305
420
|
* - `tool-status` — A tool started executing or changed status
|
|
306
421
|
* - `text-delta` — A chunk of the AI response text
|
|
422
|
+
* - `developer-trace` — Runtime trace metadata (when includeDeveloperTrace=true)
|
|
307
423
|
* - `done` — The full response is complete (includes final `QueryResult`)
|
|
308
424
|
*
|
|
309
425
|
* @param options - Query options or a plain string question
|
|
@@ -319,6 +435,9 @@ var Query = class {
|
|
|
319
435
|
* case "text-delta":
|
|
320
436
|
* process.stdout.write(event.delta);
|
|
321
437
|
* break;
|
|
438
|
+
* case "developer-trace":
|
|
439
|
+
* console.log("Trace summary:", event.trace.summary);
|
|
440
|
+
* break;
|
|
322
441
|
* case "done":
|
|
323
442
|
* console.log("\nCost:", event.result.cost.totalCostUsd);
|
|
324
443
|
* break;
|
|
@@ -338,6 +457,8 @@ var Query = class {
|
|
|
338
457
|
modelId: opts.modelId,
|
|
339
458
|
includeData: opts.includeData,
|
|
340
459
|
includeDataUrl: opts.includeDataUrl,
|
|
460
|
+
includeDeveloperTrace: opts.includeDeveloperTrace,
|
|
461
|
+
queryDepth: opts.queryDepth,
|
|
341
462
|
stream: true
|
|
342
463
|
})
|
|
343
464
|
});
|
|
@@ -348,6 +469,45 @@ var Query = class {
|
|
|
348
469
|
const reader = body.getReader();
|
|
349
470
|
const decoder = new TextDecoder();
|
|
350
471
|
let buffer = "";
|
|
472
|
+
let aggregatedTrace;
|
|
473
|
+
const statusTimeline = [];
|
|
474
|
+
const parseAndHydrateEvent = (rawData) => {
|
|
475
|
+
const event = this.parseStreamEvent(rawData);
|
|
476
|
+
if (!event) {
|
|
477
|
+
return void 0;
|
|
478
|
+
}
|
|
479
|
+
if (event.type === "developer-trace") {
|
|
480
|
+
aggregatedTrace = this.mergeDeveloperTrace(aggregatedTrace, event.trace);
|
|
481
|
+
return event;
|
|
482
|
+
}
|
|
483
|
+
if (event.type === "tool-status") {
|
|
484
|
+
statusTimeline.push({
|
|
485
|
+
status: event.status,
|
|
486
|
+
tool: {
|
|
487
|
+
id: event.tool.id,
|
|
488
|
+
name: event.tool.name
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
return event;
|
|
492
|
+
}
|
|
493
|
+
if (event.type === "done") {
|
|
494
|
+
let mergedTrace = this.mergeDeveloperTrace(
|
|
495
|
+
aggregatedTrace,
|
|
496
|
+
event.result.developerTrace
|
|
497
|
+
);
|
|
498
|
+
if (!mergedTrace && opts.includeDeveloperTrace) {
|
|
499
|
+
mergedTrace = this.buildSyntheticTraceFromStreamStatus({
|
|
500
|
+
statusTimeline,
|
|
501
|
+
toolsUsed: event.result.toolsUsed,
|
|
502
|
+
durationMs: event.result.durationMs
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
if (mergedTrace) {
|
|
506
|
+
event.result.developerTrace = mergedTrace;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return event;
|
|
510
|
+
};
|
|
351
511
|
try {
|
|
352
512
|
while (true) {
|
|
353
513
|
const { done, value } = await reader.read();
|
|
@@ -361,7 +521,10 @@ var Query = class {
|
|
|
361
521
|
const data = trimmed.slice(6);
|
|
362
522
|
if (data === "[DONE]") return;
|
|
363
523
|
try {
|
|
364
|
-
|
|
524
|
+
const event = parseAndHydrateEvent(data);
|
|
525
|
+
if (event) {
|
|
526
|
+
yield event;
|
|
527
|
+
}
|
|
365
528
|
} catch {
|
|
366
529
|
}
|
|
367
530
|
}
|
|
@@ -371,7 +534,10 @@ var Query = class {
|
|
|
371
534
|
const data = buffer.trim().slice(6);
|
|
372
535
|
if (data !== "[DONE]") {
|
|
373
536
|
try {
|
|
374
|
-
|
|
537
|
+
const event = parseAndHydrateEvent(data);
|
|
538
|
+
if (event) {
|
|
539
|
+
yield event;
|
|
540
|
+
}
|
|
375
541
|
} catch {
|
|
376
542
|
}
|
|
377
543
|
}
|
|
@@ -383,9 +549,14 @@ var Query = class {
|
|
|
383
549
|
};
|
|
384
550
|
|
|
385
551
|
// src/client/client.ts
|
|
552
|
+
var DEFAULT_BASE_URL = "https://www.ctxprotocol.com";
|
|
553
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
|
|
554
|
+
var DEFAULT_STREAM_TIMEOUT_MS = 6e5;
|
|
386
555
|
var ContextClient = class {
|
|
387
556
|
apiKey;
|
|
388
557
|
baseUrl;
|
|
558
|
+
requestTimeoutMs;
|
|
559
|
+
streamTimeoutMs;
|
|
389
560
|
_closed = false;
|
|
390
561
|
/**
|
|
391
562
|
* Discovery resource for searching tools
|
|
@@ -408,14 +579,26 @@ var ContextClient = class {
|
|
|
408
579
|
*
|
|
409
580
|
* @param options - Client configuration options
|
|
410
581
|
* @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
|
|
411
|
-
* @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
|
|
582
|
+
* @param options.baseUrl - Optional base URL override (defaults to https://www.ctxprotocol.com)
|
|
583
|
+
* @param options.requestTimeoutMs - Optional timeout for non-streaming requests (default 300000ms)
|
|
584
|
+
* @param options.streamTimeoutMs - Optional timeout for establishing stream requests (default 600000ms)
|
|
412
585
|
*/
|
|
413
586
|
constructor(options) {
|
|
414
587
|
if (!options.apiKey) {
|
|
415
588
|
throw new ContextError("API key is required");
|
|
416
589
|
}
|
|
590
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
591
|
+
const streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;
|
|
592
|
+
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) {
|
|
593
|
+
throw new ContextError("requestTimeoutMs must be a positive number");
|
|
594
|
+
}
|
|
595
|
+
if (!Number.isFinite(streamTimeoutMs) || streamTimeoutMs <= 0) {
|
|
596
|
+
throw new ContextError("streamTimeoutMs must be a positive number");
|
|
597
|
+
}
|
|
417
598
|
this.apiKey = options.apiKey;
|
|
418
|
-
this.baseUrl = (options.baseUrl ??
|
|
599
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
600
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
601
|
+
this.streamTimeoutMs = streamTimeoutMs;
|
|
419
602
|
this.discovery = new Discovery(this);
|
|
420
603
|
this.tools = new Tools(this);
|
|
421
604
|
this.query = new Query(this);
|
|
@@ -429,7 +612,7 @@ var ContextClient = class {
|
|
|
429
612
|
}
|
|
430
613
|
/**
|
|
431
614
|
* Internal method for making authenticated HTTP requests
|
|
432
|
-
* Includes timeout
|
|
615
|
+
* Includes timeout and retry with exponential backoff for transient errors
|
|
433
616
|
*
|
|
434
617
|
* @internal
|
|
435
618
|
*/
|
|
@@ -439,7 +622,7 @@ var ContextClient = class {
|
|
|
439
622
|
}
|
|
440
623
|
const url = `${this.baseUrl}${endpoint}`;
|
|
441
624
|
const maxRetries = 3;
|
|
442
|
-
const timeoutMs =
|
|
625
|
+
const timeoutMs = this.requestTimeoutMs;
|
|
443
626
|
let lastError;
|
|
444
627
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
445
628
|
const controller = new AbortController();
|
|
@@ -507,6 +690,7 @@ var ContextClient = class {
|
|
|
507
690
|
/**
|
|
508
691
|
* Internal method for making authenticated HTTP requests that returns
|
|
509
692
|
* the raw Response object. Used for streaming endpoints (SSE).
|
|
693
|
+
* Includes a configurable timeout for stream setup.
|
|
510
694
|
*
|
|
511
695
|
* @internal
|
|
512
696
|
*/
|
|
@@ -515,14 +699,32 @@ var ContextClient = class {
|
|
|
515
699
|
throw new ContextError("Client has been closed");
|
|
516
700
|
}
|
|
517
701
|
const url = `${this.baseUrl}${endpoint}`;
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
...options
|
|
702
|
+
const controller = new AbortController();
|
|
703
|
+
const timeout = setTimeout(() => controller.abort(), this.streamTimeoutMs);
|
|
704
|
+
let response;
|
|
705
|
+
try {
|
|
706
|
+
response = await fetch(url, {
|
|
707
|
+
...options,
|
|
708
|
+
signal: controller.signal,
|
|
709
|
+
headers: {
|
|
710
|
+
"Content-Type": "application/json",
|
|
711
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
712
|
+
...options.headers
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
} catch (error) {
|
|
716
|
+
clearTimeout(timeout);
|
|
717
|
+
const lastError = error instanceof Error ? error : new Error(String(error));
|
|
718
|
+
if (lastError.name === "AbortError") {
|
|
719
|
+
throw new ContextError(
|
|
720
|
+
`Streaming request timed out after ${this.streamTimeoutMs / 1e3}s`,
|
|
721
|
+
void 0,
|
|
722
|
+
408
|
|
723
|
+
);
|
|
524
724
|
}
|
|
525
|
-
|
|
725
|
+
throw new ContextError(lastError.message);
|
|
726
|
+
}
|
|
727
|
+
clearTimeout(timeout);
|
|
526
728
|
if (!response.ok) {
|
|
527
729
|
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
528
730
|
let errorCode;
|