@radaros/core 0.2.0 → 0.3.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/dist/index.d.ts +174 -1
- package/dist/index.js +822 -37
- package/package.json +6 -2
- package/src/index.ts +14 -1
- package/src/models/providers/vertex.ts +400 -0
- package/src/models/registry.ts +17 -0
- package/src/toolkits/base.ts +15 -0
- package/src/toolkits/gmail.ts +226 -0
- package/src/toolkits/hackernews.ts +121 -0
- package/src/toolkits/websearch.ts +158 -0
- package/src/toolkits/whatsapp.ts +209 -0
package/dist/index.js
CHANGED
|
@@ -2367,6 +2367,291 @@ var OllamaProvider = class {
|
|
|
2367
2367
|
}
|
|
2368
2368
|
};
|
|
2369
2369
|
|
|
2370
|
+
// src/models/providers/vertex.ts
|
|
2371
|
+
import { createRequire as createRequire7 } from "module";
|
|
2372
|
+
var _require7 = createRequire7(import.meta.url);
|
|
2373
|
+
var VertexAIProvider = class {
|
|
2374
|
+
providerId = "vertex";
|
|
2375
|
+
modelId;
|
|
2376
|
+
ai = null;
|
|
2377
|
+
GoogleGenAICtor;
|
|
2378
|
+
project;
|
|
2379
|
+
location;
|
|
2380
|
+
constructor(modelId, config) {
|
|
2381
|
+
this.modelId = modelId;
|
|
2382
|
+
this.project = config?.project ?? process.env.GOOGLE_CLOUD_PROJECT ?? process.env.GCLOUD_PROJECT ?? "";
|
|
2383
|
+
this.location = config?.location ?? process.env.GOOGLE_CLOUD_LOCATION ?? process.env.GOOGLE_CLOUD_REGION ?? "us-central1";
|
|
2384
|
+
if (!this.project) {
|
|
2385
|
+
throw new Error(
|
|
2386
|
+
"VertexAIProvider: 'project' is required. Pass it in config or set GOOGLE_CLOUD_PROJECT env var."
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
try {
|
|
2390
|
+
const { GoogleGenAI } = _require7("@google/genai");
|
|
2391
|
+
this.GoogleGenAICtor = GoogleGenAI;
|
|
2392
|
+
} catch {
|
|
2393
|
+
throw new Error(
|
|
2394
|
+
"@google/genai is required for VertexAIProvider. Install it: npm install @google/genai"
|
|
2395
|
+
);
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
getClient() {
|
|
2399
|
+
if (this.ai) return this.ai;
|
|
2400
|
+
this.ai = new this.GoogleGenAICtor({
|
|
2401
|
+
vertexai: true,
|
|
2402
|
+
project: this.project,
|
|
2403
|
+
location: this.location
|
|
2404
|
+
});
|
|
2405
|
+
return this.ai;
|
|
2406
|
+
}
|
|
2407
|
+
async generate(messages, options) {
|
|
2408
|
+
const { systemInstruction, contents } = this.toGoogleMessages(messages);
|
|
2409
|
+
const config = {};
|
|
2410
|
+
if (options?.temperature !== void 0)
|
|
2411
|
+
config.temperature = options.temperature;
|
|
2412
|
+
if (options?.maxTokens !== void 0)
|
|
2413
|
+
config.maxOutputTokens = options.maxTokens;
|
|
2414
|
+
if (options?.topP !== void 0) config.topP = options.topP;
|
|
2415
|
+
if (options?.stop) config.stopSequences = options.stop;
|
|
2416
|
+
if (options?.responseFormat) {
|
|
2417
|
+
config.responseMimeType = "application/json";
|
|
2418
|
+
const rf = options.responseFormat;
|
|
2419
|
+
if (typeof rf === "object" && rf !== null && "type" in rf && rf.type === "json_schema" && "schema" in rf && rf.schema) {
|
|
2420
|
+
config.responseSchema = this.cleanJsonSchema(
|
|
2421
|
+
rf.schema
|
|
2422
|
+
);
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
const params = {
|
|
2426
|
+
model: this.modelId,
|
|
2427
|
+
contents,
|
|
2428
|
+
config
|
|
2429
|
+
};
|
|
2430
|
+
if (systemInstruction) params.systemInstruction = systemInstruction;
|
|
2431
|
+
if (options?.tools?.length) {
|
|
2432
|
+
params.tools = [
|
|
2433
|
+
{ functionDeclarations: this.toGoogleTools(options.tools) }
|
|
2434
|
+
];
|
|
2435
|
+
}
|
|
2436
|
+
const client = this.getClient();
|
|
2437
|
+
const response = await client.models.generateContent(params);
|
|
2438
|
+
return this.normalizeResponse(response);
|
|
2439
|
+
}
|
|
2440
|
+
async *stream(messages, options) {
|
|
2441
|
+
const { systemInstruction, contents } = this.toGoogleMessages(messages);
|
|
2442
|
+
const config = {};
|
|
2443
|
+
if (options?.temperature !== void 0)
|
|
2444
|
+
config.temperature = options.temperature;
|
|
2445
|
+
if (options?.maxTokens !== void 0)
|
|
2446
|
+
config.maxOutputTokens = options.maxTokens;
|
|
2447
|
+
if (options?.topP !== void 0) config.topP = options.topP;
|
|
2448
|
+
if (options?.stop) config.stopSequences = options.stop;
|
|
2449
|
+
const params = {
|
|
2450
|
+
model: this.modelId,
|
|
2451
|
+
contents,
|
|
2452
|
+
config
|
|
2453
|
+
};
|
|
2454
|
+
if (systemInstruction) params.systemInstruction = systemInstruction;
|
|
2455
|
+
if (options?.tools?.length) {
|
|
2456
|
+
params.tools = [
|
|
2457
|
+
{ functionDeclarations: this.toGoogleTools(options.tools) }
|
|
2458
|
+
];
|
|
2459
|
+
}
|
|
2460
|
+
const client = this.getClient();
|
|
2461
|
+
const streamResult = await client.models.generateContentStream(params);
|
|
2462
|
+
let toolCallCounter = 0;
|
|
2463
|
+
for await (const chunk of streamResult) {
|
|
2464
|
+
const candidate = chunk.candidates?.[0];
|
|
2465
|
+
if (!candidate?.content?.parts) continue;
|
|
2466
|
+
for (const part of candidate.content.parts) {
|
|
2467
|
+
if (part.text) {
|
|
2468
|
+
yield { type: "text", text: part.text };
|
|
2469
|
+
}
|
|
2470
|
+
if (part.functionCall) {
|
|
2471
|
+
const id = `vertex_tc_${toolCallCounter++}`;
|
|
2472
|
+
yield {
|
|
2473
|
+
type: "tool_call_start",
|
|
2474
|
+
toolCall: { id, name: part.functionCall.name }
|
|
2475
|
+
};
|
|
2476
|
+
yield {
|
|
2477
|
+
type: "tool_call_delta",
|
|
2478
|
+
toolCallId: id,
|
|
2479
|
+
argumentsDelta: JSON.stringify(part.functionCall.args ?? {})
|
|
2480
|
+
};
|
|
2481
|
+
yield { type: "tool_call_end", toolCallId: id };
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
if (candidate.finishReason) {
|
|
2485
|
+
let finishReason = "stop";
|
|
2486
|
+
if (candidate.finishReason === "STOP" || candidate.finishReason === "END_TURN")
|
|
2487
|
+
finishReason = "stop";
|
|
2488
|
+
else if (candidate.finishReason === "MAX_TOKENS")
|
|
2489
|
+
finishReason = "length";
|
|
2490
|
+
else if (candidate.finishReason === "SAFETY")
|
|
2491
|
+
finishReason = "content_filter";
|
|
2492
|
+
const hasToolCalls = candidate.content?.parts?.some(
|
|
2493
|
+
(p) => p.functionCall
|
|
2494
|
+
);
|
|
2495
|
+
if (hasToolCalls) finishReason = "tool_calls";
|
|
2496
|
+
yield {
|
|
2497
|
+
type: "finish",
|
|
2498
|
+
finishReason,
|
|
2499
|
+
usage: chunk.usageMetadata ? {
|
|
2500
|
+
promptTokens: chunk.usageMetadata.promptTokenCount ?? 0,
|
|
2501
|
+
completionTokens: chunk.usageMetadata.candidatesTokenCount ?? 0,
|
|
2502
|
+
totalTokens: chunk.usageMetadata.totalTokenCount ?? 0
|
|
2503
|
+
} : void 0
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
// ── Message conversion (identical to GoogleProvider) ─────────────────────
|
|
2509
|
+
toGoogleMessages(messages) {
|
|
2510
|
+
let systemInstruction;
|
|
2511
|
+
const contents = [];
|
|
2512
|
+
for (const msg of messages) {
|
|
2513
|
+
if (msg.role === "system") {
|
|
2514
|
+
systemInstruction = getTextContent(msg.content) || void 0;
|
|
2515
|
+
continue;
|
|
2516
|
+
}
|
|
2517
|
+
if (msg.role === "user") {
|
|
2518
|
+
if (isMultiModal(msg.content)) {
|
|
2519
|
+
contents.push({
|
|
2520
|
+
role: "user",
|
|
2521
|
+
parts: msg.content.map((p) => this.partToGoogle(p))
|
|
2522
|
+
});
|
|
2523
|
+
} else {
|
|
2524
|
+
contents.push({
|
|
2525
|
+
role: "user",
|
|
2526
|
+
parts: [{ text: msg.content ?? "" }]
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
2529
|
+
continue;
|
|
2530
|
+
}
|
|
2531
|
+
if (msg.role === "assistant") {
|
|
2532
|
+
const parts = [];
|
|
2533
|
+
if (msg.content) parts.push({ text: msg.content });
|
|
2534
|
+
if (msg.toolCalls) {
|
|
2535
|
+
for (const tc of msg.toolCalls) {
|
|
2536
|
+
parts.push({
|
|
2537
|
+
functionCall: { name: tc.name, args: tc.arguments }
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
if (parts.length === 0) parts.push({ text: "" });
|
|
2542
|
+
contents.push({ role: "model", parts });
|
|
2543
|
+
continue;
|
|
2544
|
+
}
|
|
2545
|
+
if (msg.role === "tool") {
|
|
2546
|
+
contents.push({
|
|
2547
|
+
role: "function",
|
|
2548
|
+
parts: [
|
|
2549
|
+
{
|
|
2550
|
+
functionResponse: {
|
|
2551
|
+
name: msg.name ?? "unknown",
|
|
2552
|
+
response: { result: msg.content ?? "" }
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
]
|
|
2556
|
+
});
|
|
2557
|
+
continue;
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
return { systemInstruction, contents };
|
|
2561
|
+
}
|
|
2562
|
+
partToGoogle(part) {
|
|
2563
|
+
switch (part.type) {
|
|
2564
|
+
case "text":
|
|
2565
|
+
return { text: part.text };
|
|
2566
|
+
case "image":
|
|
2567
|
+
case "audio":
|
|
2568
|
+
case "file": {
|
|
2569
|
+
const isUrl = part.data.startsWith("http://") || part.data.startsWith("https://");
|
|
2570
|
+
if (isUrl) {
|
|
2571
|
+
return {
|
|
2572
|
+
fileData: {
|
|
2573
|
+
fileUri: part.data,
|
|
2574
|
+
mimeType: part.mimeType ?? (part.type === "image" ? "image/png" : "application/octet-stream")
|
|
2575
|
+
}
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
return {
|
|
2579
|
+
inlineData: {
|
|
2580
|
+
data: part.data,
|
|
2581
|
+
mimeType: part.mimeType ?? (part.type === "image" ? "image/png" : part.type === "audio" ? "audio/mp3" : "application/octet-stream")
|
|
2582
|
+
}
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}
|
|
2587
|
+
toGoogleTools(tools) {
|
|
2588
|
+
return tools.map((t) => ({
|
|
2589
|
+
name: t.name,
|
|
2590
|
+
description: t.description,
|
|
2591
|
+
parameters: t.parameters
|
|
2592
|
+
}));
|
|
2593
|
+
}
|
|
2594
|
+
cleanJsonSchema(schema) {
|
|
2595
|
+
const cleaned = { ...schema };
|
|
2596
|
+
delete cleaned["$schema"];
|
|
2597
|
+
delete cleaned["$ref"];
|
|
2598
|
+
delete cleaned["additionalProperties"];
|
|
2599
|
+
if (cleaned.properties && typeof cleaned.properties === "object") {
|
|
2600
|
+
const props = {};
|
|
2601
|
+
for (const [key, val] of Object.entries(
|
|
2602
|
+
cleaned.properties
|
|
2603
|
+
)) {
|
|
2604
|
+
props[key] = typeof val === "object" && val ? this.cleanJsonSchema(val) : val;
|
|
2605
|
+
}
|
|
2606
|
+
cleaned.properties = props;
|
|
2607
|
+
}
|
|
2608
|
+
if (cleaned.items && typeof cleaned.items === "object") {
|
|
2609
|
+
cleaned.items = this.cleanJsonSchema(
|
|
2610
|
+
cleaned.items
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
return cleaned;
|
|
2614
|
+
}
|
|
2615
|
+
normalizeResponse(response) {
|
|
2616
|
+
const candidate = response.candidates?.[0];
|
|
2617
|
+
const parts = candidate?.content?.parts ?? [];
|
|
2618
|
+
let textContent = "";
|
|
2619
|
+
const toolCalls = [];
|
|
2620
|
+
let toolCallCounter = 0;
|
|
2621
|
+
for (const part of parts) {
|
|
2622
|
+
if (part.text) textContent += part.text;
|
|
2623
|
+
if (part.functionCall) {
|
|
2624
|
+
toolCalls.push({
|
|
2625
|
+
id: `vertex_tc_${toolCallCounter++}`,
|
|
2626
|
+
name: part.functionCall.name,
|
|
2627
|
+
arguments: part.functionCall.args ?? {}
|
|
2628
|
+
});
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
const usage = {
|
|
2632
|
+
promptTokens: response.usageMetadata?.promptTokenCount ?? 0,
|
|
2633
|
+
completionTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
|
|
2634
|
+
totalTokens: response.usageMetadata?.totalTokenCount ?? 0
|
|
2635
|
+
};
|
|
2636
|
+
let finishReason = "stop";
|
|
2637
|
+
if (toolCalls.length > 0) finishReason = "tool_calls";
|
|
2638
|
+
else if (candidate?.finishReason === "MAX_TOKENS")
|
|
2639
|
+
finishReason = "length";
|
|
2640
|
+
else if (candidate?.finishReason === "SAFETY")
|
|
2641
|
+
finishReason = "content_filter";
|
|
2642
|
+
return {
|
|
2643
|
+
message: {
|
|
2644
|
+
role: "assistant",
|
|
2645
|
+
content: textContent || null,
|
|
2646
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : void 0
|
|
2647
|
+
},
|
|
2648
|
+
usage,
|
|
2649
|
+
finishReason,
|
|
2650
|
+
raw: response
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
};
|
|
2654
|
+
|
|
2370
2655
|
// src/models/registry.ts
|
|
2371
2656
|
var ModelRegistry = class {
|
|
2372
2657
|
factories = /* @__PURE__ */ new Map();
|
|
@@ -2415,6 +2700,16 @@ function google(modelId, config) {
|
|
|
2415
2700
|
function ollama(modelId, config) {
|
|
2416
2701
|
return registry.resolve("ollama", modelId, config);
|
|
2417
2702
|
}
|
|
2703
|
+
registry.register(
|
|
2704
|
+
"vertex",
|
|
2705
|
+
(modelId, config) => new VertexAIProvider(
|
|
2706
|
+
modelId,
|
|
2707
|
+
config
|
|
2708
|
+
)
|
|
2709
|
+
);
|
|
2710
|
+
function vertex(modelId, config) {
|
|
2711
|
+
return registry.resolve("vertex", modelId, config);
|
|
2712
|
+
}
|
|
2418
2713
|
|
|
2419
2714
|
// src/tools/define-tool.ts
|
|
2420
2715
|
function defineTool(config) {
|
|
@@ -2427,13 +2722,13 @@ function defineTool(config) {
|
|
|
2427
2722
|
}
|
|
2428
2723
|
|
|
2429
2724
|
// src/storage/sqlite.ts
|
|
2430
|
-
import { createRequire as
|
|
2431
|
-
var
|
|
2725
|
+
import { createRequire as createRequire8 } from "module";
|
|
2726
|
+
var _require8 = createRequire8(import.meta.url);
|
|
2432
2727
|
var SqliteStorage = class {
|
|
2433
2728
|
db;
|
|
2434
2729
|
constructor(dbPath) {
|
|
2435
2730
|
try {
|
|
2436
|
-
const Database =
|
|
2731
|
+
const Database = _require8("better-sqlite3");
|
|
2437
2732
|
this.db = new Database(dbPath);
|
|
2438
2733
|
this.db.pragma("journal_mode = WAL");
|
|
2439
2734
|
this.db.exec(`
|
|
@@ -2482,13 +2777,13 @@ var SqliteStorage = class {
|
|
|
2482
2777
|
};
|
|
2483
2778
|
|
|
2484
2779
|
// src/storage/postgres.ts
|
|
2485
|
-
import { createRequire as
|
|
2486
|
-
var
|
|
2780
|
+
import { createRequire as createRequire9 } from "module";
|
|
2781
|
+
var _require9 = createRequire9(import.meta.url);
|
|
2487
2782
|
var PostgresStorage = class {
|
|
2488
2783
|
pool;
|
|
2489
2784
|
constructor(connectionString) {
|
|
2490
2785
|
try {
|
|
2491
|
-
const { Pool } =
|
|
2786
|
+
const { Pool } = _require9("pg");
|
|
2492
2787
|
this.pool = new Pool({ connectionString });
|
|
2493
2788
|
} catch {
|
|
2494
2789
|
throw new Error(
|
|
@@ -2549,15 +2844,15 @@ var PostgresStorage = class {
|
|
|
2549
2844
|
};
|
|
2550
2845
|
|
|
2551
2846
|
// src/storage/mongodb.ts
|
|
2552
|
-
import { createRequire as
|
|
2553
|
-
var
|
|
2847
|
+
import { createRequire as createRequire10 } from "module";
|
|
2848
|
+
var _require10 = createRequire10(import.meta.url);
|
|
2554
2849
|
var MongoDBStorage = class {
|
|
2555
2850
|
constructor(uri, dbName = "radaros", collectionName = "kv_store") {
|
|
2556
2851
|
this.uri = uri;
|
|
2557
2852
|
this.dbName = dbName;
|
|
2558
2853
|
this.collectionName = collectionName;
|
|
2559
2854
|
try {
|
|
2560
|
-
const { MongoClient } =
|
|
2855
|
+
const { MongoClient } = _require10("mongodb");
|
|
2561
2856
|
this.client = new MongoClient(uri);
|
|
2562
2857
|
} catch {
|
|
2563
2858
|
throw new Error(
|
|
@@ -2717,8 +3012,8 @@ var InMemoryVectorStore = class extends BaseVectorStore {
|
|
|
2717
3012
|
};
|
|
2718
3013
|
|
|
2719
3014
|
// src/vector/pgvector.ts
|
|
2720
|
-
import { createRequire as
|
|
2721
|
-
var
|
|
3015
|
+
import { createRequire as createRequire11 } from "module";
|
|
3016
|
+
var _require11 = createRequire11(import.meta.url);
|
|
2722
3017
|
var PgVectorStore = class extends BaseVectorStore {
|
|
2723
3018
|
pool;
|
|
2724
3019
|
dimensions;
|
|
@@ -2727,7 +3022,7 @@ var PgVectorStore = class extends BaseVectorStore {
|
|
|
2727
3022
|
super(embedder);
|
|
2728
3023
|
this.dimensions = config.dimensions ?? embedder?.dimensions ?? 1536;
|
|
2729
3024
|
try {
|
|
2730
|
-
const { Pool } =
|
|
3025
|
+
const { Pool } = _require11("pg");
|
|
2731
3026
|
this.pool = new Pool({ connectionString: config.connectionString });
|
|
2732
3027
|
} catch {
|
|
2733
3028
|
throw new Error(
|
|
@@ -2846,9 +3141,9 @@ var PgVectorStore = class extends BaseVectorStore {
|
|
|
2846
3141
|
};
|
|
2847
3142
|
|
|
2848
3143
|
// src/vector/qdrant.ts
|
|
2849
|
-
import { createRequire as
|
|
3144
|
+
import { createRequire as createRequire12 } from "module";
|
|
2850
3145
|
import { createHash } from "crypto";
|
|
2851
|
-
var
|
|
3146
|
+
var _require12 = createRequire12(import.meta.url);
|
|
2852
3147
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2853
3148
|
function stringToUUID(str) {
|
|
2854
3149
|
const hex = createHash("md5").update(str).digest("hex");
|
|
@@ -2873,7 +3168,7 @@ var QdrantVectorStore = class extends BaseVectorStore {
|
|
|
2873
3168
|
super(embedder);
|
|
2874
3169
|
this.dimensions = config.dimensions ?? embedder?.dimensions ?? 1536;
|
|
2875
3170
|
try {
|
|
2876
|
-
const { QdrantClient } =
|
|
3171
|
+
const { QdrantClient } = _require12("@qdrant/js-client-rest");
|
|
2877
3172
|
this.client = new QdrantClient({
|
|
2878
3173
|
url: config.url ?? "http://localhost:6333",
|
|
2879
3174
|
apiKey: config.apiKey,
|
|
@@ -3006,8 +3301,8 @@ var QdrantVectorStore = class extends BaseVectorStore {
|
|
|
3006
3301
|
};
|
|
3007
3302
|
|
|
3008
3303
|
// src/vector/mongodb.ts
|
|
3009
|
-
import { createRequire as
|
|
3010
|
-
var
|
|
3304
|
+
import { createRequire as createRequire13 } from "module";
|
|
3305
|
+
var _require13 = createRequire13(import.meta.url);
|
|
3011
3306
|
var MongoDBVectorStore = class extends BaseVectorStore {
|
|
3012
3307
|
client;
|
|
3013
3308
|
db;
|
|
@@ -3019,7 +3314,7 @@ var MongoDBVectorStore = class extends BaseVectorStore {
|
|
|
3019
3314
|
this.indexName = config.indexName ?? "vector_index";
|
|
3020
3315
|
this.dbName = config.dbName ?? "radaros_vectors";
|
|
3021
3316
|
try {
|
|
3022
|
-
const { MongoClient } =
|
|
3317
|
+
const { MongoClient } = _require13("mongodb");
|
|
3023
3318
|
this.client = new MongoClient(config.uri);
|
|
3024
3319
|
} catch {
|
|
3025
3320
|
throw new Error(
|
|
@@ -3190,8 +3485,8 @@ function cosine(a, b) {
|
|
|
3190
3485
|
}
|
|
3191
3486
|
|
|
3192
3487
|
// src/vector/embeddings/openai.ts
|
|
3193
|
-
import { createRequire as
|
|
3194
|
-
var
|
|
3488
|
+
import { createRequire as createRequire14 } from "module";
|
|
3489
|
+
var _require14 = createRequire14(import.meta.url);
|
|
3195
3490
|
var MODEL_DIMENSIONS = {
|
|
3196
3491
|
"text-embedding-3-small": 1536,
|
|
3197
3492
|
"text-embedding-3-large": 3072,
|
|
@@ -3205,7 +3500,7 @@ var OpenAIEmbedding = class {
|
|
|
3205
3500
|
this.model = config.model ?? "text-embedding-3-small";
|
|
3206
3501
|
this.dimensions = config.dimensions ?? MODEL_DIMENSIONS[this.model] ?? 1536;
|
|
3207
3502
|
try {
|
|
3208
|
-
const mod =
|
|
3503
|
+
const mod = _require14("openai");
|
|
3209
3504
|
const OpenAI = mod.default ?? mod;
|
|
3210
3505
|
this.client = new OpenAI({
|
|
3211
3506
|
apiKey: config.apiKey ?? process.env.OPENAI_API_KEY,
|
|
@@ -3236,8 +3531,8 @@ var OpenAIEmbedding = class {
|
|
|
3236
3531
|
};
|
|
3237
3532
|
|
|
3238
3533
|
// src/vector/embeddings/google.ts
|
|
3239
|
-
import { createRequire as
|
|
3240
|
-
var
|
|
3534
|
+
import { createRequire as createRequire15 } from "module";
|
|
3535
|
+
var _require15 = createRequire15(import.meta.url);
|
|
3241
3536
|
var MODEL_DIMENSIONS2 = {
|
|
3242
3537
|
"text-embedding-004": 768,
|
|
3243
3538
|
"embedding-001": 768
|
|
@@ -3250,7 +3545,7 @@ var GoogleEmbedding = class {
|
|
|
3250
3545
|
this.model = config.model ?? "text-embedding-004";
|
|
3251
3546
|
this.dimensions = config.dimensions ?? MODEL_DIMENSIONS2[this.model] ?? 768;
|
|
3252
3547
|
try {
|
|
3253
|
-
const { GoogleGenAI } =
|
|
3548
|
+
const { GoogleGenAI } = _require15("@google/genai");
|
|
3254
3549
|
this.ai = new GoogleGenAI({
|
|
3255
3550
|
apiKey: config.apiKey ?? process.env.GOOGLE_API_KEY
|
|
3256
3551
|
});
|
|
@@ -3492,14 +3787,14 @@ var MCPToolProvider = class {
|
|
|
3492
3787
|
await this.discoverTools();
|
|
3493
3788
|
}
|
|
3494
3789
|
async discoverTools() {
|
|
3495
|
-
const { z:
|
|
3790
|
+
const { z: z7 } = await import("zod");
|
|
3496
3791
|
const result = await this.client.listTools();
|
|
3497
3792
|
const mcpTools = result.tools ?? [];
|
|
3498
3793
|
this.tools = mcpTools.map((mcpTool) => {
|
|
3499
3794
|
const toolName = mcpTool.name;
|
|
3500
3795
|
const description = mcpTool.description ?? "";
|
|
3501
3796
|
const inputSchema = mcpTool.inputSchema ?? { type: "object", properties: {} };
|
|
3502
|
-
const parameters = this.jsonSchemaToZod(inputSchema,
|
|
3797
|
+
const parameters = this.jsonSchemaToZod(inputSchema, z7);
|
|
3503
3798
|
const execute = async (args, _ctx) => {
|
|
3504
3799
|
const callResult = await this.client.callTool({
|
|
3505
3800
|
name: toolName,
|
|
@@ -3527,9 +3822,9 @@ var MCPToolProvider = class {
|
|
|
3527
3822
|
};
|
|
3528
3823
|
});
|
|
3529
3824
|
}
|
|
3530
|
-
jsonSchemaToZod(schema,
|
|
3825
|
+
jsonSchemaToZod(schema, z7) {
|
|
3531
3826
|
if (!schema || !schema.properties) {
|
|
3532
|
-
return
|
|
3827
|
+
return z7.object({}).passthrough();
|
|
3533
3828
|
}
|
|
3534
3829
|
const shape = {};
|
|
3535
3830
|
const required = schema.required ?? [];
|
|
@@ -3537,24 +3832,24 @@ var MCPToolProvider = class {
|
|
|
3537
3832
|
let field;
|
|
3538
3833
|
switch (prop.type) {
|
|
3539
3834
|
case "string":
|
|
3540
|
-
field =
|
|
3541
|
-
if (prop.enum) field =
|
|
3835
|
+
field = z7.string();
|
|
3836
|
+
if (prop.enum) field = z7.enum(prop.enum);
|
|
3542
3837
|
break;
|
|
3543
3838
|
case "number":
|
|
3544
3839
|
case "integer":
|
|
3545
|
-
field =
|
|
3840
|
+
field = z7.number();
|
|
3546
3841
|
break;
|
|
3547
3842
|
case "boolean":
|
|
3548
|
-
field =
|
|
3843
|
+
field = z7.boolean();
|
|
3549
3844
|
break;
|
|
3550
3845
|
case "array":
|
|
3551
|
-
field =
|
|
3846
|
+
field = z7.array(z7.any());
|
|
3552
3847
|
break;
|
|
3553
3848
|
case "object":
|
|
3554
|
-
field =
|
|
3849
|
+
field = z7.record(z7.any());
|
|
3555
3850
|
break;
|
|
3556
3851
|
default:
|
|
3557
|
-
field =
|
|
3852
|
+
field = z7.any();
|
|
3558
3853
|
}
|
|
3559
3854
|
if (prop.description) {
|
|
3560
3855
|
field = field.describe(prop.description);
|
|
@@ -3564,7 +3859,7 @@ var MCPToolProvider = class {
|
|
|
3564
3859
|
}
|
|
3565
3860
|
shape[key] = field;
|
|
3566
3861
|
}
|
|
3567
|
-
return
|
|
3862
|
+
return z7.object(shape);
|
|
3568
3863
|
}
|
|
3569
3864
|
/**
|
|
3570
3865
|
* Returns tools from this MCP server as RadarOS ToolDef[].
|
|
@@ -3813,14 +4108,499 @@ var A2ARemoteAgent = class {
|
|
|
3813
4108
|
).map((p) => p.text).join("\n");
|
|
3814
4109
|
}
|
|
3815
4110
|
};
|
|
4111
|
+
|
|
4112
|
+
// src/toolkits/base.ts
|
|
4113
|
+
var Toolkit = class {
|
|
4114
|
+
};
|
|
4115
|
+
|
|
4116
|
+
// src/toolkits/websearch.ts
|
|
4117
|
+
import { z as z3 } from "zod";
|
|
4118
|
+
var WebSearchToolkit = class extends Toolkit {
|
|
4119
|
+
name = "websearch";
|
|
4120
|
+
config;
|
|
4121
|
+
constructor(config) {
|
|
4122
|
+
super();
|
|
4123
|
+
this.config = config;
|
|
4124
|
+
}
|
|
4125
|
+
getApiKey() {
|
|
4126
|
+
if (this.config.apiKey) return this.config.apiKey;
|
|
4127
|
+
const envKey = this.config.provider === "tavily" ? process.env.TAVILY_API_KEY : process.env.SERPAPI_API_KEY;
|
|
4128
|
+
if (!envKey) {
|
|
4129
|
+
const envName = this.config.provider === "tavily" ? "TAVILY_API_KEY" : "SERPAPI_API_KEY";
|
|
4130
|
+
throw new Error(
|
|
4131
|
+
`WebSearchToolkit: No API key provided. Set ${envName} env var or pass apiKey in config.`
|
|
4132
|
+
);
|
|
4133
|
+
}
|
|
4134
|
+
return envKey;
|
|
4135
|
+
}
|
|
4136
|
+
getTools() {
|
|
4137
|
+
const self = this;
|
|
4138
|
+
return [
|
|
4139
|
+
{
|
|
4140
|
+
name: "web_search",
|
|
4141
|
+
description: "Search the web for current information. Returns titles, URLs, and snippets from search results.",
|
|
4142
|
+
parameters: z3.object({
|
|
4143
|
+
query: z3.string().describe("The search query"),
|
|
4144
|
+
maxResults: z3.number().optional().describe("Maximum number of results (default 5)")
|
|
4145
|
+
}),
|
|
4146
|
+
execute: async (args, _ctx) => {
|
|
4147
|
+
const query = args.query;
|
|
4148
|
+
const max = args.maxResults ?? self.config.maxResults ?? 5;
|
|
4149
|
+
if (self.config.provider === "tavily") {
|
|
4150
|
+
return self.searchTavily(query, max);
|
|
4151
|
+
}
|
|
4152
|
+
return self.searchSerpApi(query, max);
|
|
4153
|
+
}
|
|
4154
|
+
}
|
|
4155
|
+
];
|
|
4156
|
+
}
|
|
4157
|
+
async searchTavily(query, maxResults) {
|
|
4158
|
+
const apiKey = this.getApiKey();
|
|
4159
|
+
const res = await fetch("https://api.tavily.com/search", {
|
|
4160
|
+
method: "POST",
|
|
4161
|
+
headers: { "Content-Type": "application/json" },
|
|
4162
|
+
body: JSON.stringify({
|
|
4163
|
+
api_key: apiKey,
|
|
4164
|
+
query,
|
|
4165
|
+
max_results: maxResults,
|
|
4166
|
+
include_answer: true
|
|
4167
|
+
})
|
|
4168
|
+
});
|
|
4169
|
+
if (!res.ok) {
|
|
4170
|
+
throw new Error(`Tavily search failed: ${res.status} ${res.statusText}`);
|
|
4171
|
+
}
|
|
4172
|
+
const data = await res.json();
|
|
4173
|
+
const results = [];
|
|
4174
|
+
if (data.answer) {
|
|
4175
|
+
results.push(`Answer: ${data.answer}
|
|
4176
|
+
`);
|
|
4177
|
+
}
|
|
4178
|
+
for (const r of data.results ?? []) {
|
|
4179
|
+
results.push(`Title: ${r.title}
|
|
4180
|
+
URL: ${r.url}
|
|
4181
|
+
Snippet: ${r.content}
|
|
4182
|
+
`);
|
|
4183
|
+
}
|
|
4184
|
+
return results.join("\n---\n") || "No results found.";
|
|
4185
|
+
}
|
|
4186
|
+
async searchSerpApi(query, maxResults) {
|
|
4187
|
+
const apiKey = this.getApiKey();
|
|
4188
|
+
const params = new URLSearchParams({
|
|
4189
|
+
q: query,
|
|
4190
|
+
api_key: apiKey,
|
|
4191
|
+
engine: "google",
|
|
4192
|
+
num: String(maxResults)
|
|
4193
|
+
});
|
|
4194
|
+
const res = await fetch(
|
|
4195
|
+
`https://serpapi.com/search.json?${params.toString()}`
|
|
4196
|
+
);
|
|
4197
|
+
if (!res.ok) {
|
|
4198
|
+
throw new Error(
|
|
4199
|
+
`SerpAPI search failed: ${res.status} ${res.statusText}`
|
|
4200
|
+
);
|
|
4201
|
+
}
|
|
4202
|
+
const data = await res.json();
|
|
4203
|
+
const results = [];
|
|
4204
|
+
if (data.answer_box?.answer) {
|
|
4205
|
+
results.push(`Answer: ${data.answer_box.answer}
|
|
4206
|
+
`);
|
|
4207
|
+
}
|
|
4208
|
+
for (const r of (data.organic_results ?? []).slice(0, maxResults)) {
|
|
4209
|
+
results.push(
|
|
4210
|
+
`Title: ${r.title}
|
|
4211
|
+
URL: ${r.link}
|
|
4212
|
+
Snippet: ${r.snippet ?? ""}
|
|
4213
|
+
`
|
|
4214
|
+
);
|
|
4215
|
+
}
|
|
4216
|
+
return results.join("\n---\n") || "No results found.";
|
|
4217
|
+
}
|
|
4218
|
+
};
|
|
4219
|
+
|
|
4220
|
+
// src/toolkits/gmail.ts
|
|
4221
|
+
import { z as z4 } from "zod";
|
|
4222
|
+
import { createRequire as createRequire16 } from "module";
|
|
4223
|
+
var _require16 = createRequire16(import.meta.url);
|
|
4224
|
+
var GmailToolkit = class extends Toolkit {
|
|
4225
|
+
name = "gmail";
|
|
4226
|
+
config;
|
|
4227
|
+
gmail = null;
|
|
4228
|
+
constructor(config = {}) {
|
|
4229
|
+
super();
|
|
4230
|
+
this.config = config;
|
|
4231
|
+
}
|
|
4232
|
+
async getGmailClient() {
|
|
4233
|
+
if (this.gmail) return this.gmail;
|
|
4234
|
+
if (this.config.authClient) {
|
|
4235
|
+
const { google: google3 } = _require16("googleapis");
|
|
4236
|
+
this.gmail = google3.gmail({ version: "v1", auth: this.config.authClient });
|
|
4237
|
+
return this.gmail;
|
|
4238
|
+
}
|
|
4239
|
+
const credPath = this.config.credentialsPath ?? process.env.GMAIL_CREDENTIALS_PATH;
|
|
4240
|
+
const tokenPath = this.config.tokenPath ?? process.env.GMAIL_TOKEN_PATH;
|
|
4241
|
+
if (!credPath || !tokenPath) {
|
|
4242
|
+
throw new Error(
|
|
4243
|
+
"GmailToolkit: Provide credentialsPath + tokenPath, or an authClient. Set GMAIL_CREDENTIALS_PATH and GMAIL_TOKEN_PATH env vars, or pass them in config."
|
|
4244
|
+
);
|
|
4245
|
+
}
|
|
4246
|
+
const { google: google2 } = _require16("googleapis");
|
|
4247
|
+
const fs = await import("fs");
|
|
4248
|
+
const creds = JSON.parse(fs.readFileSync(credPath, "utf-8"));
|
|
4249
|
+
const token = JSON.parse(fs.readFileSync(tokenPath, "utf-8"));
|
|
4250
|
+
const { client_id, client_secret, redirect_uris } = creds.installed || creds.web;
|
|
4251
|
+
const oAuth2 = new google2.auth.OAuth2(
|
|
4252
|
+
client_id,
|
|
4253
|
+
client_secret,
|
|
4254
|
+
redirect_uris?.[0]
|
|
4255
|
+
);
|
|
4256
|
+
oAuth2.setCredentials(token);
|
|
4257
|
+
this.gmail = google2.gmail({ version: "v1", auth: oAuth2 });
|
|
4258
|
+
return this.gmail;
|
|
4259
|
+
}
|
|
4260
|
+
getTools() {
|
|
4261
|
+
const self = this;
|
|
4262
|
+
return [
|
|
4263
|
+
{
|
|
4264
|
+
name: "gmail_send",
|
|
4265
|
+
description: "Send an email via Gmail. Provide recipient, subject, and body.",
|
|
4266
|
+
parameters: z4.object({
|
|
4267
|
+
to: z4.string().describe("Recipient email address"),
|
|
4268
|
+
subject: z4.string().describe("Email subject line"),
|
|
4269
|
+
body: z4.string().describe("Email body (plain text)")
|
|
4270
|
+
}),
|
|
4271
|
+
execute: async (args, _ctx) => {
|
|
4272
|
+
const gmail = await self.getGmailClient();
|
|
4273
|
+
const rawMessage = [
|
|
4274
|
+
`To: ${args.to}`,
|
|
4275
|
+
`Subject: ${args.subject}`,
|
|
4276
|
+
"Content-Type: text/plain; charset=utf-8",
|
|
4277
|
+
"",
|
|
4278
|
+
args.body
|
|
4279
|
+
].join("\n");
|
|
4280
|
+
const encoded = Buffer.from(rawMessage).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
4281
|
+
const res = await gmail.users.messages.send({
|
|
4282
|
+
userId: "me",
|
|
4283
|
+
requestBody: { raw: encoded }
|
|
4284
|
+
});
|
|
4285
|
+
return `Email sent successfully. Message ID: ${res.data.id}`;
|
|
4286
|
+
}
|
|
4287
|
+
},
|
|
4288
|
+
{
|
|
4289
|
+
name: "gmail_search",
|
|
4290
|
+
description: "Search emails in Gmail. Returns subject, from, date, and snippet for matching messages.",
|
|
4291
|
+
parameters: z4.object({
|
|
4292
|
+
query: z4.string().describe(
|
|
4293
|
+
'Gmail search query (e.g. "from:john subject:meeting is:unread")'
|
|
4294
|
+
),
|
|
4295
|
+
maxResults: z4.number().optional().describe("Maximum number of results (default 10)")
|
|
4296
|
+
}),
|
|
4297
|
+
execute: async (args, _ctx) => {
|
|
4298
|
+
const gmail = await self.getGmailClient();
|
|
4299
|
+
const max = args.maxResults ?? 10;
|
|
4300
|
+
const list = await gmail.users.messages.list({
|
|
4301
|
+
userId: "me",
|
|
4302
|
+
q: args.query,
|
|
4303
|
+
maxResults: max
|
|
4304
|
+
});
|
|
4305
|
+
const messages = list.data.messages ?? [];
|
|
4306
|
+
if (messages.length === 0) return "No emails found.";
|
|
4307
|
+
const results = [];
|
|
4308
|
+
for (const msg of messages) {
|
|
4309
|
+
const detail = await gmail.users.messages.get({
|
|
4310
|
+
userId: "me",
|
|
4311
|
+
id: msg.id,
|
|
4312
|
+
format: "metadata",
|
|
4313
|
+
metadataHeaders: ["From", "Subject", "Date"]
|
|
4314
|
+
});
|
|
4315
|
+
const headers = detail.data.payload?.headers ?? [];
|
|
4316
|
+
const getHeader = (name) => headers.find(
|
|
4317
|
+
(h) => h.name.toLowerCase() === name.toLowerCase()
|
|
4318
|
+
)?.value ?? "";
|
|
4319
|
+
results.push(
|
|
4320
|
+
`ID: ${msg.id}
|
|
4321
|
+
From: ${getHeader("From")}
|
|
4322
|
+
Subject: ${getHeader("Subject")}
|
|
4323
|
+
Date: ${getHeader("Date")}
|
|
4324
|
+
Snippet: ${detail.data.snippet ?? ""}`
|
|
4325
|
+
);
|
|
4326
|
+
}
|
|
4327
|
+
return results.join("\n\n---\n\n");
|
|
4328
|
+
}
|
|
4329
|
+
},
|
|
4330
|
+
{
|
|
4331
|
+
name: "gmail_read",
|
|
4332
|
+
description: "Read the full content of an email by its message ID.",
|
|
4333
|
+
parameters: z4.object({
|
|
4334
|
+
messageId: z4.string().describe("The Gmail message ID to read")
|
|
4335
|
+
}),
|
|
4336
|
+
execute: async (args, _ctx) => {
|
|
4337
|
+
const gmail = await self.getGmailClient();
|
|
4338
|
+
const detail = await gmail.users.messages.get({
|
|
4339
|
+
userId: "me",
|
|
4340
|
+
id: args.messageId,
|
|
4341
|
+
format: "full"
|
|
4342
|
+
});
|
|
4343
|
+
const headers = detail.data.payload?.headers ?? [];
|
|
4344
|
+
const getHeader = (name) => headers.find(
|
|
4345
|
+
(h) => h.name.toLowerCase() === name.toLowerCase()
|
|
4346
|
+
)?.value ?? "";
|
|
4347
|
+
let body = "";
|
|
4348
|
+
const payload = detail.data.payload;
|
|
4349
|
+
if (payload?.body?.data) {
|
|
4350
|
+
body = Buffer.from(payload.body.data, "base64").toString("utf-8");
|
|
4351
|
+
} else if (payload?.parts) {
|
|
4352
|
+
const textPart = payload.parts.find(
|
|
4353
|
+
(p) => p.mimeType === "text/plain"
|
|
4354
|
+
);
|
|
4355
|
+
if (textPart?.body?.data) {
|
|
4356
|
+
body = Buffer.from(textPart.body.data, "base64").toString(
|
|
4357
|
+
"utf-8"
|
|
4358
|
+
);
|
|
4359
|
+
} else {
|
|
4360
|
+
const htmlPart = payload.parts.find(
|
|
4361
|
+
(p) => p.mimeType === "text/html"
|
|
4362
|
+
);
|
|
4363
|
+
if (htmlPart?.body?.data) {
|
|
4364
|
+
body = Buffer.from(htmlPart.body.data, "base64").toString(
|
|
4365
|
+
"utf-8"
|
|
4366
|
+
);
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
return `From: ${getHeader("From")}
|
|
4371
|
+
To: ${getHeader("To")}
|
|
4372
|
+
Subject: ${getHeader("Subject")}
|
|
4373
|
+
Date: ${getHeader("Date")}
|
|
4374
|
+
|
|
4375
|
+
${body || "(no body)"}`;
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
];
|
|
4379
|
+
}
|
|
4380
|
+
};
|
|
4381
|
+
|
|
4382
|
+
// src/toolkits/whatsapp.ts
|
|
4383
|
+
import { z as z5 } from "zod";
|
|
4384
|
+
var WhatsAppToolkit = class extends Toolkit {
|
|
4385
|
+
name = "whatsapp";
|
|
4386
|
+
accessToken;
|
|
4387
|
+
phoneNumberId;
|
|
4388
|
+
version;
|
|
4389
|
+
recipientWaid;
|
|
4390
|
+
constructor(config = {}) {
|
|
4391
|
+
super();
|
|
4392
|
+
this.accessToken = config.accessToken ?? process.env.WHATSAPP_ACCESS_TOKEN ?? "";
|
|
4393
|
+
this.phoneNumberId = config.phoneNumberId ?? process.env.WHATSAPP_PHONE_NUMBER_ID ?? "";
|
|
4394
|
+
this.version = config.version ?? process.env.WHATSAPP_VERSION ?? "v22.0";
|
|
4395
|
+
this.recipientWaid = config.recipientWaid ?? process.env.WHATSAPP_RECIPIENT_WAID;
|
|
4396
|
+
}
|
|
4397
|
+
getBaseUrl() {
|
|
4398
|
+
return `https://graph.facebook.com/${this.version}/${this.phoneNumberId}/messages`;
|
|
4399
|
+
}
|
|
4400
|
+
validate() {
|
|
4401
|
+
if (!this.accessToken) {
|
|
4402
|
+
throw new Error(
|
|
4403
|
+
"WhatsAppToolkit: accessToken is required. Set WHATSAPP_ACCESS_TOKEN env var or pass in config."
|
|
4404
|
+
);
|
|
4405
|
+
}
|
|
4406
|
+
if (!this.phoneNumberId) {
|
|
4407
|
+
throw new Error(
|
|
4408
|
+
"WhatsAppToolkit: phoneNumberId is required. Set WHATSAPP_PHONE_NUMBER_ID env var or pass in config."
|
|
4409
|
+
);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
resolveRecipient(recipient) {
|
|
4413
|
+
const r = recipient ?? this.recipientWaid;
|
|
4414
|
+
if (!r) {
|
|
4415
|
+
throw new Error(
|
|
4416
|
+
"WhatsAppToolkit: recipient is required. Provide it in the tool call or set WHATSAPP_RECIPIENT_WAID env var."
|
|
4417
|
+
);
|
|
4418
|
+
}
|
|
4419
|
+
return r.replace(/[^0-9]/g, "");
|
|
4420
|
+
}
|
|
4421
|
+
getTools() {
|
|
4422
|
+
const self = this;
|
|
4423
|
+
return [
|
|
4424
|
+
{
|
|
4425
|
+
name: "whatsapp_send_text",
|
|
4426
|
+
description: "Send a text message to a WhatsApp user via WhatsApp Business Cloud API.",
|
|
4427
|
+
parameters: z5.object({
|
|
4428
|
+
text: z5.string().describe("The text message to send"),
|
|
4429
|
+
recipient: z5.string().optional().describe(
|
|
4430
|
+
"Recipient WhatsApp number with country code (e.g. 919876543210). Uses default if omitted."
|
|
4431
|
+
),
|
|
4432
|
+
previewUrl: z5.boolean().optional().describe("Enable URL previews in the message (default false)")
|
|
4433
|
+
}),
|
|
4434
|
+
execute: async (args, _ctx) => {
|
|
4435
|
+
self.validate();
|
|
4436
|
+
const recipient = self.resolveRecipient(args.recipient);
|
|
4437
|
+
const res = await fetch(self.getBaseUrl(), {
|
|
4438
|
+
method: "POST",
|
|
4439
|
+
headers: {
|
|
4440
|
+
Authorization: `Bearer ${self.accessToken}`,
|
|
4441
|
+
"Content-Type": "application/json"
|
|
4442
|
+
},
|
|
4443
|
+
body: JSON.stringify({
|
|
4444
|
+
messaging_product: "whatsapp",
|
|
4445
|
+
recipient_type: "individual",
|
|
4446
|
+
to: recipient,
|
|
4447
|
+
type: "text",
|
|
4448
|
+
text: {
|
|
4449
|
+
preview_url: args.previewUrl ?? false,
|
|
4450
|
+
body: args.text
|
|
4451
|
+
}
|
|
4452
|
+
})
|
|
4453
|
+
});
|
|
4454
|
+
if (!res.ok) {
|
|
4455
|
+
const err = await res.text();
|
|
4456
|
+
throw new Error(
|
|
4457
|
+
`WhatsApp send failed: ${res.status} ${err}`
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
const data = await res.json();
|
|
4461
|
+
const msgId = data.messages?.[0]?.id ?? "unknown";
|
|
4462
|
+
return `Message sent successfully to ${recipient}. Message ID: ${msgId}`;
|
|
4463
|
+
}
|
|
4464
|
+
},
|
|
4465
|
+
{
|
|
4466
|
+
name: "whatsapp_send_template",
|
|
4467
|
+
description: "Send a template message to a WhatsApp user. Required for first-time outreach (24-hour messaging window).",
|
|
4468
|
+
parameters: z5.object({
|
|
4469
|
+
templateName: z5.string().describe(
|
|
4470
|
+
'The pre-approved template name (e.g. "hello_world")'
|
|
4471
|
+
),
|
|
4472
|
+
recipient: z5.string().optional().describe(
|
|
4473
|
+
"Recipient WhatsApp number with country code. Uses default if omitted."
|
|
4474
|
+
),
|
|
4475
|
+
languageCode: z5.string().optional().describe('Template language code (default "en_US")'),
|
|
4476
|
+
components: z5.array(z5.record(z5.any())).optional().describe(
|
|
4477
|
+
"Template components for dynamic content (header, body, button parameters)"
|
|
4478
|
+
)
|
|
4479
|
+
}),
|
|
4480
|
+
execute: async (args, _ctx) => {
|
|
4481
|
+
self.validate();
|
|
4482
|
+
const recipient = self.resolveRecipient(args.recipient);
|
|
4483
|
+
const langCode = args.languageCode ?? "en_US";
|
|
4484
|
+
const template = {
|
|
4485
|
+
name: args.templateName,
|
|
4486
|
+
language: { code: langCode }
|
|
4487
|
+
};
|
|
4488
|
+
if (args.components) {
|
|
4489
|
+
template.components = args.components;
|
|
4490
|
+
}
|
|
4491
|
+
const res = await fetch(self.getBaseUrl(), {
|
|
4492
|
+
method: "POST",
|
|
4493
|
+
headers: {
|
|
4494
|
+
Authorization: `Bearer ${self.accessToken}`,
|
|
4495
|
+
"Content-Type": "application/json"
|
|
4496
|
+
},
|
|
4497
|
+
body: JSON.stringify({
|
|
4498
|
+
messaging_product: "whatsapp",
|
|
4499
|
+
recipient_type: "individual",
|
|
4500
|
+
to: recipient,
|
|
4501
|
+
type: "template",
|
|
4502
|
+
template
|
|
4503
|
+
})
|
|
4504
|
+
});
|
|
4505
|
+
if (!res.ok) {
|
|
4506
|
+
const err = await res.text();
|
|
4507
|
+
throw new Error(
|
|
4508
|
+
`WhatsApp template send failed: ${res.status} ${err}`
|
|
4509
|
+
);
|
|
4510
|
+
}
|
|
4511
|
+
const data = await res.json();
|
|
4512
|
+
const msgId = data.messages?.[0]?.id ?? "unknown";
|
|
4513
|
+
return `Template message "${args.templateName}" sent to ${recipient}. Message ID: ${msgId}`;
|
|
4514
|
+
}
|
|
4515
|
+
}
|
|
4516
|
+
];
|
|
4517
|
+
}
|
|
4518
|
+
};
|
|
4519
|
+
|
|
4520
|
+
// src/toolkits/hackernews.ts
|
|
4521
|
+
import { z as z6 } from "zod";
|
|
4522
|
+
var HackerNewsToolkit = class extends Toolkit {
|
|
4523
|
+
name = "hackernews";
|
|
4524
|
+
config;
|
|
4525
|
+
constructor(config = {}) {
|
|
4526
|
+
super();
|
|
4527
|
+
this.config = {
|
|
4528
|
+
enableGetTopStories: config.enableGetTopStories ?? true,
|
|
4529
|
+
enableGetUserDetails: config.enableGetUserDetails ?? true
|
|
4530
|
+
};
|
|
4531
|
+
}
|
|
4532
|
+
getTools() {
|
|
4533
|
+
const tools = [];
|
|
4534
|
+
if (this.config.enableGetTopStories) {
|
|
4535
|
+
tools.push({
|
|
4536
|
+
name: "hackernews_top_stories",
|
|
4537
|
+
description: "Get the top stories from Hacker News. Returns title, URL, score, author, and comment count.",
|
|
4538
|
+
parameters: z6.object({
|
|
4539
|
+
numStories: z6.number().optional().describe("Number of top stories to fetch (default 10, max 30)")
|
|
4540
|
+
}),
|
|
4541
|
+
execute: async (args, _ctx) => {
|
|
4542
|
+
const num = Math.min(args.numStories ?? 10, 30);
|
|
4543
|
+
const idsRes = await fetch(
|
|
4544
|
+
"https://hacker-news.firebaseio.com/v0/topstories.json"
|
|
4545
|
+
);
|
|
4546
|
+
if (!idsRes.ok) throw new Error(`HN API failed: ${idsRes.status}`);
|
|
4547
|
+
const ids = await idsRes.json();
|
|
4548
|
+
const stories = await Promise.all(
|
|
4549
|
+
ids.slice(0, num).map(async (id) => {
|
|
4550
|
+
const res = await fetch(
|
|
4551
|
+
`https://hacker-news.firebaseio.com/v0/item/${id}.json`
|
|
4552
|
+
);
|
|
4553
|
+
return res.json();
|
|
4554
|
+
})
|
|
4555
|
+
);
|
|
4556
|
+
return stories.map(
|
|
4557
|
+
(s, i) => `${i + 1}. ${s.title}
|
|
4558
|
+
URL: ${s.url ?? `https://news.ycombinator.com/item?id=${s.id}`}
|
|
4559
|
+
Score: ${s.score} | By: ${s.by} | Comments: ${s.descendants ?? 0}`
|
|
4560
|
+
).join("\n\n");
|
|
4561
|
+
}
|
|
4562
|
+
});
|
|
4563
|
+
}
|
|
4564
|
+
if (this.config.enableGetUserDetails) {
|
|
4565
|
+
tools.push({
|
|
4566
|
+
name: "hackernews_user",
|
|
4567
|
+
description: "Get details about a Hacker News user by username. Returns karma, about, and account creation date.",
|
|
4568
|
+
parameters: z6.object({
|
|
4569
|
+
username: z6.string().describe("The HN username to look up")
|
|
4570
|
+
}),
|
|
4571
|
+
execute: async (args, _ctx) => {
|
|
4572
|
+
const username = args.username;
|
|
4573
|
+
const res = await fetch(
|
|
4574
|
+
`https://hacker-news.firebaseio.com/v0/user/${username}.json`
|
|
4575
|
+
);
|
|
4576
|
+
if (!res.ok)
|
|
4577
|
+
throw new Error(`HN user API failed: ${res.status}`);
|
|
4578
|
+
const user = await res.json();
|
|
4579
|
+
if (!user) return `User "${username}" not found.`;
|
|
4580
|
+
const created = new Date(user.created * 1e3).toISOString().split("T")[0];
|
|
4581
|
+
return [
|
|
4582
|
+
`Username: ${user.id}`,
|
|
4583
|
+
`Karma: ${user.karma}`,
|
|
4584
|
+
`Created: ${created}`,
|
|
4585
|
+
user.about ? `About: ${user.about}` : null,
|
|
4586
|
+
`Submitted: ${user.submitted?.length ?? 0} items`
|
|
4587
|
+
].filter(Boolean).join("\n");
|
|
4588
|
+
}
|
|
4589
|
+
});
|
|
4590
|
+
}
|
|
4591
|
+
return tools;
|
|
4592
|
+
}
|
|
4593
|
+
};
|
|
3816
4594
|
export {
|
|
3817
4595
|
A2ARemoteAgent,
|
|
3818
4596
|
Agent,
|
|
3819
4597
|
AnthropicProvider,
|
|
3820
4598
|
BaseVectorStore,
|
|
3821
4599
|
EventBus,
|
|
4600
|
+
GmailToolkit,
|
|
3822
4601
|
GoogleEmbedding,
|
|
3823
4602
|
GoogleProvider,
|
|
4603
|
+
HackerNewsToolkit,
|
|
3824
4604
|
InMemoryStorage,
|
|
3825
4605
|
InMemoryVectorStore,
|
|
3826
4606
|
KnowledgeBase,
|
|
@@ -3843,6 +4623,10 @@ export {
|
|
|
3843
4623
|
Team,
|
|
3844
4624
|
TeamMode,
|
|
3845
4625
|
ToolExecutor,
|
|
4626
|
+
Toolkit,
|
|
4627
|
+
VertexAIProvider,
|
|
4628
|
+
WebSearchToolkit,
|
|
4629
|
+
WhatsAppToolkit,
|
|
3846
4630
|
Workflow,
|
|
3847
4631
|
anthropic,
|
|
3848
4632
|
defineTool,
|
|
@@ -3851,5 +4635,6 @@ export {
|
|
|
3851
4635
|
isMultiModal,
|
|
3852
4636
|
ollama,
|
|
3853
4637
|
openai,
|
|
3854
|
-
registry
|
|
4638
|
+
registry,
|
|
4639
|
+
vertex
|
|
3855
4640
|
};
|