@threaded/ai 1.0.2 → 1.0.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/dist/index.cjs +228 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -8
- package/dist/index.d.ts +66 -8
- package/dist/index.js +225 -51
- package/dist/index.js.map +1 -1
- package/package.json +6 -11
package/dist/index.cjs
CHANGED
|
@@ -25,7 +25,9 @@ __export(index_exports, {
|
|
|
25
25
|
compose: () => compose,
|
|
26
26
|
convertMCPSchemaToToolSchema: () => convertMCPSchemaToToolSchema,
|
|
27
27
|
convertStandardSchemaToJsonSchema: () => convertStandardSchemaToJsonSchema,
|
|
28
|
+
convertStandardSchemaToSchemaProperties: () => convertStandardSchemaToSchemaProperties,
|
|
28
29
|
createMCPTools: () => createMCPTools,
|
|
30
|
+
embed: () => embed,
|
|
29
31
|
everyNMessages: () => everyNMessages,
|
|
30
32
|
everyNTokens: () => everyNTokens,
|
|
31
33
|
generateApprovalToken: () => generateApprovalToken,
|
|
@@ -39,6 +41,7 @@ __export(index_exports, {
|
|
|
39
41
|
onApprovalRequested: () => onApprovalRequested,
|
|
40
42
|
onApprovalResolved: () => onApprovalResolved,
|
|
41
43
|
parseModelName: () => parseModelName,
|
|
44
|
+
rateLimited: () => rateLimited,
|
|
42
45
|
removeApprovalListener: () => removeApprovalListener,
|
|
43
46
|
requestApproval: () => requestApproval,
|
|
44
47
|
resolveApproval: () => resolveApproval,
|
|
@@ -54,24 +57,16 @@ __export(index_exports, {
|
|
|
54
57
|
module.exports = __toCommonJS(index_exports);
|
|
55
58
|
|
|
56
59
|
// src/schema.ts
|
|
60
|
+
var import_zod = require("zod");
|
|
57
61
|
var isStandardSchema = (schema) => {
|
|
58
62
|
return schema && typeof schema === "object" && "~standard" in schema;
|
|
59
63
|
};
|
|
60
64
|
var convertStandardSchemaToJsonSchema = (standardSchema, name = "Schema") => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
name,
|
|
67
|
-
schema: jsonSchema
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
}
|
|
72
|
-
throw new Error(
|
|
73
|
-
"Standard Schema conversion requires zod v4+ with toJSONSchema support. Please install zod@^4.0.0 or provide a JsonSchema object instead."
|
|
74
|
-
);
|
|
65
|
+
const jsonSchema = import_zod.z.toJSONSchema(standardSchema);
|
|
66
|
+
return {
|
|
67
|
+
name,
|
|
68
|
+
schema: jsonSchema
|
|
69
|
+
};
|
|
75
70
|
};
|
|
76
71
|
var convertMCPSchemaToToolSchema = (mcpSchema) => {
|
|
77
72
|
if (!mcpSchema?.properties) return {};
|
|
@@ -81,7 +76,8 @@ var convertMCPSchemaToToolSchema = (mcpSchema) => {
|
|
|
81
76
|
result[key] = {
|
|
82
77
|
type: prop.type || "string",
|
|
83
78
|
description: prop.description || "",
|
|
84
|
-
optional: !mcpSchema.required?.includes(key)
|
|
79
|
+
optional: !mcpSchema.required?.includes(key),
|
|
80
|
+
...prop.enum && { enum: prop.enum }
|
|
85
81
|
};
|
|
86
82
|
}
|
|
87
83
|
return result;
|
|
@@ -92,6 +88,10 @@ function normalizeSchema(schema, name) {
|
|
|
92
88
|
}
|
|
93
89
|
return schema;
|
|
94
90
|
}
|
|
91
|
+
var convertStandardSchemaToSchemaProperties = (standardSchema) => {
|
|
92
|
+
const jsonSchema = import_zod.z.toJSONSchema(standardSchema);
|
|
93
|
+
return convertMCPSchemaToToolSchema(jsonSchema);
|
|
94
|
+
};
|
|
95
95
|
|
|
96
96
|
// src/mcp.ts
|
|
97
97
|
var createMCPTools = async (client) => {
|
|
@@ -130,9 +130,10 @@ var Inherit = /* @__PURE__ */ ((Inherit2) => {
|
|
|
130
130
|
|
|
131
131
|
// src/utils.ts
|
|
132
132
|
var toolConfigToToolDefinition = (tool) => {
|
|
133
|
+
const schema = isStandardSchema(tool.schema) ? convertStandardSchemaToSchemaProperties(tool.schema) : tool.schema;
|
|
133
134
|
const properties = {};
|
|
134
135
|
const required = [];
|
|
135
|
-
for (const [key, prop] of Object.entries(
|
|
136
|
+
for (const [key, prop] of Object.entries(schema)) {
|
|
136
137
|
properties[key] = convertSchemaProperty(prop);
|
|
137
138
|
if (!prop.optional) {
|
|
138
139
|
required.push(key);
|
|
@@ -198,6 +199,49 @@ var maxCalls = (toolConfig, maxCalls2) => ({
|
|
|
198
199
|
_maxCalls: maxCalls2
|
|
199
200
|
});
|
|
200
201
|
|
|
202
|
+
// src/embed.ts
|
|
203
|
+
var import_transformers = require("@huggingface/transformers");
|
|
204
|
+
var modelCache = /* @__PURE__ */ new Map();
|
|
205
|
+
var embed = async (model2, text, config) => {
|
|
206
|
+
if (model2.startsWith("openai/")) {
|
|
207
|
+
const modelName = model2.replace("openai/", "");
|
|
208
|
+
const apiKey = getKey("openai") || process.env.OPENAI_API_KEY;
|
|
209
|
+
if (!apiKey) {
|
|
210
|
+
throw new Error("OpenAI API key not found");
|
|
211
|
+
}
|
|
212
|
+
const body = {
|
|
213
|
+
model: modelName,
|
|
214
|
+
input: text
|
|
215
|
+
};
|
|
216
|
+
if (config?.dimensions) {
|
|
217
|
+
body.dimensions = config.dimensions;
|
|
218
|
+
}
|
|
219
|
+
const response = await fetch("https://api.openai.com/v1/embeddings", {
|
|
220
|
+
method: "POST",
|
|
221
|
+
headers: {
|
|
222
|
+
"Content-Type": "application/json",
|
|
223
|
+
Authorization: `Bearer ${apiKey}`
|
|
224
|
+
},
|
|
225
|
+
body: JSON.stringify(body)
|
|
226
|
+
});
|
|
227
|
+
if (!response.ok) {
|
|
228
|
+
const error = await response.text();
|
|
229
|
+
throw new Error(`OpenAI API error: ${error}`);
|
|
230
|
+
}
|
|
231
|
+
const data = await response.json();
|
|
232
|
+
return data.data[0].embedding;
|
|
233
|
+
}
|
|
234
|
+
if (!modelCache.has(model2)) {
|
|
235
|
+
const extractor2 = await (0, import_transformers.pipeline)("feature-extraction", model2, {
|
|
236
|
+
dtype: "fp32"
|
|
237
|
+
});
|
|
238
|
+
modelCache.set(model2, extractor2);
|
|
239
|
+
}
|
|
240
|
+
const extractor = modelCache.get(model2);
|
|
241
|
+
const result = await extractor(text, { pooling: "mean", normalize: true });
|
|
242
|
+
return Array.from(result.data);
|
|
243
|
+
};
|
|
244
|
+
|
|
201
245
|
// src/providers/openai.ts
|
|
202
246
|
var appendToolCalls = (toolCalls, tcchunklist) => {
|
|
203
247
|
for (const tcchunk of tcchunklist) {
|
|
@@ -329,18 +373,66 @@ var handleOpenAIStream = async (response, ctx) => {
|
|
|
329
373
|
};
|
|
330
374
|
|
|
331
375
|
// src/providers/anthropic.ts
|
|
376
|
+
var convertToAnthropicFormat = (messages) => {
|
|
377
|
+
const result = [];
|
|
378
|
+
let i = 0;
|
|
379
|
+
while (i < messages.length) {
|
|
380
|
+
const msg = messages[i];
|
|
381
|
+
if (msg.role === "system") {
|
|
382
|
+
i++;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (msg.role === "assistant") {
|
|
386
|
+
if (msg.tool_calls) {
|
|
387
|
+
result.push({
|
|
388
|
+
role: "assistant",
|
|
389
|
+
content: msg.tool_calls.map((tc) => ({
|
|
390
|
+
type: "tool_use",
|
|
391
|
+
id: tc.id,
|
|
392
|
+
name: tc.function.name,
|
|
393
|
+
input: JSON.parse(tc.function.arguments)
|
|
394
|
+
}))
|
|
395
|
+
});
|
|
396
|
+
} else {
|
|
397
|
+
result.push({
|
|
398
|
+
role: "assistant",
|
|
399
|
+
content: msg.content
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
i++;
|
|
403
|
+
} else if (msg.role === "tool") {
|
|
404
|
+
const toolResults = [];
|
|
405
|
+
while (i < messages.length && messages[i].role === "tool") {
|
|
406
|
+
const toolMsg = messages[i];
|
|
407
|
+
toolResults.push({
|
|
408
|
+
type: "tool_result",
|
|
409
|
+
tool_use_id: toolMsg.tool_call_id,
|
|
410
|
+
content: toolMsg.content
|
|
411
|
+
});
|
|
412
|
+
i++;
|
|
413
|
+
}
|
|
414
|
+
result.push({
|
|
415
|
+
role: "user",
|
|
416
|
+
content: toolResults
|
|
417
|
+
});
|
|
418
|
+
} else {
|
|
419
|
+
result.push(msg);
|
|
420
|
+
i++;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return result;
|
|
424
|
+
};
|
|
332
425
|
var callAnthropic = async (config, ctx) => {
|
|
333
426
|
const { model: model2, instructions, schema } = config;
|
|
334
427
|
const apiKey = getKey("anthropic") || process.env.ANTHROPIC_API_KEY;
|
|
335
428
|
if (!apiKey) {
|
|
336
429
|
throw new Error("Anthropic API key not found");
|
|
337
430
|
}
|
|
338
|
-
const messages = [...ctx.history];
|
|
339
431
|
let system = instructions;
|
|
340
|
-
if (
|
|
341
|
-
system =
|
|
342
|
-
messages.shift();
|
|
432
|
+
if (ctx.history[0]?.role === "system") {
|
|
433
|
+
system = ctx.history[0].content;
|
|
343
434
|
}
|
|
435
|
+
const messages = convertToAnthropicFormat(ctx.history);
|
|
344
436
|
if (schema) {
|
|
345
437
|
const schemaPrompt = `
|
|
346
438
|
|
|
@@ -442,10 +534,17 @@ var handleAnthropicStream = async (response, ctx) => {
|
|
|
442
534
|
type: "function",
|
|
443
535
|
function: {
|
|
444
536
|
name: toolUse.name,
|
|
445
|
-
arguments:
|
|
446
|
-
}
|
|
537
|
+
arguments: ""
|
|
538
|
+
},
|
|
539
|
+
index: parsed.index
|
|
447
540
|
});
|
|
448
541
|
}
|
|
542
|
+
if (parsed.type === "content_block_delta" && parsed.delta?.type === "input_json_delta") {
|
|
543
|
+
const toolCall = toolCalls.find((tc) => tc.index === parsed.index);
|
|
544
|
+
if (toolCall) {
|
|
545
|
+
toolCall.function.arguments += parsed.delta.partial_json;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
449
548
|
} catch (e) {
|
|
450
549
|
}
|
|
451
550
|
}
|
|
@@ -459,7 +558,7 @@ var handleAnthropicStream = async (response, ctx) => {
|
|
|
459
558
|
content: fullContent
|
|
460
559
|
};
|
|
461
560
|
if (toolCalls.length > 0) {
|
|
462
|
-
msg.tool_calls = toolCalls;
|
|
561
|
+
msg.tool_calls = toolCalls.map(({ index, ...tc }) => tc);
|
|
463
562
|
}
|
|
464
563
|
return {
|
|
465
564
|
...ctx,
|
|
@@ -681,7 +780,7 @@ var model = ({
|
|
|
681
780
|
tools: []
|
|
682
781
|
}
|
|
683
782
|
) : (
|
|
684
|
-
// model()(/* few shot
|
|
783
|
+
// model()(/* few shot or history */);
|
|
685
784
|
ctxOrMessage
|
|
686
785
|
);
|
|
687
786
|
const normalizedSchema = schema ? normalizeSchema(schema) : void 0;
|
|
@@ -712,27 +811,12 @@ var executeTools = async (ctx) => {
|
|
|
712
811
|
approvalCallback,
|
|
713
812
|
parallel = false,
|
|
714
813
|
retryCount = 0,
|
|
715
|
-
approvalId
|
|
814
|
+
approvalId,
|
|
815
|
+
executeOnApproval = false
|
|
716
816
|
} = toolConfig;
|
|
717
|
-
const approvalPromises = calls.map(async (call) => {
|
|
718
|
-
if (requireApproval) {
|
|
719
|
-
let approved;
|
|
720
|
-
if (approvalCallback) {
|
|
721
|
-
approved = await approvalCallback(call);
|
|
722
|
-
} else {
|
|
723
|
-
const response = await requestApproval(call, approvalId);
|
|
724
|
-
approved = response.approved;
|
|
725
|
-
}
|
|
726
|
-
return { call, approved };
|
|
727
|
-
} else {
|
|
728
|
-
return { call, approved: true };
|
|
729
|
-
}
|
|
730
|
-
});
|
|
731
|
-
const approvals = await Promise.all(approvalPromises);
|
|
732
817
|
const updatedCounts = { ...ctx.toolCallCounts || {} };
|
|
733
|
-
const runCall = async (call) => {
|
|
734
|
-
|
|
735
|
-
if (!approval?.approved) {
|
|
818
|
+
const runCall = async (call, approved) => {
|
|
819
|
+
if (!approved) {
|
|
736
820
|
if (ctx.stream) {
|
|
737
821
|
ctx.stream({
|
|
738
822
|
type: "tool_error",
|
|
@@ -793,7 +877,51 @@ var executeTools = async (ctx) => {
|
|
|
793
877
|
}
|
|
794
878
|
return { call, result: { error } };
|
|
795
879
|
};
|
|
796
|
-
|
|
880
|
+
if (executeOnApproval && requireApproval) {
|
|
881
|
+
const resultPromises = calls.map(async (call) => {
|
|
882
|
+
let approved;
|
|
883
|
+
if (approvalCallback) {
|
|
884
|
+
approved = await approvalCallback(call);
|
|
885
|
+
} else {
|
|
886
|
+
const response = await requestApproval(call, approvalId);
|
|
887
|
+
approved = response.approved;
|
|
888
|
+
}
|
|
889
|
+
return runCall(call, approved);
|
|
890
|
+
});
|
|
891
|
+
const results2 = await Promise.all(resultPromises);
|
|
892
|
+
return {
|
|
893
|
+
...ctx,
|
|
894
|
+
history: [
|
|
895
|
+
...ctx.history,
|
|
896
|
+
...results2.map(({ call, result }) => ({
|
|
897
|
+
role: "tool",
|
|
898
|
+
tool_call_id: call.id,
|
|
899
|
+
content: JSON.stringify(result)
|
|
900
|
+
}))
|
|
901
|
+
],
|
|
902
|
+
toolCallCounts: updatedCounts
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
const approvalPromises = calls.map(async (call) => {
|
|
906
|
+
if (requireApproval) {
|
|
907
|
+
let approved;
|
|
908
|
+
if (approvalCallback) {
|
|
909
|
+
approved = await approvalCallback(call);
|
|
910
|
+
} else {
|
|
911
|
+
const response = await requestApproval(call, approvalId);
|
|
912
|
+
approved = response.approved;
|
|
913
|
+
}
|
|
914
|
+
return { call, approved };
|
|
915
|
+
} else {
|
|
916
|
+
return { call, approved: true };
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
const approvals = await Promise.all(approvalPromises);
|
|
920
|
+
const runCallWithApproval = async (call) => {
|
|
921
|
+
const approval = approvals.find((a) => a.call.id === call.id);
|
|
922
|
+
return runCall(call, approval?.approved ?? true);
|
|
923
|
+
};
|
|
924
|
+
const results = parallel ? await Promise.all(calls.map(runCallWithApproval)) : await runCallsSequentially(calls, runCallWithApproval);
|
|
797
925
|
return {
|
|
798
926
|
...ctx,
|
|
799
927
|
history: [
|
|
@@ -1122,6 +1250,59 @@ var scope = (config, ...steps) => {
|
|
|
1122
1250
|
};
|
|
1123
1251
|
};
|
|
1124
1252
|
};
|
|
1253
|
+
|
|
1254
|
+
// src/utils/rateLimited.ts
|
|
1255
|
+
var rateLimited = (config) => (fn) => {
|
|
1256
|
+
const { rps, burst, concurrency } = config;
|
|
1257
|
+
let tokens = burst;
|
|
1258
|
+
let inFlight = 0;
|
|
1259
|
+
const queue = [];
|
|
1260
|
+
let intervalId = null;
|
|
1261
|
+
const refillTokens = () => {
|
|
1262
|
+
tokens = Math.min(tokens + 1, burst);
|
|
1263
|
+
processQueue();
|
|
1264
|
+
};
|
|
1265
|
+
const startInterval = () => {
|
|
1266
|
+
if (!intervalId) {
|
|
1267
|
+
intervalId = setInterval(refillTokens, 1e3 / rps);
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
const stopInterval = () => {
|
|
1271
|
+
if (intervalId && queue.length === 0 && inFlight === 0) {
|
|
1272
|
+
clearInterval(intervalId);
|
|
1273
|
+
intervalId = null;
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
const processQueue = () => {
|
|
1277
|
+
while (queue.length > 0 && tokens > 0 && inFlight < concurrency) {
|
|
1278
|
+
tokens--;
|
|
1279
|
+
inFlight++;
|
|
1280
|
+
const item = queue.shift();
|
|
1281
|
+
item.fn().then((result) => {
|
|
1282
|
+
inFlight--;
|
|
1283
|
+
item.resolve(result);
|
|
1284
|
+
processQueue();
|
|
1285
|
+
stopInterval();
|
|
1286
|
+
}).catch((error) => {
|
|
1287
|
+
inFlight--;
|
|
1288
|
+
item.reject(error);
|
|
1289
|
+
processQueue();
|
|
1290
|
+
stopInterval();
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
1294
|
+
return (async (...args) => {
|
|
1295
|
+
return new Promise((resolve, reject) => {
|
|
1296
|
+
queue.push({
|
|
1297
|
+
fn: () => fn(...args),
|
|
1298
|
+
resolve,
|
|
1299
|
+
reject
|
|
1300
|
+
});
|
|
1301
|
+
startInterval();
|
|
1302
|
+
processQueue();
|
|
1303
|
+
});
|
|
1304
|
+
});
|
|
1305
|
+
};
|
|
1125
1306
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1126
1307
|
0 && (module.exports = {
|
|
1127
1308
|
Inherit,
|
|
@@ -1129,7 +1310,9 @@ var scope = (config, ...steps) => {
|
|
|
1129
1310
|
compose,
|
|
1130
1311
|
convertMCPSchemaToToolSchema,
|
|
1131
1312
|
convertStandardSchemaToJsonSchema,
|
|
1313
|
+
convertStandardSchemaToSchemaProperties,
|
|
1132
1314
|
createMCPTools,
|
|
1315
|
+
embed,
|
|
1133
1316
|
everyNMessages,
|
|
1134
1317
|
everyNTokens,
|
|
1135
1318
|
generateApprovalToken,
|
|
@@ -1143,6 +1326,7 @@ var scope = (config, ...steps) => {
|
|
|
1143
1326
|
onApprovalRequested,
|
|
1144
1327
|
onApprovalResolved,
|
|
1145
1328
|
parseModelName,
|
|
1329
|
+
rateLimited,
|
|
1146
1330
|
removeApprovalListener,
|
|
1147
1331
|
requestApproval,
|
|
1148
1332
|
resolveApproval,
|