@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.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 createRequire7 } from "module";
2431
- var _require7 = createRequire7(import.meta.url);
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 = _require7("better-sqlite3");
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 createRequire8 } from "module";
2486
- var _require8 = createRequire8(import.meta.url);
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 } = _require8("pg");
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 createRequire9 } from "module";
2553
- var _require9 = createRequire9(import.meta.url);
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 } = _require9("mongodb");
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 createRequire10 } from "module";
2721
- var _require10 = createRequire10(import.meta.url);
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 } = _require10("pg");
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 createRequire11 } from "module";
3144
+ import { createRequire as createRequire12 } from "module";
2850
3145
  import { createHash } from "crypto";
2851
- var _require11 = createRequire11(import.meta.url);
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 } = _require11("@qdrant/js-client-rest");
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 createRequire12 } from "module";
3010
- var _require12 = createRequire12(import.meta.url);
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 } = _require12("mongodb");
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 createRequire13 } from "module";
3194
- var _require13 = createRequire13(import.meta.url);
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 = _require13("openai");
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 createRequire14 } from "module";
3240
- var _require14 = createRequire14(import.meta.url);
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 } = _require14("@google/genai");
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: z3 } = await import("zod");
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, z3);
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, z3) {
3825
+ jsonSchemaToZod(schema, z7) {
3531
3826
  if (!schema || !schema.properties) {
3532
- return z3.object({}).passthrough();
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 = z3.string();
3541
- if (prop.enum) field = z3.enum(prop.enum);
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 = z3.number();
3840
+ field = z7.number();
3546
3841
  break;
3547
3842
  case "boolean":
3548
- field = z3.boolean();
3843
+ field = z7.boolean();
3549
3844
  break;
3550
3845
  case "array":
3551
- field = z3.array(z3.any());
3846
+ field = z7.array(z7.any());
3552
3847
  break;
3553
3848
  case "object":
3554
- field = z3.record(z3.any());
3849
+ field = z7.record(z7.any());
3555
3850
  break;
3556
3851
  default:
3557
- field = z3.any();
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 z3.object(shape);
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
  };