@ctxprotocol/sdk 0.8.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/dist/client/index.cjs +56 -50
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +147 -10
- package/dist/client/index.d.ts +147 -10
- package/dist/client/index.js +56 -50
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +56 -50
- 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 +56 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -19,6 +19,14 @@ var Discovery = class {
|
|
|
19
19
|
constructor(client) {
|
|
20
20
|
this.client = client;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch a single marketplace tool by its unique ID.
|
|
24
|
+
*/
|
|
25
|
+
async get(toolId) {
|
|
26
|
+
return this.client._fetch(
|
|
27
|
+
`/api/v1/tools/${encodeURIComponent(toolId)}`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
22
30
|
async search(queryOrOptions, limit) {
|
|
23
31
|
const options = typeof queryOrOptions === "string" ? { query: queryOrOptions, limit } : queryOrOptions;
|
|
24
32
|
const params = new URLSearchParams();
|
|
@@ -342,7 +350,7 @@ var Query = class {
|
|
|
342
350
|
* Run an agentic query and wait for the full response.
|
|
343
351
|
*
|
|
344
352
|
* The server discovers relevant tools (or uses the ones you specify),
|
|
345
|
-
* executes the
|
|
353
|
+
* executes the discovery-first pipeline (up to 100 MCP calls per tool),
|
|
346
354
|
* and returns an AI-synthesized answer. Payment is settled after
|
|
347
355
|
* successful execution via deferred settlement.
|
|
348
356
|
*
|
|
@@ -371,48 +379,25 @@ var Query = class {
|
|
|
371
379
|
*/
|
|
372
380
|
async run(options) {
|
|
373
381
|
const opts = typeof options === "string" ? { query: options } : options;
|
|
374
|
-
|
|
375
|
-
const
|
|
376
|
-
"
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
queryDepth: opts.queryDepth,
|
|
388
|
-
stream: false
|
|
389
|
-
})
|
|
382
|
+
let terminalError;
|
|
383
|
+
for await (const event of this.stream(opts)) {
|
|
384
|
+
if (event.type === "error") {
|
|
385
|
+
terminalError = {
|
|
386
|
+
error: event.error,
|
|
387
|
+
...event.code ? { code: event.code } : {},
|
|
388
|
+
...event.scope ? { scope: event.scope } : {},
|
|
389
|
+
...event.reasonCode ? { reasonCode: event.reasonCode } : {}
|
|
390
|
+
};
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
if (event.type === "done") {
|
|
394
|
+
return event.result;
|
|
390
395
|
}
|
|
391
|
-
);
|
|
392
|
-
if ("error" in response) {
|
|
393
|
-
throw new ContextError(
|
|
394
|
-
response.error,
|
|
395
|
-
response.code,
|
|
396
|
-
void 0,
|
|
397
|
-
response.helpUrl
|
|
398
|
-
);
|
|
399
396
|
}
|
|
400
|
-
if (
|
|
401
|
-
|
|
402
|
-
toolsUsed: response.toolsUsed,
|
|
403
|
-
durationMs: response.durationMs
|
|
404
|
-
}) : void 0);
|
|
405
|
-
return {
|
|
406
|
-
response: response.response,
|
|
407
|
-
toolsUsed: response.toolsUsed,
|
|
408
|
-
cost: response.cost,
|
|
409
|
-
durationMs: response.durationMs,
|
|
410
|
-
data: response.data,
|
|
411
|
-
dataUrl: response.dataUrl,
|
|
412
|
-
developerTrace
|
|
413
|
-
};
|
|
397
|
+
if (terminalError) {
|
|
398
|
+
throw new ContextError(terminalError.error, terminalError.code);
|
|
414
399
|
}
|
|
415
|
-
throw new ContextError("
|
|
400
|
+
throw new ContextError("Streaming query ended before done event");
|
|
416
401
|
}
|
|
417
402
|
/**
|
|
418
403
|
* Run an agentic query with streaming. Returns an async iterable that
|
|
@@ -422,6 +407,7 @@ var Query = class {
|
|
|
422
407
|
* - `tool-status` — A tool started executing or changed status
|
|
423
408
|
* - `text-delta` — A chunk of the AI response text
|
|
424
409
|
* - `developer-trace` — Runtime trace metadata (when includeDeveloperTrace=true)
|
|
410
|
+
* - `error` — A structured query/runtime error emitted before stream completion
|
|
425
411
|
* - `done` — The full response is complete (includes final `QueryResult`)
|
|
426
412
|
*
|
|
427
413
|
* @param options - Query options or a plain string question
|
|
@@ -443,6 +429,9 @@ var Query = class {
|
|
|
443
429
|
* case "done":
|
|
444
430
|
* console.log("\nCost:", event.result.cost.totalCostUsd);
|
|
445
431
|
* break;
|
|
432
|
+
* case "error":
|
|
433
|
+
* console.error("Stream error:", event.error);
|
|
434
|
+
* break;
|
|
446
435
|
* }
|
|
447
436
|
* }
|
|
448
437
|
* ```
|
|
@@ -461,6 +450,7 @@ var Query = class {
|
|
|
461
450
|
includeDataUrl: opts.includeDataUrl,
|
|
462
451
|
includeDeveloperTrace: opts.includeDeveloperTrace,
|
|
463
452
|
queryDepth: opts.queryDepth,
|
|
453
|
+
debugScoutDeepMode: opts.debugScoutDeepMode,
|
|
464
454
|
stream: true
|
|
465
455
|
})
|
|
466
456
|
});
|
|
@@ -498,10 +488,13 @@ var Query = class {
|
|
|
498
488
|
event.result.developerTrace
|
|
499
489
|
);
|
|
500
490
|
if (!mergedTrace && opts.includeDeveloperTrace) {
|
|
501
|
-
mergedTrace = this.buildSyntheticTraceFromStreamStatus({
|
|
491
|
+
mergedTrace = statusTimeline.length > 0 ? this.buildSyntheticTraceFromStreamStatus({
|
|
502
492
|
statusTimeline,
|
|
503
493
|
toolsUsed: event.result.toolsUsed,
|
|
504
494
|
durationMs: event.result.durationMs
|
|
495
|
+
}) : this.buildSyntheticTraceFromRunResult({
|
|
496
|
+
toolsUsed: event.result.toolsUsed,
|
|
497
|
+
durationMs: event.result.durationMs
|
|
505
498
|
});
|
|
506
499
|
}
|
|
507
500
|
if (mergedTrace) {
|
|
@@ -618,30 +611,34 @@ var ContextClient = class {
|
|
|
618
611
|
*
|
|
619
612
|
* @internal
|
|
620
613
|
*/
|
|
621
|
-
async _fetch(endpoint, options = {}) {
|
|
614
|
+
async _fetch(endpoint, options = {}, fetchOptions) {
|
|
622
615
|
if (this._closed) {
|
|
623
616
|
throw new ContextError("Client has been closed");
|
|
624
617
|
}
|
|
625
618
|
const url = `${this.baseUrl}${endpoint}`;
|
|
626
619
|
const maxRetries = 3;
|
|
627
620
|
const timeoutMs = this.requestTimeoutMs;
|
|
621
|
+
const method = (options.method ?? "GET").toUpperCase();
|
|
622
|
+
const requestHeaders = new Headers(options.headers);
|
|
623
|
+
const canRetryRequest = fetchOptions?.retry === false ? false : method === "GET" || method === "HEAD" || method === "OPTIONS" || requestHeaders.has("Idempotency-Key");
|
|
628
624
|
let lastError;
|
|
629
625
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
630
626
|
const controller = new AbortController();
|
|
631
627
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
628
|
+
const mergedHeaders = new Headers(requestHeaders);
|
|
629
|
+
if (!mergedHeaders.has("Content-Type")) {
|
|
630
|
+
mergedHeaders.set("Content-Type", "application/json");
|
|
631
|
+
}
|
|
632
|
+
mergedHeaders.set("Authorization", `Bearer ${this.apiKey}`);
|
|
632
633
|
try {
|
|
633
634
|
const response = await fetch(url, {
|
|
634
635
|
...options,
|
|
635
636
|
signal: controller.signal,
|
|
636
|
-
headers:
|
|
637
|
-
"Content-Type": "application/json",
|
|
638
|
-
Authorization: `Bearer ${this.apiKey}`,
|
|
639
|
-
...options.headers
|
|
640
|
-
}
|
|
637
|
+
headers: mergedHeaders
|
|
641
638
|
});
|
|
642
639
|
clearTimeout(timeout);
|
|
643
640
|
if (!response.ok) {
|
|
644
|
-
if (response.status >= 500 && attempt < maxRetries) {
|
|
641
|
+
if (response.status >= 500 && canRetryRequest && attempt < maxRetries) {
|
|
645
642
|
const delay = Math.min(1e3 * 2 ** attempt, 1e4);
|
|
646
643
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
647
644
|
continue;
|
|
@@ -660,7 +657,16 @@ var ContextClient = class {
|
|
|
660
657
|
}
|
|
661
658
|
throw new ContextError(errorMessage, errorCode, response.status, helpUrl);
|
|
662
659
|
}
|
|
663
|
-
|
|
660
|
+
try {
|
|
661
|
+
return await response.json();
|
|
662
|
+
} catch (error) {
|
|
663
|
+
const parseError = error instanceof Error ? error : new Error(String(error));
|
|
664
|
+
throw new ContextError(
|
|
665
|
+
`Failed to parse JSON response: ${parseError.message}`,
|
|
666
|
+
void 0,
|
|
667
|
+
response.status
|
|
668
|
+
);
|
|
669
|
+
}
|
|
664
670
|
} catch (error) {
|
|
665
671
|
clearTimeout(timeout);
|
|
666
672
|
if (error instanceof ContextError) {
|
|
@@ -668,7 +674,7 @@ var ContextClient = class {
|
|
|
668
674
|
}
|
|
669
675
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
670
676
|
const isRetryable = lastError.name === "AbortError" || lastError.message.includes("fetch failed") || lastError.message.includes("ECONNRESET") || lastError.message.includes("ETIMEDOUT");
|
|
671
|
-
if (isRetryable && attempt < maxRetries) {
|
|
677
|
+
if (isRetryable && canRetryRequest && attempt < maxRetries) {
|
|
672
678
|
const delay = Math.min(1e3 * 2 ** attempt, 1e4);
|
|
673
679
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
674
680
|
continue;
|