@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
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/vercel/index.ts
|
|
21
|
+
var vercel_exports = {};
|
|
22
|
+
__export(vercel_exports, {
|
|
23
|
+
childTelemVercelTools: () => childTelemVercelTools,
|
|
24
|
+
createTelemVercelAgent: () => createTelemVercelAgent,
|
|
25
|
+
createTelemVercelTools: () => createTelemVercelTools,
|
|
26
|
+
default: () => vercel_default,
|
|
27
|
+
telemVercelAgentFor: () => telemVercelAgentFor,
|
|
28
|
+
telemVercelAutoNesting: () => telemVercelAutoNesting,
|
|
29
|
+
telemVercelMessageHistory: () => telemVercelMessageHistory
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(vercel_exports);
|
|
32
|
+
var import_ai = require("ai");
|
|
33
|
+
|
|
34
|
+
// src/http.ts
|
|
35
|
+
var MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
36
|
+
function isObject(value) {
|
|
37
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/trajectory.ts
|
|
41
|
+
var NS_TRAJECTORY = "443866ab-1b45-5ed8-979e-52fdad07b810";
|
|
42
|
+
var NONE = "none";
|
|
43
|
+
var ENCODER = new TextEncoder();
|
|
44
|
+
var NAMESPACE_BYTES = Uint8Array.from(
|
|
45
|
+
NS_TRAJECTORY.replaceAll("-", "").match(/../g) ?? [],
|
|
46
|
+
(pair) => parseInt(pair, 16)
|
|
47
|
+
);
|
|
48
|
+
function hex(bytes) {
|
|
49
|
+
let out = "";
|
|
50
|
+
for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
async function digest(algorithm, bytes) {
|
|
54
|
+
return new Uint8Array(await crypto.subtle.digest(algorithm, bytes));
|
|
55
|
+
}
|
|
56
|
+
async function sha256(value) {
|
|
57
|
+
return hex(await digest("SHA-256", ENCODER.encode(value)));
|
|
58
|
+
}
|
|
59
|
+
function lp(value) {
|
|
60
|
+
return `${ENCODER.encode(value).length}:${value}`;
|
|
61
|
+
}
|
|
62
|
+
async function uuid5(name) {
|
|
63
|
+
const encoded = ENCODER.encode(name);
|
|
64
|
+
const input = new Uint8Array(NAMESPACE_BYTES.length + encoded.length);
|
|
65
|
+
input.set(NAMESPACE_BYTES);
|
|
66
|
+
input.set(encoded, NAMESPACE_BYTES.length);
|
|
67
|
+
const bytes = (await digest("SHA-1", input)).slice(0, 16);
|
|
68
|
+
bytes[6] = bytes[6] & 15 | 80;
|
|
69
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
70
|
+
const chars = hex(bytes);
|
|
71
|
+
return [
|
|
72
|
+
chars.slice(0, 8),
|
|
73
|
+
chars.slice(8, 12),
|
|
74
|
+
chars.slice(12, 16),
|
|
75
|
+
chars.slice(16, 20),
|
|
76
|
+
chars.slice(20)
|
|
77
|
+
].join("-");
|
|
78
|
+
}
|
|
79
|
+
async function fingerprint(harness, conversationId) {
|
|
80
|
+
return await sha256(lp(harness) + lp(conversationId));
|
|
81
|
+
}
|
|
82
|
+
async function sessionKey(harness, conversationId, windowId) {
|
|
83
|
+
const name = lp(harness) + lp(await sha256(conversationId)) + lp(windowId) + lp(NONE);
|
|
84
|
+
return await uuid5(name);
|
|
85
|
+
}
|
|
86
|
+
async function eventNodeKey(harness, session, messageId, toolCallId) {
|
|
87
|
+
const name = lp(harness) + lp(session) + lp(messageId) + lp(toolCallId) + lp("event");
|
|
88
|
+
return await uuid5(name);
|
|
89
|
+
}
|
|
90
|
+
async function snapshotNodeKey(harness, conversationId, messageId) {
|
|
91
|
+
const name = lp(harness) + lp(await sha256(conversationId)) + lp(messageId) + lp("snap");
|
|
92
|
+
return await uuid5(name);
|
|
93
|
+
}
|
|
94
|
+
async function contentAnchor(...parts) {
|
|
95
|
+
return await sha256(parts.map(lp).join(""));
|
|
96
|
+
}
|
|
97
|
+
var HISTORY_TEXT_CAP = 128e3;
|
|
98
|
+
var TOOL_INPUT_CAP = 128e3;
|
|
99
|
+
function cap(value) {
|
|
100
|
+
if (value.length <= HISTORY_TEXT_CAP) return value;
|
|
101
|
+
return Array.from(value).slice(0, HISTORY_TEXT_CAP).join("");
|
|
102
|
+
}
|
|
103
|
+
function toolMarker(name, status, args) {
|
|
104
|
+
let serialized = "";
|
|
105
|
+
try {
|
|
106
|
+
const text = JSON.stringify(args);
|
|
107
|
+
if (typeof text === "string") serialized = text;
|
|
108
|
+
} catch {
|
|
109
|
+
serialized = "";
|
|
110
|
+
}
|
|
111
|
+
if (serialized.length > TOOL_INPUT_CAP) serialized = Array.from(serialized).slice(0, TOOL_INPUT_CAP).join("");
|
|
112
|
+
const suffix = serialized ? ` ${serialized}` : "";
|
|
113
|
+
return `[tool ${name || "?"}: ${status}${suffix}]`;
|
|
114
|
+
}
|
|
115
|
+
function pyStr(value) {
|
|
116
|
+
if (typeof value === "string") return value;
|
|
117
|
+
if (value === null) return "None";
|
|
118
|
+
if (value === true) return "True";
|
|
119
|
+
if (value === false) return "False";
|
|
120
|
+
return String(value);
|
|
121
|
+
}
|
|
122
|
+
function messageText(content) {
|
|
123
|
+
if (typeof content === "string") return cap(content);
|
|
124
|
+
if (Array.isArray(content)) {
|
|
125
|
+
const pieces = [];
|
|
126
|
+
for (const block of content) {
|
|
127
|
+
if (typeof block === "string") pieces.push(block);
|
|
128
|
+
else if (isObject(block) && typeof block.text === "string") pieces.push(block.text);
|
|
129
|
+
}
|
|
130
|
+
return cap(pieces.join("\n"));
|
|
131
|
+
}
|
|
132
|
+
return content === null || content === void 0 ? "" : cap(pyStr(content));
|
|
133
|
+
}
|
|
134
|
+
async function windowAnchor(messages) {
|
|
135
|
+
const first = messages[0];
|
|
136
|
+
if (first === void 0) return NONE;
|
|
137
|
+
return await contentAnchor(
|
|
138
|
+
first.role === void 0 ? "" : pyStr(first.role),
|
|
139
|
+
messageText(first.content)
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
async function buildMetadata(args) {
|
|
143
|
+
const [session, fp] = await Promise.all([
|
|
144
|
+
sessionKey(args.harness, args.conversationId, args.windowId),
|
|
145
|
+
fingerprint(args.harness, args.conversationId)
|
|
146
|
+
]);
|
|
147
|
+
return {
|
|
148
|
+
message_history: args.history,
|
|
149
|
+
session_key: session,
|
|
150
|
+
fingerprint: fp,
|
|
151
|
+
node_key: await eventNodeKey(args.harness, session, args.messageId, args.toolCallId),
|
|
152
|
+
parent_node_key: parentNodeKey(args.ancestors),
|
|
153
|
+
ancestors: args.ancestors
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async function buildSnapshot(args) {
|
|
157
|
+
const [session, fp, node] = await Promise.all([
|
|
158
|
+
sessionKey(args.harness, args.conversationId, args.windowId),
|
|
159
|
+
fingerprint(args.harness, args.conversationId),
|
|
160
|
+
snapshotNodeKey(args.harness, args.conversationId, args.messageId)
|
|
161
|
+
]);
|
|
162
|
+
return {
|
|
163
|
+
session_key: session,
|
|
164
|
+
fingerprint: fp,
|
|
165
|
+
node_key: node,
|
|
166
|
+
parent_node_key: parentNodeKey(args.ancestors),
|
|
167
|
+
context: args.context,
|
|
168
|
+
spawned_at: args.spawnedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function parentNodeKey(ancestors) {
|
|
172
|
+
return ancestors.at(-1)?.node_key ?? null;
|
|
173
|
+
}
|
|
174
|
+
var TRAJECTORY = /* @__PURE__ */ Symbol.for("telem.trajectory");
|
|
175
|
+
function withTrajectory(options, envelope) {
|
|
176
|
+
return { ...options, [TRAJECTORY]: envelope };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/incremental.ts
|
|
180
|
+
function incrementalMode(raw) {
|
|
181
|
+
const value = typeof raw === "string" ? raw.trim().toLowerCase() : "";
|
|
182
|
+
return value === "off" || value === "history" ? value : "ancestors";
|
|
183
|
+
}
|
|
184
|
+
function env(name) {
|
|
185
|
+
const value = globalThis.process?.env?.[name];
|
|
186
|
+
return typeof value === "string" ? value : void 0;
|
|
187
|
+
}
|
|
188
|
+
var DELIVERED_CAP = 4096;
|
|
189
|
+
var CAPABILITY_CAP = 64;
|
|
190
|
+
var HISTORY_WATERMARK_CAP = 256;
|
|
191
|
+
var MISSING_SNAPSHOTS = "missing_snapshots";
|
|
192
|
+
var SEARCH_MARKER = "[tool telem_search:";
|
|
193
|
+
function createLruSet(cap2) {
|
|
194
|
+
const entries = /* @__PURE__ */ new Map();
|
|
195
|
+
return {
|
|
196
|
+
has: (key) => entries.has(key),
|
|
197
|
+
add(key) {
|
|
198
|
+
entries.delete(key);
|
|
199
|
+
entries.set(key, true);
|
|
200
|
+
while (entries.size > cap2) {
|
|
201
|
+
const oldest = entries.keys().next().value;
|
|
202
|
+
if (oldest === void 0) break;
|
|
203
|
+
entries.delete(oldest);
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
remove(key) {
|
|
207
|
+
entries.delete(key);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function createLruMap(cap2) {
|
|
212
|
+
const entries = /* @__PURE__ */ new Map();
|
|
213
|
+
return {
|
|
214
|
+
get: (key) => entries.get(key),
|
|
215
|
+
set(key, value) {
|
|
216
|
+
entries.delete(key);
|
|
217
|
+
entries.set(key, value);
|
|
218
|
+
while (entries.size > cap2) {
|
|
219
|
+
const oldest = entries.keys().next().value;
|
|
220
|
+
if (oldest === void 0) break;
|
|
221
|
+
entries.delete(oldest);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
async function cacheScope(baseUrl, apiKey) {
|
|
227
|
+
return baseUrl + " " + await sha256(apiKey ?? "");
|
|
228
|
+
}
|
|
229
|
+
function deliveredKey(scope, snapshotKey) {
|
|
230
|
+
return scope + "\0" + snapshotKey;
|
|
231
|
+
}
|
|
232
|
+
function newDeliveryPlan(scope) {
|
|
233
|
+
return { scope, sentWithContext: [], omitted: [], epochDegraded: false };
|
|
234
|
+
}
|
|
235
|
+
function isMissingSnapshotsRefusal(error, plan) {
|
|
236
|
+
if (error.status !== 409 || !plan.omitted.length) return false;
|
|
237
|
+
return error.code === void 0 || error.code === MISSING_SNAPSHOTS;
|
|
238
|
+
}
|
|
239
|
+
async function historyHash(entry) {
|
|
240
|
+
return await sha256(entry.content + "\0" + (entry.reasoning ?? ""));
|
|
241
|
+
}
|
|
242
|
+
async function fullHistorySend(flat) {
|
|
243
|
+
const hashes = await Promise.all(flat.map((message) => historyHash(message.entry)));
|
|
244
|
+
return {
|
|
245
|
+
entries: flat.map((message) => message.entry),
|
|
246
|
+
sent: flat.map((message, index) => ({ id: message.id, hash: hashes[index] }))
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
async function historyDelta(flat, hashes) {
|
|
250
|
+
const include = /* @__PURE__ */ new Set();
|
|
251
|
+
const boosters = /* @__PURE__ */ new Set();
|
|
252
|
+
const hashOf = await Promise.all(flat.map((message) => historyHash(message.entry)));
|
|
253
|
+
for (let i = 0; i < flat.length; i++) {
|
|
254
|
+
const { id, entry } = flat[i];
|
|
255
|
+
if (hashes.get(id) !== hashOf[i]) {
|
|
256
|
+
include.add(i);
|
|
257
|
+
if (entry.reasoning) boosters.add(entry.reasoning);
|
|
258
|
+
} else if (entry.role === "user") {
|
|
259
|
+
include.add(i);
|
|
260
|
+
} else if (entry.role === "assistant" && entry.content.includes(SEARCH_MARKER)) {
|
|
261
|
+
include.add(i);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (flat.length) include.add(flat.length - 1);
|
|
265
|
+
for (let i = 0; i < flat.length; i++) {
|
|
266
|
+
if (include.has(i)) continue;
|
|
267
|
+
const reasoning = flat[i].entry.reasoning;
|
|
268
|
+
if (reasoning && boosters.has(reasoning)) include.add(i);
|
|
269
|
+
}
|
|
270
|
+
const chosen = [...include].sort((a, b) => a - b);
|
|
271
|
+
return {
|
|
272
|
+
entries: chosen.map((i) => flat[i].entry),
|
|
273
|
+
sent: chosen.map((i) => ({ id: flat[i].id, hash: hashOf[i] }))
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function continuesEpoch(previous, flat) {
|
|
277
|
+
const at = flat.findIndex((message) => message.id === previous.lastMsgId);
|
|
278
|
+
return at >= 0 && at <= previous.msgCount - 1;
|
|
279
|
+
}
|
|
280
|
+
function historyKey(scope, conversationId) {
|
|
281
|
+
return scope + "\0" + conversationId;
|
|
282
|
+
}
|
|
283
|
+
function createIncrementalState(options = {}) {
|
|
284
|
+
const mode = options.mode ?? (() => incrementalMode(env("TELEM_INCREMENTAL")));
|
|
285
|
+
const forced = options.forced ?? (() => env("TELEM_INCREMENTAL_FORCE") === "1");
|
|
286
|
+
const delivered = createLruSet(DELIVERED_CAP);
|
|
287
|
+
const capability = createLruSet(CAPABILITY_CAP);
|
|
288
|
+
const historyWatermarks = createLruMap(HISTORY_WATERMARK_CAP);
|
|
289
|
+
function omitsDeliveredContext(scope) {
|
|
290
|
+
if (mode() === "off") return false;
|
|
291
|
+
if (forced()) return true;
|
|
292
|
+
return capability.has(scope);
|
|
293
|
+
}
|
|
294
|
+
function planAncestors(plan, chain) {
|
|
295
|
+
const omit = omitsDeliveredContext(plan.scope);
|
|
296
|
+
const entries = [];
|
|
297
|
+
const sentWithContext = [];
|
|
298
|
+
const omitted = [];
|
|
299
|
+
for (const snapshot of chain) {
|
|
300
|
+
const entry = { ...snapshot };
|
|
301
|
+
const key = typeof snapshot.node_key === "string" ? snapshot.node_key : void 0;
|
|
302
|
+
if (key !== void 0 && omit && delivered.has(deliveredKey(plan.scope, key))) {
|
|
303
|
+
const context = entry.context;
|
|
304
|
+
delete entry.context;
|
|
305
|
+
entry.context_omitted = true;
|
|
306
|
+
omitted.push({ key, entry, context });
|
|
307
|
+
} else if (key !== void 0) {
|
|
308
|
+
sentWithContext.push(key);
|
|
309
|
+
}
|
|
310
|
+
entries.push(entry);
|
|
311
|
+
}
|
|
312
|
+
plan.sentWithContext = sentWithContext;
|
|
313
|
+
plan.omitted = omitted;
|
|
314
|
+
return entries;
|
|
315
|
+
}
|
|
316
|
+
async function planHistory(plan, conversationId, sessionKey2, flat) {
|
|
317
|
+
if (mode() !== "history") return flat.map((message) => message.entry);
|
|
318
|
+
const epoch = {
|
|
319
|
+
sessionKey: sessionKey2,
|
|
320
|
+
lastMsgId: flat.length ? flat[flat.length - 1].id : "none",
|
|
321
|
+
msgCount: flat.length
|
|
322
|
+
};
|
|
323
|
+
const previous = historyWatermarks.get(historyKey(plan.scope, conversationId));
|
|
324
|
+
const continuous = previous !== void 0 && !plan.epochDegraded && previous.epoch.sessionKey === epoch.sessionKey && continuesEpoch(previous.epoch, flat);
|
|
325
|
+
const chosen = continuous ? await historyDelta(flat, previous.hashes) : await fullHistorySend(flat);
|
|
326
|
+
plan.history = { conversationKey: conversationId, epoch, sent: chosen.sent };
|
|
327
|
+
return chosen.entries;
|
|
328
|
+
}
|
|
329
|
+
function advanceHistory(plan) {
|
|
330
|
+
const send = plan.history;
|
|
331
|
+
if (!send) return;
|
|
332
|
+
const key = historyKey(plan.scope, send.conversationKey);
|
|
333
|
+
const current = historyWatermarks.get(key);
|
|
334
|
+
if (!current || current.epoch.sessionKey !== send.epoch.sessionKey) {
|
|
335
|
+
const hashes = /* @__PURE__ */ new Map();
|
|
336
|
+
for (const { id, hash } of send.sent) hashes.set(id, hash);
|
|
337
|
+
historyWatermarks.set(key, { epoch: send.epoch, hashes });
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
for (const { id, hash } of send.sent) current.hashes.set(id, hash);
|
|
341
|
+
current.epoch = send.epoch;
|
|
342
|
+
historyWatermarks.set(key, current);
|
|
343
|
+
}
|
|
344
|
+
function recordDelivery(plan, body) {
|
|
345
|
+
for (const key of plan.sentWithContext) delivered.add(deliveredKey(plan.scope, key));
|
|
346
|
+
advanceHistory(plan);
|
|
347
|
+
if (!body || typeof body !== "object") return;
|
|
348
|
+
if (!(MISSING_SNAPSHOTS in body)) return;
|
|
349
|
+
capability.add(plan.scope);
|
|
350
|
+
const missing = body[MISSING_SNAPSHOTS];
|
|
351
|
+
if (Array.isArray(missing)) {
|
|
352
|
+
for (const key of missing) delivered.remove(deliveredKey(plan.scope, String(key)));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function restoreOmittedContexts(plan) {
|
|
356
|
+
for (const { key, entry, context } of plan.omitted) {
|
|
357
|
+
delivered.remove(deliveredKey(plan.scope, key));
|
|
358
|
+
delete entry.context_omitted;
|
|
359
|
+
entry.context = context;
|
|
360
|
+
plan.sentWithContext.push(key);
|
|
361
|
+
}
|
|
362
|
+
plan.omitted = [];
|
|
363
|
+
}
|
|
364
|
+
async function sendWithOmissionRetry(plan, send) {
|
|
365
|
+
try {
|
|
366
|
+
return await send();
|
|
367
|
+
} catch (error) {
|
|
368
|
+
const shape = error;
|
|
369
|
+
if (!isMissingSnapshotsRefusal(shape, plan)) throw error;
|
|
370
|
+
restoreOmittedContexts(plan);
|
|
371
|
+
return await send();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
return { planAncestors, planHistory, recordDelivery, sendWithOmissionRetry };
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/vercel/index.ts
|
|
378
|
+
var SEARCH_TOOL = "telem_search";
|
|
379
|
+
var FETCH_TOOL = "telem_fetch";
|
|
380
|
+
var RESULT_CAP = 12;
|
|
381
|
+
var PAGE_CAP = 4e3;
|
|
382
|
+
var RUNNING = "running";
|
|
383
|
+
function answeredCalls(messages) {
|
|
384
|
+
const answered = /* @__PURE__ */ new Set();
|
|
385
|
+
for (const message of messages) {
|
|
386
|
+
if (!isObject(message) || !Array.isArray(message.content)) continue;
|
|
387
|
+
if (message.role !== "tool" && message.role !== "assistant") continue;
|
|
388
|
+
for (const part of message.content) {
|
|
389
|
+
if (isObject(part) && part.type === "tool-result" && typeof part.toolCallId === "string") {
|
|
390
|
+
answered.add(part.toolCallId);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return answered;
|
|
395
|
+
}
|
|
396
|
+
function telemVercelMessageHistory(messages, current) {
|
|
397
|
+
const answered = answeredCalls(messages);
|
|
398
|
+
const flat = [];
|
|
399
|
+
for (let index = 0; index < messages.length; index++) {
|
|
400
|
+
const message = messages[index];
|
|
401
|
+
if (!isObject(message)) continue;
|
|
402
|
+
const role = message.role;
|
|
403
|
+
if (role !== "user" && role !== "assistant" && role !== "system") continue;
|
|
404
|
+
const pieces = [];
|
|
405
|
+
const thoughts = [];
|
|
406
|
+
const content = message.content;
|
|
407
|
+
if (typeof content === "string") {
|
|
408
|
+
pieces.push(content);
|
|
409
|
+
} else if (Array.isArray(content)) {
|
|
410
|
+
for (const raw of content) {
|
|
411
|
+
if (typeof raw === "string") {
|
|
412
|
+
pieces.push(raw);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (!isObject(raw)) continue;
|
|
416
|
+
const part = raw;
|
|
417
|
+
if (part.type === "text" && typeof part.text === "string") pieces.push(part.text);
|
|
418
|
+
else if (part.type === "reasoning" && typeof part.text === "string") thoughts.push(part.text);
|
|
419
|
+
else if (part.type === "tool-call") {
|
|
420
|
+
const id = typeof part.toolCallId === "string" ? part.toolCallId : "";
|
|
421
|
+
const name = typeof part.toolName === "string" ? part.toolName : "";
|
|
422
|
+
const status = answered.has(id) ? "completed" : "pending";
|
|
423
|
+
pieces.push(toolMarker(name, status, part.input !== void 0 ? part.input : part.args));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
} else if (content !== null && content !== void 0) {
|
|
427
|
+
pieces.push(messageText(content));
|
|
428
|
+
}
|
|
429
|
+
const text = cap(pieces.join("\n"));
|
|
430
|
+
const reasoning = cap(thoughts.join("\n"));
|
|
431
|
+
if (!text && !reasoning) continue;
|
|
432
|
+
const entry = { role, content: text };
|
|
433
|
+
if (reasoning) entry.reasoning = reasoning;
|
|
434
|
+
flat.push({ id: "\0pos:" + index, entry });
|
|
435
|
+
}
|
|
436
|
+
if (current) {
|
|
437
|
+
flat.push({
|
|
438
|
+
id: "\0pos:" + messages.length,
|
|
439
|
+
entry: { role: "assistant", content: toolMarker(current.name, RUNNING, current.input) }
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
return flat;
|
|
443
|
+
}
|
|
444
|
+
async function turnAnchor(messages, windowId) {
|
|
445
|
+
const last = messages[messages.length - 1];
|
|
446
|
+
let text = "";
|
|
447
|
+
try {
|
|
448
|
+
text = last === void 0 ? "" : cap(JSON.stringify(last) ?? "");
|
|
449
|
+
} catch {
|
|
450
|
+
text = isObject(last) ? messageText(last.content) : "";
|
|
451
|
+
}
|
|
452
|
+
return await contentAnchor(String(messages.length), windowId, text);
|
|
453
|
+
}
|
|
454
|
+
function compact(response) {
|
|
455
|
+
return response.results.slice(0, RESULT_CAP).map(({ provider, title, url, summary }) => ({ provider, title, url, summary }));
|
|
456
|
+
}
|
|
457
|
+
function page(response) {
|
|
458
|
+
const first = response.results[0];
|
|
459
|
+
return {
|
|
460
|
+
status: first?.status,
|
|
461
|
+
error: first?.error ?? null,
|
|
462
|
+
content: (first?.content ?? "").slice(0, PAGE_CAP)
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function isInteraction(raw) {
|
|
466
|
+
return isObject(raw) && "session_id" in raw;
|
|
467
|
+
}
|
|
468
|
+
var SEARCH_SCHEMA = (0, import_ai.jsonSchema)({
|
|
469
|
+
type: "object",
|
|
470
|
+
properties: {
|
|
471
|
+
query: { type: "string", description: "One search query." },
|
|
472
|
+
goal: { type: "string", description: "What this search is for, in a few words." },
|
|
473
|
+
context: {
|
|
474
|
+
type: "string",
|
|
475
|
+
description: "Two or three sentences of your reasoning: what you want to find out and why, given what you already know. Not a restatement of the query."
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
required: ["query"],
|
|
479
|
+
additionalProperties: false
|
|
480
|
+
});
|
|
481
|
+
var FETCH_SCHEMA = (0, import_ai.jsonSchema)({
|
|
482
|
+
type: "object",
|
|
483
|
+
properties: {
|
|
484
|
+
url: { type: "string", description: "The http(s) URL to read." },
|
|
485
|
+
goal: { type: "string", description: "What you want from this page, in a few words." }
|
|
486
|
+
},
|
|
487
|
+
required: ["url"],
|
|
488
|
+
additionalProperties: false
|
|
489
|
+
});
|
|
490
|
+
function loadFrames() {
|
|
491
|
+
try {
|
|
492
|
+
const proc = globalThis.process;
|
|
493
|
+
if (typeof proc?.getBuiltinModule !== "function") return void 0;
|
|
494
|
+
const hooks = proc.getBuiltinModule("node:async_hooks");
|
|
495
|
+
return hooks?.AsyncLocalStorage ? new hooks.AsyncLocalStorage() : void 0;
|
|
496
|
+
} catch {
|
|
497
|
+
return void 0;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
var REGISTRY = /* @__PURE__ */ Symbol.for("telem.vercel.registry");
|
|
501
|
+
var registry = globalThis[REGISTRY] ??= {
|
|
502
|
+
frames: loadFrames(),
|
|
503
|
+
sets: /* @__PURE__ */ new WeakMap(),
|
|
504
|
+
owners: /* @__PURE__ */ new WeakMap(),
|
|
505
|
+
turnStarts: /* @__PURE__ */ new WeakMap()
|
|
506
|
+
};
|
|
507
|
+
registry.turnStarts ??= /* @__PURE__ */ new WeakMap();
|
|
508
|
+
var { frames, sets, owners, turnStarts } = registry;
|
|
509
|
+
function turnStart(execution) {
|
|
510
|
+
const key = execution.messages;
|
|
511
|
+
if (typeof key !== "object" || key === null) return (/* @__PURE__ */ new Date()).toISOString();
|
|
512
|
+
const cached = turnStarts.get(key);
|
|
513
|
+
if (cached && cached.length === key.length) return cached.startedAt;
|
|
514
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
515
|
+
turnStarts.set(key, { startedAt, length: key.length });
|
|
516
|
+
return startedAt;
|
|
517
|
+
}
|
|
518
|
+
var telemVercelAutoNesting = frames !== void 0;
|
|
519
|
+
function createTelemVercelAgent(options) {
|
|
520
|
+
const { telem, harness } = options;
|
|
521
|
+
if (typeof harness !== "string" || !harness) throw new TypeError("createTelemVercelAgent requires `harness`");
|
|
522
|
+
const conversationId = options.conversationId ?? crypto.randomUUID();
|
|
523
|
+
const ancestors = [...options.ancestors ?? []];
|
|
524
|
+
const mode = options.incremental;
|
|
525
|
+
const state = options.incrementalState ?? createIncrementalState(mode === void 0 ? {} : { mode: () => mode });
|
|
526
|
+
const renderSearch = options.render?.search ?? compact;
|
|
527
|
+
const renderFetch = options.render?.fetch ?? page;
|
|
528
|
+
const callsPerToolCall = createLruMap(1024);
|
|
529
|
+
function callIdFor(execution) {
|
|
530
|
+
const n = (callsPerToolCall.get(execution.toolCallId) ?? 0) + 1;
|
|
531
|
+
callsPerToolCall.set(execution.toolCallId, n);
|
|
532
|
+
return n === 1 ? execution.toolCallId : `${execution.toolCallId}#${n}`;
|
|
533
|
+
}
|
|
534
|
+
function signalFor(execution, own) {
|
|
535
|
+
const sdk = execution?.abortSignal;
|
|
536
|
+
if (!sdk || !own) return sdk ?? own;
|
|
537
|
+
return typeof AbortSignal.any === "function" ? AbortSignal.any([sdk, own]) : own;
|
|
538
|
+
}
|
|
539
|
+
async function turn(messages) {
|
|
540
|
+
const windowId = await windowAnchor(messages);
|
|
541
|
+
return { windowId, messageId: await turnAnchor(messages, windowId) };
|
|
542
|
+
}
|
|
543
|
+
async function lineage(execution, current) {
|
|
544
|
+
const messages = execution?.messages ?? [];
|
|
545
|
+
const plan = newDeliveryPlan(await cacheScope(telem.baseUrl, telem.apiKey));
|
|
546
|
+
plan.epochDegraded = execution?.messages === void 0;
|
|
547
|
+
const flat = telemVercelMessageHistory(messages, current);
|
|
548
|
+
const { windowId, messageId } = await turn(messages);
|
|
549
|
+
const planned = state.planAncestors(plan, ancestors);
|
|
550
|
+
const envelope = await buildMetadata({
|
|
551
|
+
harness,
|
|
552
|
+
conversationId,
|
|
553
|
+
windowId,
|
|
554
|
+
messageId,
|
|
555
|
+
toolCallId: execution ? callIdFor(execution) : crypto.randomUUID(),
|
|
556
|
+
history: flat.map((message) => message.entry),
|
|
557
|
+
ancestors: planned
|
|
558
|
+
});
|
|
559
|
+
envelope.message_history = await state.planHistory(plan, conversationId, envelope.session_key, flat);
|
|
560
|
+
return { envelope, plan };
|
|
561
|
+
}
|
|
562
|
+
async function search(query, searchOptions, execution) {
|
|
563
|
+
const opts = { ...searchOptions ?? {}, signal: signalFor(execution, searchOptions?.signal) };
|
|
564
|
+
const { envelope, plan } = await lineage(execution, {
|
|
565
|
+
name: SEARCH_TOOL,
|
|
566
|
+
input: { query, goal: opts.goal, context: opts.context }
|
|
567
|
+
});
|
|
568
|
+
const response = await state.sendWithOmissionRetry(
|
|
569
|
+
plan,
|
|
570
|
+
() => telem.search(query, withTrajectory(opts, envelope))
|
|
571
|
+
);
|
|
572
|
+
if (isInteraction(response.raw)) state.recordDelivery(plan, response.raw);
|
|
573
|
+
await notify({ kind: "search", agent, query, response });
|
|
574
|
+
return response;
|
|
575
|
+
}
|
|
576
|
+
async function fetch(url, fetchOptions, execution) {
|
|
577
|
+
const opts = { ...fetchOptions ?? {}, signal: signalFor(execution, fetchOptions?.signal) };
|
|
578
|
+
const { envelope, plan } = await lineage(execution, {
|
|
579
|
+
name: FETCH_TOOL,
|
|
580
|
+
input: { url, goal: opts.metadata?.goal }
|
|
581
|
+
});
|
|
582
|
+
const response = await state.sendWithOmissionRetry(
|
|
583
|
+
plan,
|
|
584
|
+
() => telem.fetch(url, withTrajectory(opts, envelope))
|
|
585
|
+
);
|
|
586
|
+
if (isInteraction(response.raw)) state.recordDelivery(plan, response.raw);
|
|
587
|
+
await notify({ kind: "fetch", agent, url, response });
|
|
588
|
+
return response;
|
|
589
|
+
}
|
|
590
|
+
async function notify(event) {
|
|
591
|
+
try {
|
|
592
|
+
await options.onResponse?.(event);
|
|
593
|
+
} catch {
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async function snapshot(execution, spawnedAt) {
|
|
597
|
+
const messages = execution?.messages ?? [];
|
|
598
|
+
const { windowId, messageId } = await turn(messages);
|
|
599
|
+
return await buildSnapshot({
|
|
600
|
+
harness,
|
|
601
|
+
conversationId,
|
|
602
|
+
windowId,
|
|
603
|
+
messageId,
|
|
604
|
+
context: telemVercelMessageHistory(messages).map((message) => message.entry),
|
|
605
|
+
ancestors,
|
|
606
|
+
spawnedAt
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
async function child(execution, childOptions) {
|
|
610
|
+
return createTelemVercelAgent({
|
|
611
|
+
telem,
|
|
612
|
+
harness,
|
|
613
|
+
conversationId: childOptions?.conversationId,
|
|
614
|
+
ancestors: [...ancestors, await snapshot(execution, childOptions?.spawnedAt)],
|
|
615
|
+
incremental: mode,
|
|
616
|
+
render: options.render,
|
|
617
|
+
onResponse: options.onResponse,
|
|
618
|
+
incrementalState: state
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
const tools = {
|
|
622
|
+
telem_search: {
|
|
623
|
+
description: "Search the public web. One query per call; returns the top results with provider, title, url and summary. Use telem_fetch to read a page in full.",
|
|
624
|
+
inputSchema: SEARCH_SCHEMA,
|
|
625
|
+
execute: async (input, execution) => renderSearch(await search(input.query, { goal: input.goal, context: input.context }, execution))
|
|
626
|
+
},
|
|
627
|
+
telem_fetch: {
|
|
628
|
+
description: "Read the text of one web page by URL. telem_search returns snippets; this returns the page.",
|
|
629
|
+
inputSchema: FETCH_SCHEMA,
|
|
630
|
+
execute: async (input, execution) => renderFetch(
|
|
631
|
+
await fetch(
|
|
632
|
+
input.url,
|
|
633
|
+
{ inlineContent: true, inlineMaxChars: PAGE_CAP, metadata: input.goal ? { goal: input.goal } : void 0 },
|
|
634
|
+
execution
|
|
635
|
+
)
|
|
636
|
+
)
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
const agent = { conversationId, ancestors, telem, tools, search, fetch, snapshot, child };
|
|
640
|
+
return agent;
|
|
641
|
+
}
|
|
642
|
+
async function agentFor(entry, execution) {
|
|
643
|
+
const frame = frames?.getStore();
|
|
644
|
+
if (!frame || frame.owner !== entry) return entry.root;
|
|
645
|
+
if (execution === frame.options || execution?.messages === frame.options.messages) return await frame.agent;
|
|
646
|
+
const parent = await frame.agent;
|
|
647
|
+
const key = await contentAnchor(parent.conversationId, frame.options.toolCallId);
|
|
648
|
+
let child = frame.children.get(key);
|
|
649
|
+
if (!child) {
|
|
650
|
+
child = parent.child(frame.options, { conversationId: key, spawnedAt: frame.startedAt });
|
|
651
|
+
child.catch(() => frame.children.delete(key));
|
|
652
|
+
frame.children.set(key, child);
|
|
653
|
+
}
|
|
654
|
+
return await child;
|
|
655
|
+
}
|
|
656
|
+
function isAsyncIterable(value) {
|
|
657
|
+
return typeof value === "object" && value !== null && Symbol.asyncIterator in value;
|
|
658
|
+
}
|
|
659
|
+
function within(store, frame, source) {
|
|
660
|
+
return {
|
|
661
|
+
[Symbol.asyncIterator]() {
|
|
662
|
+
const iterator = store.run(frame, () => source[Symbol.asyncIterator]());
|
|
663
|
+
return {
|
|
664
|
+
next: (value) => store.run(frame, () => iterator.next(value)),
|
|
665
|
+
return: (value) => store.run(frame, () => iterator.return?.(value) ?? Promise.resolve({ done: true, value })),
|
|
666
|
+
throw: (error) => store.run(frame, () => iterator.throw?.(error) ?? Promise.reject(error))
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function wrapTool(tool, entry) {
|
|
672
|
+
const execute = tool.execute;
|
|
673
|
+
if (typeof execute !== "function") return tool;
|
|
674
|
+
return {
|
|
675
|
+
...tool,
|
|
676
|
+
execute(input, execution) {
|
|
677
|
+
if (!isObject(execution)) return execute.call(tool, input, execution);
|
|
678
|
+
owners.set(execution, entry);
|
|
679
|
+
if (entry.explicit || !frames) return execute.call(tool, input, execution);
|
|
680
|
+
const frame = {
|
|
681
|
+
owner: entry,
|
|
682
|
+
// Never rejects: a frame whose run makes no Telem call never awaits it.
|
|
683
|
+
agent: agentFor(entry, execution).catch(() => entry.root),
|
|
684
|
+
options: execution,
|
|
685
|
+
startedAt: turnStart(execution),
|
|
686
|
+
children: /* @__PURE__ */ new Map()
|
|
687
|
+
};
|
|
688
|
+
const result = frames.run(frame, () => execute.call(tool, input, execution));
|
|
689
|
+
return isAsyncIterable(result) ? within(frames, frame, result) : result;
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function createTelemVercelTools(options) {
|
|
694
|
+
const { tools: own, ...agentOptions } = options;
|
|
695
|
+
return buildSet(createTelemVercelAgent(agentOptions), own, false);
|
|
696
|
+
}
|
|
697
|
+
function entryFor(tools, execution, who) {
|
|
698
|
+
const entry = (isObject(execution) ? owners.get(execution) : void 0) ?? sets.get(tools);
|
|
699
|
+
if (!entry) {
|
|
700
|
+
throw new TypeError(`${who}: pass the set that createTelemVercelTools returned, not a copy of it`);
|
|
701
|
+
}
|
|
702
|
+
return entry;
|
|
703
|
+
}
|
|
704
|
+
async function childTelemVercelTools(tools, execution, options) {
|
|
705
|
+
const entry = entryFor(tools, execution, "childTelemVercelTools");
|
|
706
|
+
const parent = entry.explicit ? entry.root : await agentFor(entry, execution);
|
|
707
|
+
const child = await parent.child(execution, { ...options, spawnedAt: turnStart(execution) });
|
|
708
|
+
return buildSet(child, entry.own, true);
|
|
709
|
+
}
|
|
710
|
+
function buildSet(root, own, explicit) {
|
|
711
|
+
const entry = { root, own, explicit };
|
|
712
|
+
const resolve = explicit ? async () => root : (execution) => agentFor(entry, execution);
|
|
713
|
+
const set = {
|
|
714
|
+
telem_search: {
|
|
715
|
+
...root.tools.telem_search,
|
|
716
|
+
execute: async (input, execution) => (await resolve(execution)).tools.telem_search.execute(input, execution)
|
|
717
|
+
},
|
|
718
|
+
telem_fetch: {
|
|
719
|
+
...root.tools.telem_fetch,
|
|
720
|
+
execute: async (input, execution) => (await resolve(execution)).tools.telem_fetch.execute(input, execution)
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
for (const [name, tool] of Object.entries(own ?? {})) {
|
|
724
|
+
if (name === SEARCH_TOOL || name === FETCH_TOOL) {
|
|
725
|
+
throw new TypeError(`createTelemVercelTools: \`${name}\` is the Telem tool's own name; use \`render\` to change what it returns`);
|
|
726
|
+
}
|
|
727
|
+
set[name] = wrapTool(tool, entry);
|
|
728
|
+
}
|
|
729
|
+
sets.set(set, entry);
|
|
730
|
+
return set;
|
|
731
|
+
}
|
|
732
|
+
async function telemVercelAgentFor(tools, execution) {
|
|
733
|
+
const entry = entryFor(tools, execution, "telemVercelAgentFor");
|
|
734
|
+
return entry.explicit ? entry.root : await agentFor(entry, execution);
|
|
735
|
+
}
|
|
736
|
+
var vercel_default = createTelemVercelAgent;
|
|
737
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
738
|
+
0 && (module.exports = {
|
|
739
|
+
childTelemVercelTools,
|
|
740
|
+
createTelemVercelAgent,
|
|
741
|
+
createTelemVercelTools,
|
|
742
|
+
telemVercelAgentFor,
|
|
743
|
+
telemVercelAutoNesting,
|
|
744
|
+
telemVercelMessageHistory
|
|
745
|
+
});
|
|
746
|
+
module.exports = Object.assign(module.exports.default, module.exports);
|