@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/dist/client/index.d.ts
CHANGED
|
@@ -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
|
|
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 };
|
package/dist/client/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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 ??
|
|
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
|
|
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 =
|
|
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
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
...options
|
|
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;
|