@telemai/sdk 0.1.1 → 0.2.1
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 +48 -8
- package/dist/chunk-RYY4S5LP.js +373 -0
- package/dist/index.cjs +94 -48
- package/dist/index.d.cts +20 -5
- package/dist/index.d.ts +20 -5
- package/dist/index.js +40 -320
- package/dist/vercel/index.cjs +746 -0
- package/dist/vercel/index.d.cts +265 -0
- package/dist/vercel/index.d.ts +265 -0
- package/dist/vercel/index.js +583 -0
- package/package.json +38 -7
package/dist/index.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
1
|
+
import {
|
|
2
|
+
RESERVED_METADATA,
|
|
3
|
+
TelemError,
|
|
4
|
+
TimeoutError,
|
|
5
|
+
asArray,
|
|
6
|
+
asObject,
|
|
7
|
+
buildMetadata,
|
|
8
|
+
buildSnapshot,
|
|
9
|
+
contentAnchor,
|
|
10
|
+
eventNodeKey,
|
|
11
|
+
fingerprint,
|
|
12
|
+
invalidRequest,
|
|
13
|
+
isObject,
|
|
14
|
+
request,
|
|
15
|
+
sessionKey,
|
|
16
|
+
snapshotNodeKey,
|
|
17
|
+
stringList,
|
|
18
|
+
toolMarker,
|
|
19
|
+
windowAnchor,
|
|
20
|
+
wireMetadata,
|
|
21
|
+
withTrajectory
|
|
22
|
+
} from "./chunk-RYY4S5LP.js";
|
|
20
23
|
|
|
21
24
|
// src/version.ts
|
|
22
|
-
var VERSION = "0.
|
|
25
|
+
var VERSION = "0.2.1";
|
|
23
26
|
|
|
24
27
|
// src/config.ts
|
|
25
28
|
var DEFAULT_BASE_URL = "https://router.telem.ai";
|
|
@@ -34,6 +37,9 @@ function csvEnv(raw) {
|
|
|
34
37
|
const items = raw.split(",").map(trimBlank).filter((item) => item !== "");
|
|
35
38
|
return items.length ? items : void 0;
|
|
36
39
|
}
|
|
40
|
+
function intEnv(raw) {
|
|
41
|
+
return raw !== void 0 && /^\s*[+-]?\d+\s*$/.test(raw) ? Number(raw) : void 0;
|
|
42
|
+
}
|
|
37
43
|
function readCredentials(env) {
|
|
38
44
|
try {
|
|
39
45
|
const proc = globalThis.process;
|
|
@@ -110,306 +116,13 @@ function resolveConfig(options) {
|
|
|
110
116
|
fields: opts.fields ?? csvEnv(env.TELEM_FIELDS),
|
|
111
117
|
providersInclude: opts.providersInclude ?? csvEnv(env.TELEM_PROVIDERS_INCLUDE),
|
|
112
118
|
providersExclude: opts.providersExclude ?? csvEnv(env.TELEM_PROVIDERS_EXCLUDE),
|
|
113
|
-
includeFullContent: opts.includeFullContent ?? (env.TELEM_FULL_CONTENT === "1" || void 0)
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// src/http.ts
|
|
119
|
-
var MAX_DELAY_MS = 3e4;
|
|
120
|
-
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
121
|
-
var BASE_DELAY_MS = 500;
|
|
122
|
-
function isObject(value) {
|
|
123
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
124
|
-
}
|
|
125
|
-
function asObject(value) {
|
|
126
|
-
return isObject(value) ? value : {};
|
|
127
|
-
}
|
|
128
|
-
function asArray(value) {
|
|
129
|
-
return Array.isArray(value) ? value : [];
|
|
130
|
-
}
|
|
131
|
-
function invalidRequest(message) {
|
|
132
|
-
return new TelemError(message, { code: "invalid_request" });
|
|
133
|
-
}
|
|
134
|
-
function stringList(items, empty, what) {
|
|
135
|
-
const list = asArray(items);
|
|
136
|
-
if (!list.length) throw invalidRequest(empty);
|
|
137
|
-
for (const item of list) {
|
|
138
|
-
if (typeof item !== "string") {
|
|
139
|
-
throw invalidRequest(`${what} must be strings, got ${item === null ? "null" : typeof item}`);
|
|
140
|
-
}
|
|
141
|
-
if (item === "") throw invalidRequest(`${what} must not be empty`);
|
|
142
|
-
}
|
|
143
|
-
return list;
|
|
144
|
-
}
|
|
145
|
-
function errorEnvelope(body) {
|
|
146
|
-
if (!isObject(body)) return void 0;
|
|
147
|
-
if (isObject(body.error)) return body.error;
|
|
148
|
-
if (isObject(body.detail)) return body.detail;
|
|
149
|
-
return void 0;
|
|
150
|
-
}
|
|
151
|
-
function detailFromBody(body) {
|
|
152
|
-
if (!isObject(body)) return void 0;
|
|
153
|
-
const envelope = errorEnvelope(body);
|
|
154
|
-
if (envelope && typeof envelope.message === "string" && envelope.message) {
|
|
155
|
-
return envelope.message;
|
|
156
|
-
}
|
|
157
|
-
const detail = body.detail;
|
|
158
|
-
if (typeof detail === "string" && detail) return detail;
|
|
159
|
-
if (Array.isArray(detail) && detail.length) {
|
|
160
|
-
const messages = detail.map((item) => isObject(item) && typeof item.msg === "string" ? item.msg : void 0).filter((message) => message !== void 0);
|
|
161
|
-
return messages.join(", ") || JSON.stringify(detail);
|
|
162
|
-
}
|
|
163
|
-
return void 0;
|
|
164
|
-
}
|
|
165
|
-
function codeFromBody(body) {
|
|
166
|
-
const envelope = errorEnvelope(body);
|
|
167
|
-
return envelope && typeof envelope.code === "string" ? envelope.code : void 0;
|
|
168
|
-
}
|
|
169
|
-
function isResponseLike(value) {
|
|
170
|
-
return isObject(value) && typeof value.text === "function" && typeof value.status === "number" && typeof value.headers?.get === "function";
|
|
171
|
-
}
|
|
172
|
-
var NotAResponse = class extends Error {
|
|
173
|
-
};
|
|
174
|
-
function defaultMessage(status) {
|
|
175
|
-
if (status === 400) return "Bad request";
|
|
176
|
-
if (status === 401 || status === 403) return "Authentication failed";
|
|
177
|
-
if (status === 404) return "Not found";
|
|
178
|
-
return `Unexpected status code ${status}`;
|
|
179
|
-
}
|
|
180
|
-
function statusError(status, body) {
|
|
181
|
-
return new TelemError(detailFromBody(body) ?? defaultMessage(status), {
|
|
182
|
-
status,
|
|
183
|
-
code: codeFromBody(body),
|
|
184
|
-
details: body
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
function connectionError(url, cause) {
|
|
188
|
-
const error = cause;
|
|
189
|
-
const detail = typeof error?.cause?.message === "string" && error.cause.message || typeof error?.message === "string" && error.message || String(cause);
|
|
190
|
-
return new TelemError(`could not reach ${url}: ${detail}`, {
|
|
191
|
-
code: "connection_error",
|
|
192
|
-
cause
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
function isRetryable(status) {
|
|
196
|
-
return status >= 500 || status === 429;
|
|
197
|
-
}
|
|
198
|
-
function backoff(attempt) {
|
|
199
|
-
return Math.min(BASE_DELAY_MS * 2 ** attempt, MAX_DELAY_MS);
|
|
200
|
-
}
|
|
201
|
-
function retryDelay(retryAfter, attempt) {
|
|
202
|
-
if (retryAfter !== null && /^\s*\d+\s*$/.test(retryAfter)) {
|
|
203
|
-
return Math.min(Number(retryAfter) * 1e3, MAX_DELAY_MS);
|
|
204
|
-
}
|
|
205
|
-
return backoff(attempt);
|
|
206
|
-
}
|
|
207
|
-
async function request(config, method, path, body) {
|
|
208
|
-
const url = `${config.baseUrl}/${path.replace(/^\/+/, "")}`;
|
|
209
|
-
const headers = { "User-Agent": config.userAgent };
|
|
210
|
-
if (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;
|
|
211
|
-
const init = { method, headers };
|
|
212
|
-
if (body !== void 0) {
|
|
213
|
-
headers["Content-Type"] = "application/json";
|
|
214
|
-
try {
|
|
215
|
-
init.body = JSON.stringify(body);
|
|
216
|
-
} catch (cause) {
|
|
217
|
-
throw invalidRequest(`request body is not JSON: ${cause?.message ?? String(cause)}`);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
for (let attempt = 0; ; attempt++) {
|
|
221
|
-
const signal = Number.isFinite(config.timeoutMs) ? AbortSignal.timeout(Math.min(config.timeoutMs, MAX_TIMEOUT_MS)) : void 0;
|
|
222
|
-
let onAbort = () => {
|
|
223
|
-
};
|
|
224
|
-
const deadline = signal && new Promise((_, reject) => {
|
|
225
|
-
onAbort = () => reject(signal.reason);
|
|
226
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
227
|
-
});
|
|
228
|
-
const race = (work) => deadline ? Promise.race([work, deadline]) : work;
|
|
229
|
-
let received;
|
|
230
|
-
try {
|
|
231
|
-
const response = await race(config.fetch(url, { ...init, signal }));
|
|
232
|
-
if (!isResponseLike(response)) throw new NotAResponse();
|
|
233
|
-
const text = await race(response.text());
|
|
234
|
-
let parsed;
|
|
235
|
-
try {
|
|
236
|
-
parsed = JSON.parse(text);
|
|
237
|
-
} catch {
|
|
238
|
-
parsed = text;
|
|
239
|
-
}
|
|
240
|
-
received = {
|
|
241
|
-
status: response.status,
|
|
242
|
-
retryAfter: response.headers.get("retry-after"),
|
|
243
|
-
body: parsed
|
|
244
|
-
};
|
|
245
|
-
} catch (cause) {
|
|
246
|
-
if (cause instanceof NotAResponse) {
|
|
247
|
-
throw new TelemError("the injected fetch returned something that is not a Response", {
|
|
248
|
-
code: "connection_error"
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
if (signal?.aborted) {
|
|
252
|
-
throw new TimeoutError(`request to ${url} timed out after ${config.timeoutMs}ms`, cause);
|
|
253
|
-
}
|
|
254
|
-
if (attempt >= config.maxRetries) throw connectionError(url, cause);
|
|
255
|
-
await config.sleep(backoff(attempt));
|
|
256
|
-
continue;
|
|
257
|
-
} finally {
|
|
258
|
-
signal?.removeEventListener("abort", onAbort);
|
|
119
|
+
includeFullContent: opts.includeFullContent ?? (env.TELEM_FULL_CONTENT === "1" || void 0),
|
|
120
|
+
autoRouting: opts.autoRouting ?? (trimBlank(env.TELEM_AUTO_ROUTING ?? "") || void 0),
|
|
121
|
+
maxRoutingProviders: opts.maxRoutingProviders ?? intEnv(env.TELEM_MAX_ROUTING_PROVIDERS),
|
|
122
|
+
topic: opts.topic ?? (trimBlank(env.TELEM_TOPIC ?? "") || void 0)
|
|
259
123
|
}
|
|
260
|
-
if (received.status >= 200 && received.status < 300) return received.body;
|
|
261
|
-
if (isRetryable(received.status) && attempt < config.maxRetries) {
|
|
262
|
-
await config.sleep(retryDelay(received.retryAfter, attempt));
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
throw statusError(received.status, received.body);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// src/trajectory.ts
|
|
270
|
-
var NS_TRAJECTORY = "443866ab-1b45-5ed8-979e-52fdad07b810";
|
|
271
|
-
var NONE = "none";
|
|
272
|
-
var RESERVED_METADATA = /* @__PURE__ */ new Set([
|
|
273
|
-
"message_history",
|
|
274
|
-
"session_key",
|
|
275
|
-
"fingerprint",
|
|
276
|
-
"node_key",
|
|
277
|
-
"kind",
|
|
278
|
-
"parent_node_key",
|
|
279
|
-
"ancestors"
|
|
280
|
-
]);
|
|
281
|
-
var ENCODER = new TextEncoder();
|
|
282
|
-
var NAMESPACE_BYTES = Uint8Array.from(
|
|
283
|
-
NS_TRAJECTORY.replaceAll("-", "").match(/../g) ?? [],
|
|
284
|
-
(pair) => parseInt(pair, 16)
|
|
285
|
-
);
|
|
286
|
-
function hex(bytes) {
|
|
287
|
-
let out = "";
|
|
288
|
-
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
289
|
-
return out;
|
|
290
|
-
}
|
|
291
|
-
async function digest(algorithm, bytes) {
|
|
292
|
-
return new Uint8Array(await crypto.subtle.digest(algorithm, bytes));
|
|
293
|
-
}
|
|
294
|
-
async function sha256(value) {
|
|
295
|
-
return hex(await digest("SHA-256", ENCODER.encode(value)));
|
|
296
|
-
}
|
|
297
|
-
function lp(value) {
|
|
298
|
-
return `${ENCODER.encode(value).length}:${value}`;
|
|
299
|
-
}
|
|
300
|
-
async function uuid5(name) {
|
|
301
|
-
const encoded = ENCODER.encode(name);
|
|
302
|
-
const input = new Uint8Array(NAMESPACE_BYTES.length + encoded.length);
|
|
303
|
-
input.set(NAMESPACE_BYTES);
|
|
304
|
-
input.set(encoded, NAMESPACE_BYTES.length);
|
|
305
|
-
const bytes = (await digest("SHA-1", input)).slice(0, 16);
|
|
306
|
-
bytes[6] = bytes[6] & 15 | 80;
|
|
307
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
308
|
-
const chars = hex(bytes);
|
|
309
|
-
return [
|
|
310
|
-
chars.slice(0, 8),
|
|
311
|
-
chars.slice(8, 12),
|
|
312
|
-
chars.slice(12, 16),
|
|
313
|
-
chars.slice(16, 20),
|
|
314
|
-
chars.slice(20)
|
|
315
|
-
].join("-");
|
|
316
|
-
}
|
|
317
|
-
async function fingerprint(harness, conversationId) {
|
|
318
|
-
return await sha256(lp(harness) + lp(conversationId));
|
|
319
|
-
}
|
|
320
|
-
async function sessionKey(harness, conversationId, windowId) {
|
|
321
|
-
const name = lp(harness) + lp(await sha256(conversationId)) + lp(windowId) + lp(NONE);
|
|
322
|
-
return await uuid5(name);
|
|
323
|
-
}
|
|
324
|
-
async function eventNodeKey(harness, session, messageId, toolCallId) {
|
|
325
|
-
const name = lp(harness) + lp(session) + lp(messageId) + lp(toolCallId) + lp("event");
|
|
326
|
-
return await uuid5(name);
|
|
327
|
-
}
|
|
328
|
-
async function snapshotNodeKey(harness, conversationId, messageId) {
|
|
329
|
-
const name = lp(harness) + lp(await sha256(conversationId)) + lp(messageId) + lp("snap");
|
|
330
|
-
return await uuid5(name);
|
|
331
|
-
}
|
|
332
|
-
async function contentAnchor(...parts) {
|
|
333
|
-
return await sha256(parts.map(lp).join(""));
|
|
334
|
-
}
|
|
335
|
-
var HISTORY_TEXT_CAP = 128e3;
|
|
336
|
-
function cap(value) {
|
|
337
|
-
if (value.length <= HISTORY_TEXT_CAP) return value;
|
|
338
|
-
return Array.from(value).slice(0, HISTORY_TEXT_CAP).join("");
|
|
339
|
-
}
|
|
340
|
-
function pyStr(value) {
|
|
341
|
-
if (typeof value === "string") return value;
|
|
342
|
-
if (value === null) return "None";
|
|
343
|
-
if (value === true) return "True";
|
|
344
|
-
if (value === false) return "False";
|
|
345
|
-
return String(value);
|
|
346
|
-
}
|
|
347
|
-
function messageText(content) {
|
|
348
|
-
if (typeof content === "string") return cap(content);
|
|
349
|
-
if (Array.isArray(content)) {
|
|
350
|
-
const pieces = [];
|
|
351
|
-
for (const block of content) {
|
|
352
|
-
if (typeof block === "string") pieces.push(block);
|
|
353
|
-
else if (isObject(block) && typeof block.text === "string") pieces.push(block.text);
|
|
354
|
-
}
|
|
355
|
-
return cap(pieces.join("\n"));
|
|
356
|
-
}
|
|
357
|
-
return content === null || content === void 0 ? "" : cap(pyStr(content));
|
|
358
|
-
}
|
|
359
|
-
async function windowAnchor(messages) {
|
|
360
|
-
const first = messages[0];
|
|
361
|
-
if (first === void 0) return NONE;
|
|
362
|
-
return await contentAnchor(
|
|
363
|
-
first.role === void 0 ? "" : pyStr(first.role),
|
|
364
|
-
messageText(first.content)
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
async function buildMetadata(args) {
|
|
368
|
-
const [session, fp] = await Promise.all([
|
|
369
|
-
sessionKey(args.harness, args.conversationId, args.windowId),
|
|
370
|
-
fingerprint(args.harness, args.conversationId)
|
|
371
|
-
]);
|
|
372
|
-
return {
|
|
373
|
-
message_history: args.history,
|
|
374
|
-
session_key: session,
|
|
375
|
-
fingerprint: fp,
|
|
376
|
-
node_key: await eventNodeKey(args.harness, session, args.messageId, args.toolCallId),
|
|
377
|
-
parent_node_key: parentNodeKey(args.ancestors),
|
|
378
|
-
ancestors: args.ancestors
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
|
-
async function buildSnapshot(args) {
|
|
382
|
-
const [session, fp, node] = await Promise.all([
|
|
383
|
-
sessionKey(args.harness, args.conversationId, args.windowId),
|
|
384
|
-
fingerprint(args.harness, args.conversationId),
|
|
385
|
-
snapshotNodeKey(args.harness, args.conversationId, args.messageId)
|
|
386
|
-
]);
|
|
387
|
-
return {
|
|
388
|
-
session_key: session,
|
|
389
|
-
fingerprint: fp,
|
|
390
|
-
node_key: node,
|
|
391
|
-
parent_node_key: parentNodeKey(args.ancestors),
|
|
392
|
-
context: args.context,
|
|
393
|
-
spawned_at: args.spawnedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
394
124
|
};
|
|
395
125
|
}
|
|
396
|
-
function parentNodeKey(ancestors) {
|
|
397
|
-
return ancestors.at(-1)?.node_key ?? null;
|
|
398
|
-
}
|
|
399
|
-
var TRAJECTORY = /* @__PURE__ */ Symbol.for("telem.trajectory");
|
|
400
|
-
function withTrajectory(options, envelope) {
|
|
401
|
-
return { ...options, [TRAJECTORY]: envelope };
|
|
402
|
-
}
|
|
403
|
-
function wireMetadata(options, kind) {
|
|
404
|
-
const metadata = {};
|
|
405
|
-
for (const [key, value] of Object.entries(options.metadata ?? {})) {
|
|
406
|
-
if (!RESERVED_METADATA.has(key)) metadata[key] = value;
|
|
407
|
-
}
|
|
408
|
-
const envelope = options[TRAJECTORY];
|
|
409
|
-
if (envelope !== void 0) Object.assign(metadata, envelope, { kind });
|
|
410
|
-
const sessionId = metadata.session_key === void 0 ? options.session : void 0;
|
|
411
|
-
return { metadata, sessionId };
|
|
412
|
-
}
|
|
413
126
|
|
|
414
127
|
// src/methods/fetch.ts
|
|
415
128
|
function fetchBody(url, options) {
|
|
@@ -466,7 +179,7 @@ function buildFetchResponse(interaction) {
|
|
|
466
179
|
}
|
|
467
180
|
async function fetchUrls(config, url, options) {
|
|
468
181
|
const body = fetchBody(url, options);
|
|
469
|
-
return buildFetchResponse(await request(config, "POST", "/v1/fetch", body));
|
|
182
|
+
return buildFetchResponse(await request(config, "POST", "/v1/fetch", body, options.signal));
|
|
470
183
|
}
|
|
471
184
|
|
|
472
185
|
// src/methods/providers.ts
|
|
@@ -515,6 +228,12 @@ function searchBlock(defaults, options) {
|
|
|
515
228
|
if (options.includeRaw !== void 0) block.include_raw = options.includeRaw;
|
|
516
229
|
if (options.rerank !== void 0) block.rerank = options.rerank;
|
|
517
230
|
if (includeFullContent !== void 0) block.include_full_content = includeFullContent;
|
|
231
|
+
const autoRouting = options.autoRouting ?? defaults.autoRouting;
|
|
232
|
+
if (autoRouting !== void 0) block.auto_routing = autoRouting;
|
|
233
|
+
const maxRoutingProviders = options.maxRoutingProviders ?? defaults.maxRoutingProviders;
|
|
234
|
+
if (maxRoutingProviders !== void 0) block.max_routing_providers = maxRoutingProviders;
|
|
235
|
+
const topic = options.topic ?? defaults.topic;
|
|
236
|
+
if (topic !== void 0) block.topic = topic;
|
|
518
237
|
return block;
|
|
519
238
|
}
|
|
520
239
|
function userInput(query) {
|
|
@@ -615,7 +334,7 @@ function buildSearchResponse(interaction) {
|
|
|
615
334
|
}
|
|
616
335
|
async function search(config, query, options) {
|
|
617
336
|
const body = searchBody(config, query, options);
|
|
618
|
-
const data = await request(config, "POST", "/v1/interactions", body);
|
|
337
|
+
const data = await request(config, "POST", "/v1/interactions", body, options.signal);
|
|
619
338
|
assertV2(data);
|
|
620
339
|
return buildSearchResponse(data);
|
|
621
340
|
}
|
|
@@ -683,7 +402,7 @@ var Telem = class {
|
|
|
683
402
|
timeoutMs;
|
|
684
403
|
/** Resolved retry budget (attempts after the first). */
|
|
685
404
|
maxRetries;
|
|
686
|
-
/** The session read surface: `list
|
|
405
|
+
/** The session read surface: `list` and `results(id)`. */
|
|
687
406
|
sessions;
|
|
688
407
|
#config;
|
|
689
408
|
/**
|
|
@@ -744,6 +463,7 @@ export {
|
|
|
744
463
|
fingerprint,
|
|
745
464
|
sessionKey,
|
|
746
465
|
snapshotNodeKey,
|
|
466
|
+
toolMarker,
|
|
747
467
|
windowAnchor,
|
|
748
468
|
withTrajectory
|
|
749
469
|
};
|