@ctxprotocol/sdk 0.8.1 → 0.8.3
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 +128 -31
- package/dist/client/index.cjs +166 -32
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +155 -17
- package/dist/client/index.d.ts +155 -17
- package/dist/client/index.js +166 -32
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +166 -32
- 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 +166 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,27 +17,36 @@ var Discovery = class {
|
|
|
17
17
|
constructor(client) {
|
|
18
18
|
this.client = client;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*
|
|
23
|
-
* @param query - The search query (e.g., "gas prices", "nft metadata")
|
|
24
|
-
* @param limit - Maximum number of results (1-50, default 10)
|
|
25
|
-
* @returns Array of matching tools
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* const tools = await client.discovery.search("gas prices");
|
|
30
|
-
* console.log(tools[0].name); // "Gas Price Oracle"
|
|
31
|
-
* console.log(tools[0].mcpTools); // Available methods
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
|
-
async search(query, limit) {
|
|
20
|
+
async search(queryOrOptions, limit) {
|
|
21
|
+
const options = typeof queryOrOptions === "string" ? { query: queryOrOptions, limit } : queryOrOptions;
|
|
35
22
|
const params = new URLSearchParams();
|
|
23
|
+
const query = options.query ?? "";
|
|
36
24
|
if (query) {
|
|
37
25
|
params.set("q", query);
|
|
38
26
|
}
|
|
39
|
-
if (limit !== void 0) {
|
|
40
|
-
params.set("limit", String(limit));
|
|
27
|
+
if (options.limit !== void 0) {
|
|
28
|
+
params.set("limit", String(options.limit));
|
|
29
|
+
}
|
|
30
|
+
if (options.mode) {
|
|
31
|
+
params.set("mode", options.mode);
|
|
32
|
+
}
|
|
33
|
+
if (options.surface) {
|
|
34
|
+
params.set("surface", options.surface);
|
|
35
|
+
}
|
|
36
|
+
if (options.queryEligible !== void 0) {
|
|
37
|
+
params.set("queryEligible", String(options.queryEligible));
|
|
38
|
+
}
|
|
39
|
+
if (options.requireExecutePricing !== void 0) {
|
|
40
|
+
params.set(
|
|
41
|
+
"requireExecutePricing",
|
|
42
|
+
String(options.requireExecutePricing)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (options.excludeLatencyClasses && options.excludeLatencyClasses.length > 0) {
|
|
46
|
+
params.set("excludeLatency", options.excludeLatencyClasses.join(","));
|
|
47
|
+
}
|
|
48
|
+
if (options.excludeSlow !== void 0) {
|
|
49
|
+
params.set("excludeSlow", String(options.excludeSlow));
|
|
41
50
|
}
|
|
42
51
|
const queryString = params.toString();
|
|
43
52
|
const endpoint = `/api/v1/tools/search${queryString ? `?${queryString}` : ""}`;
|
|
@@ -55,8 +64,12 @@ var Discovery = class {
|
|
|
55
64
|
* const featured = await client.discovery.getFeatured(5);
|
|
56
65
|
* ```
|
|
57
66
|
*/
|
|
58
|
-
async getFeatured(limit) {
|
|
59
|
-
return this.search(
|
|
67
|
+
async getFeatured(limit, options) {
|
|
68
|
+
return this.search({
|
|
69
|
+
...options ?? {},
|
|
70
|
+
query: "",
|
|
71
|
+
...limit !== void 0 ? { limit } : {}
|
|
72
|
+
});
|
|
60
73
|
}
|
|
61
74
|
};
|
|
62
75
|
|
|
@@ -97,14 +110,31 @@ var Tools = class {
|
|
|
97
110
|
* ```
|
|
98
111
|
*/
|
|
99
112
|
async execute(options) {
|
|
100
|
-
const {
|
|
113
|
+
const {
|
|
114
|
+
toolId,
|
|
115
|
+
toolName,
|
|
116
|
+
args,
|
|
117
|
+
idempotencyKey,
|
|
118
|
+
mode,
|
|
119
|
+
sessionId,
|
|
120
|
+
maxSpendUsd,
|
|
121
|
+
closeSession
|
|
122
|
+
} = options;
|
|
101
123
|
const headers = idempotencyKey ? { "Idempotency-Key": idempotencyKey } : void 0;
|
|
102
124
|
const response = await this.client._fetch(
|
|
103
125
|
"/api/v1/tools/execute",
|
|
104
126
|
{
|
|
105
127
|
method: "POST",
|
|
106
128
|
headers,
|
|
107
|
-
body: JSON.stringify({
|
|
129
|
+
body: JSON.stringify({
|
|
130
|
+
toolId,
|
|
131
|
+
toolName,
|
|
132
|
+
args,
|
|
133
|
+
mode: mode ?? "execute",
|
|
134
|
+
sessionId,
|
|
135
|
+
maxSpendUsd,
|
|
136
|
+
closeSession
|
|
137
|
+
})
|
|
108
138
|
}
|
|
109
139
|
);
|
|
110
140
|
if ("error" in response) {
|
|
@@ -118,13 +148,79 @@ var Tools = class {
|
|
|
118
148
|
}
|
|
119
149
|
if (response.success) {
|
|
120
150
|
return {
|
|
151
|
+
mode: response.mode,
|
|
121
152
|
result: response.result,
|
|
122
153
|
tool: response.tool,
|
|
154
|
+
method: response.method,
|
|
155
|
+
session: response.session,
|
|
123
156
|
durationMs: response.durationMs
|
|
124
157
|
};
|
|
125
158
|
}
|
|
126
159
|
throw new ContextError("Unexpected response format from API");
|
|
127
160
|
}
|
|
161
|
+
/**
|
|
162
|
+
* Start an execute session with a max spend budget.
|
|
163
|
+
*/
|
|
164
|
+
async startSession(options) {
|
|
165
|
+
const response = await this.client._fetch(
|
|
166
|
+
"/api/v1/tools/execute/sessions",
|
|
167
|
+
{
|
|
168
|
+
method: "POST",
|
|
169
|
+
body: JSON.stringify({
|
|
170
|
+
mode: "execute",
|
|
171
|
+
maxSpendUsd: options.maxSpendUsd
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
return this.resolveSessionLifecycleResponse(response);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Fetch current execute session status by ID.
|
|
179
|
+
*/
|
|
180
|
+
async getSession(sessionId) {
|
|
181
|
+
if (!sessionId) {
|
|
182
|
+
throw new ContextError("sessionId is required");
|
|
183
|
+
}
|
|
184
|
+
const encodedSessionId = encodeURIComponent(sessionId);
|
|
185
|
+
const response = await this.client._fetch(
|
|
186
|
+
`/api/v1/tools/execute/sessions/${encodedSessionId}`
|
|
187
|
+
);
|
|
188
|
+
return this.resolveSessionLifecycleResponse(response);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Close an execute session by ID.
|
|
192
|
+
*/
|
|
193
|
+
async closeSession(sessionId) {
|
|
194
|
+
if (!sessionId) {
|
|
195
|
+
throw new ContextError("sessionId is required");
|
|
196
|
+
}
|
|
197
|
+
const encodedSessionId = encodeURIComponent(sessionId);
|
|
198
|
+
const response = await this.client._fetch(
|
|
199
|
+
`/api/v1/tools/execute/sessions/${encodedSessionId}/close`,
|
|
200
|
+
{
|
|
201
|
+
method: "POST",
|
|
202
|
+
body: JSON.stringify({ mode: "execute" })
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
return this.resolveSessionLifecycleResponse(response);
|
|
206
|
+
}
|
|
207
|
+
resolveSessionLifecycleResponse(response) {
|
|
208
|
+
if ("error" in response) {
|
|
209
|
+
throw new ContextError(
|
|
210
|
+
response.error,
|
|
211
|
+
response.code,
|
|
212
|
+
void 0,
|
|
213
|
+
response.helpUrl
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
if (response.success) {
|
|
217
|
+
return {
|
|
218
|
+
mode: response.mode,
|
|
219
|
+
session: response.session
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
throw new ContextError("Unexpected response format from API");
|
|
223
|
+
}
|
|
128
224
|
};
|
|
129
225
|
|
|
130
226
|
// src/client/resources/query.ts
|
|
@@ -177,6 +273,7 @@ var Query = class {
|
|
|
177
273
|
modelId: opts.modelId,
|
|
178
274
|
includeData: opts.includeData,
|
|
179
275
|
includeDataUrl: opts.includeDataUrl,
|
|
276
|
+
queryDepth: opts.queryDepth,
|
|
180
277
|
stream: false
|
|
181
278
|
})
|
|
182
279
|
}
|
|
@@ -242,6 +339,7 @@ var Query = class {
|
|
|
242
339
|
modelId: opts.modelId,
|
|
243
340
|
includeData: opts.includeData,
|
|
244
341
|
includeDataUrl: opts.includeDataUrl,
|
|
342
|
+
queryDepth: opts.queryDepth,
|
|
245
343
|
stream: true
|
|
246
344
|
})
|
|
247
345
|
});
|
|
@@ -287,9 +385,14 @@ var Query = class {
|
|
|
287
385
|
};
|
|
288
386
|
|
|
289
387
|
// src/client/client.ts
|
|
388
|
+
var DEFAULT_BASE_URL = "https://www.ctxprotocol.com";
|
|
389
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e5;
|
|
390
|
+
var DEFAULT_STREAM_TIMEOUT_MS = 6e5;
|
|
290
391
|
var ContextClient = class {
|
|
291
392
|
apiKey;
|
|
292
393
|
baseUrl;
|
|
394
|
+
requestTimeoutMs;
|
|
395
|
+
streamTimeoutMs;
|
|
293
396
|
_closed = false;
|
|
294
397
|
/**
|
|
295
398
|
* Discovery resource for searching tools
|
|
@@ -312,14 +415,26 @@ var ContextClient = class {
|
|
|
312
415
|
*
|
|
313
416
|
* @param options - Client configuration options
|
|
314
417
|
* @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
|
|
315
|
-
* @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
|
|
418
|
+
* @param options.baseUrl - Optional base URL override (defaults to https://www.ctxprotocol.com)
|
|
419
|
+
* @param options.requestTimeoutMs - Optional timeout for non-streaming requests (default 300000ms)
|
|
420
|
+
* @param options.streamTimeoutMs - Optional timeout for establishing stream requests (default 600000ms)
|
|
316
421
|
*/
|
|
317
422
|
constructor(options) {
|
|
318
423
|
if (!options.apiKey) {
|
|
319
424
|
throw new ContextError("API key is required");
|
|
320
425
|
}
|
|
426
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
427
|
+
const streamTimeoutMs = options.streamTimeoutMs ?? DEFAULT_STREAM_TIMEOUT_MS;
|
|
428
|
+
if (!Number.isFinite(requestTimeoutMs) || requestTimeoutMs <= 0) {
|
|
429
|
+
throw new ContextError("requestTimeoutMs must be a positive number");
|
|
430
|
+
}
|
|
431
|
+
if (!Number.isFinite(streamTimeoutMs) || streamTimeoutMs <= 0) {
|
|
432
|
+
throw new ContextError("streamTimeoutMs must be a positive number");
|
|
433
|
+
}
|
|
321
434
|
this.apiKey = options.apiKey;
|
|
322
|
-
this.baseUrl = (options.baseUrl ??
|
|
435
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
436
|
+
this.requestTimeoutMs = requestTimeoutMs;
|
|
437
|
+
this.streamTimeoutMs = streamTimeoutMs;
|
|
323
438
|
this.discovery = new Discovery(this);
|
|
324
439
|
this.tools = new Tools(this);
|
|
325
440
|
this.query = new Query(this);
|
|
@@ -333,7 +448,7 @@ var ContextClient = class {
|
|
|
333
448
|
}
|
|
334
449
|
/**
|
|
335
450
|
* Internal method for making authenticated HTTP requests
|
|
336
|
-
* Includes timeout
|
|
451
|
+
* Includes timeout and retry with exponential backoff for transient errors
|
|
337
452
|
*
|
|
338
453
|
* @internal
|
|
339
454
|
*/
|
|
@@ -343,7 +458,7 @@ var ContextClient = class {
|
|
|
343
458
|
}
|
|
344
459
|
const url = `${this.baseUrl}${endpoint}`;
|
|
345
460
|
const maxRetries = 3;
|
|
346
|
-
const timeoutMs =
|
|
461
|
+
const timeoutMs = this.requestTimeoutMs;
|
|
347
462
|
let lastError;
|
|
348
463
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
349
464
|
const controller = new AbortController();
|
|
@@ -411,6 +526,7 @@ var ContextClient = class {
|
|
|
411
526
|
/**
|
|
412
527
|
* Internal method for making authenticated HTTP requests that returns
|
|
413
528
|
* the raw Response object. Used for streaming endpoints (SSE).
|
|
529
|
+
* Includes a configurable timeout for stream setup.
|
|
414
530
|
*
|
|
415
531
|
* @internal
|
|
416
532
|
*/
|
|
@@ -419,14 +535,32 @@ var ContextClient = class {
|
|
|
419
535
|
throw new ContextError("Client has been closed");
|
|
420
536
|
}
|
|
421
537
|
const url = `${this.baseUrl}${endpoint}`;
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
...options
|
|
538
|
+
const controller = new AbortController();
|
|
539
|
+
const timeout = setTimeout(() => controller.abort(), this.streamTimeoutMs);
|
|
540
|
+
let response;
|
|
541
|
+
try {
|
|
542
|
+
response = await fetch(url, {
|
|
543
|
+
...options,
|
|
544
|
+
signal: controller.signal,
|
|
545
|
+
headers: {
|
|
546
|
+
"Content-Type": "application/json",
|
|
547
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
548
|
+
...options.headers
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
} catch (error) {
|
|
552
|
+
clearTimeout(timeout);
|
|
553
|
+
const lastError = error instanceof Error ? error : new Error(String(error));
|
|
554
|
+
if (lastError.name === "AbortError") {
|
|
555
|
+
throw new ContextError(
|
|
556
|
+
`Streaming request timed out after ${this.streamTimeoutMs / 1e3}s`,
|
|
557
|
+
void 0,
|
|
558
|
+
408
|
|
559
|
+
);
|
|
428
560
|
}
|
|
429
|
-
|
|
561
|
+
throw new ContextError(lastError.message);
|
|
562
|
+
}
|
|
563
|
+
clearTimeout(timeout);
|
|
430
564
|
if (!response.ok) {
|
|
431
565
|
let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
|
|
432
566
|
let errorCode;
|