@iqai/adk 0.8.1 → 0.8.5

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.mjs CHANGED
@@ -1342,12 +1342,21 @@ var InvocationContext = class _InvocationContext {
1342
1342
  * The current session of this invocation context. Readonly.
1343
1343
  */
1344
1344
  session;
1345
+ /**
1346
+ * Shared flags container so that child/parent contexts stay in sync.
1347
+ */
1348
+ _invocationFlags;
1345
1349
  /**
1346
1350
  * Whether to end this invocation.
1347
1351
  *
1348
1352
  * Set to True in callbacks or tools to terminate this invocation.
1349
1353
  */
1350
- endInvocation = false;
1354
+ get endInvocation() {
1355
+ return this._invocationFlags.endInvocation;
1356
+ }
1357
+ set endInvocation(value) {
1358
+ this._invocationFlags.endInvocation = value;
1359
+ }
1351
1360
  /**
1352
1361
  * The queue to receive live requests.
1353
1362
  */
@@ -1388,7 +1397,9 @@ var InvocationContext = class _InvocationContext {
1388
1397
  this.agent = options.agent;
1389
1398
  this.userContent = options.userContent;
1390
1399
  this.session = options.session;
1391
- this.endInvocation = options.endInvocation || false;
1400
+ this._invocationFlags = options.invocationFlags ?? {
1401
+ endInvocation: options.endInvocation || false
1402
+ };
1392
1403
  this.liveRequestQueue = options.liveRequestQueue;
1393
1404
  this.activeStreamingTools = options.activeStreamingTools;
1394
1405
  this.transcriptionCache = options.transcriptionCache;
@@ -1447,6 +1458,12 @@ var InvocationContext = class _InvocationContext {
1447
1458
  getSpanCounters() {
1448
1459
  return this._spanCounters;
1449
1460
  }
1461
+ /**
1462
+ * Exposes shared invocation flags for child contexts.
1463
+ */
1464
+ getInvocationFlags() {
1465
+ return this._invocationFlags;
1466
+ }
1450
1467
  /**
1451
1468
  * Creates a child invocation context for a sub-agent
1452
1469
  */
@@ -1465,7 +1482,7 @@ var InvocationContext = class _InvocationContext {
1465
1482
  // Update to the new agent
1466
1483
  userContent: this.userContent,
1467
1484
  session: this.session,
1468
- endInvocation: this.endInvocation,
1485
+ invocationFlags: this._invocationFlags,
1469
1486
  liveRequestQueue: this.liveRequestQueue,
1470
1487
  activeStreamingTools: this.activeStreamingTools,
1471
1488
  transcriptionCache: this.transcriptionCache,
@@ -3694,15 +3711,10 @@ var VectorStorageProvider = class {
3694
3711
  this.memoryCache.delete(id);
3695
3712
  }
3696
3713
  } else {
3697
- const idsToDelete = [];
3714
+ const vectorFilter = this.buildDeleteFilter(filter);
3715
+ deleted = await this.vectorStore.delete({ filter: vectorFilter });
3698
3716
  for (const [id, record] of this.memoryCache.entries()) {
3699
3717
  if (this.matchesFilter(record, filter)) {
3700
- idsToDelete.push(id);
3701
- }
3702
- }
3703
- if (idsToDelete.length > 0) {
3704
- deleted = await this.vectorStore.delete({ ids: idsToDelete });
3705
- for (const id of idsToDelete) {
3706
3718
  this.memoryCache.delete(id);
3707
3719
  }
3708
3720
  }
@@ -3713,6 +3725,10 @@ var VectorStorageProvider = class {
3713
3725
  * Count memories matching filter.
3714
3726
  */
3715
3727
  async count(filter) {
3728
+ if (this.vectorStore.count) {
3729
+ const vectorFilter = this.buildDeleteFilter(filter);
3730
+ return this.vectorStore.count(vectorFilter);
3731
+ }
3716
3732
  let count = 0;
3717
3733
  for (const record of this.memoryCache.values()) {
3718
3734
  if (this.matchesFilter(record, filter)) {
@@ -3844,15 +3860,34 @@ var VectorStorageProvider = class {
3844
3860
  }
3845
3861
  return filter;
3846
3862
  }
3863
+ /**
3864
+ * Build filter object for vector store delete/count operations.
3865
+ */
3866
+ buildDeleteFilter(filter) {
3867
+ const vectorFilter = {};
3868
+ if (filter.userId !== void 0) vectorFilter.userId = filter.userId;
3869
+ if (filter.appName !== void 0) vectorFilter.appName = filter.appName;
3870
+ if (filter.sessionId !== void 0)
3871
+ vectorFilter.sessionId = filter.sessionId;
3872
+ if (filter.before !== void 0) vectorFilter.before = filter.before;
3873
+ if (filter.after !== void 0) vectorFilter.after = filter.after;
3874
+ if (this.namespace) vectorFilter.namespace = this.namespace;
3875
+ return vectorFilter;
3876
+ }
3847
3877
  /**
3848
3878
  * Check if a record matches the given filter.
3849
3879
  */
3850
3880
  matchesFilter(record, filter) {
3851
- if (filter.userId && record.userId !== filter.userId) return false;
3852
- if (filter.appName && record.appName !== filter.appName) return false;
3853
- if (filter.sessionId && record.sessionId !== filter.sessionId) return false;
3854
- if (filter.before && record.timestamp > filter.before) return false;
3855
- if (filter.after && record.timestamp < filter.after) return false;
3881
+ if (filter.userId !== void 0 && record.userId !== filter.userId)
3882
+ return false;
3883
+ if (filter.appName !== void 0 && record.appName !== filter.appName)
3884
+ return false;
3885
+ if (filter.sessionId !== void 0 && record.sessionId !== filter.sessionId)
3886
+ return false;
3887
+ if (filter.before !== void 0 && record.timestamp > filter.before)
3888
+ return false;
3889
+ if (filter.after !== void 0 && record.timestamp < filter.after)
3890
+ return false;
3856
3891
  return true;
3857
3892
  }
3858
3893
  /**
@@ -4059,11 +4094,12 @@ var LlmSummaryProvider = class {
4059
4094
  }
4060
4095
  const baseUrl = this.baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
4061
4096
  const response = await fetch(
4062
- `${baseUrl}/models/${this.model}:generateContent?key=${apiKey}`,
4097
+ `${baseUrl}/models/${this.model}:generateContent`,
4063
4098
  {
4064
4099
  method: "POST",
4065
4100
  headers: {
4066
- "Content-Type": "application/json"
4101
+ "Content-Type": "application/json",
4102
+ "x-goog-api-key": apiKey
4067
4103
  },
4068
4104
  body: JSON.stringify({
4069
4105
  contents: [{ parts: [{ text: prompt }] }],
@@ -4444,7 +4480,7 @@ var OPERATIONS = {
4444
4480
  EXECUTE_TOOL: "execute_tool",
4445
4481
  // ============================================
4446
4482
  // ADK-specific operations (framework extensions)
4447
- // These are non-standard but useful for the ADK framework
4483
+ // These are non-standard but useful for the ADK-TS framework
4448
4484
  // ============================================
4449
4485
  TRANSFER_AGENT: "transfer_agent",
4450
4486
  // Multi-agent transfer
@@ -5560,7 +5596,7 @@ var TracingService = class {
5560
5596
  [ADK_ATTRS.INVOCATION_ID]: invocationContext.invocationId,
5561
5597
  [ADK_ATTRS.EVENT_ID]: eventId,
5562
5598
  [ADK_ATTRS.ENVIRONMENT]: getEnvironment() || "",
5563
- // Content attributes (only if capture is enabled) - ADK namespace for backward compat
5599
+ // Content attributes (only if capture is enabled) - ADK-TS namespace for backward compat
5564
5600
  [ADK_ATTRS.LLM_REQUEST]: captureContent ? safeJsonStringify(llmRequestData) : "{}",
5565
5601
  [ADK_ATTRS.LLM_RESPONSE]: captureContent ? safeJsonStringify(llmResponseData) : "{}"
5566
5602
  });
@@ -6259,7 +6295,7 @@ var BaseLlm = class {
6259
6295
  true
6260
6296
  // retry may be recommended for transient model errors
6261
6297
  );
6262
- this.logger.error("\u274C ADK LLM Error:", {
6298
+ this.logger.error("\u274C ADK-TS LLM Error:", {
6263
6299
  model: this.model,
6264
6300
  error: error.message
6265
6301
  });
@@ -7027,7 +7063,7 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7027
7063
  });
7028
7064
  }
7029
7065
  /**
7030
- * Convert ADK LlmRequest to AI SDK CoreMessage format
7066
+ * Convert ADK-TS LlmRequest to AI SDK CoreMessage format
7031
7067
  */
7032
7068
  convertToAiSdkMessages(llmRequest) {
7033
7069
  const messages = [];
@@ -7077,7 +7113,7 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7077
7113
  return transformedSchema;
7078
7114
  }
7079
7115
  /**
7080
- * Convert ADK tools to AI SDK tools format
7116
+ * Convert ADK-TS tools to AI SDK tools format
7081
7117
  */
7082
7118
  convertToAiSdkTools(llmRequest) {
7083
7119
  const tools = {};
@@ -7098,7 +7134,7 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7098
7134
  return tools;
7099
7135
  }
7100
7136
  /**
7101
- * Convert ADK Content to AI SDK CoreMessage
7137
+ * Convert ADK-TS Content to AI SDK CoreMessage
7102
7138
  */
7103
7139
  contentToAiSdkMessage(content) {
7104
7140
  const role = this.mapRole(content.role);
@@ -7200,7 +7236,7 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7200
7236
  return { role: "user", content: contentParts };
7201
7237
  }
7202
7238
  /**
7203
- * Map ADK role to AI SDK role
7239
+ * Map ADK-TS role to AI SDK role
7204
7240
  */
7205
7241
  mapRole(role) {
7206
7242
  switch (role) {
@@ -7214,7 +7250,7 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7214
7250
  }
7215
7251
  }
7216
7252
  /**
7217
- * Map AI SDK finish reason to ADK finish reason
7253
+ * Map AI SDK finish reason to ADK-TS finish reason
7218
7254
  */
7219
7255
  mapFinishReason(finishReason) {
7220
7256
  switch (finishReason) {
@@ -7233,6 +7269,21 @@ var AiSdkLlm = class _AiSdkLlm extends BaseLlm {
7233
7269
  // src/models/anthropic-llm.ts
7234
7270
  init_logger();
7235
7271
  import Anthropic from "@anthropic-ai/sdk";
7272
+
7273
+ // src/models/llm-utils.ts
7274
+ function safeParseToolArgs(json, logger2) {
7275
+ try {
7276
+ return JSON.parse(json || "{}");
7277
+ } catch (error) {
7278
+ logger2.warn("Failed to parse tool call arguments, using empty args", {
7279
+ rawArgs: json,
7280
+ error: String(error)
7281
+ });
7282
+ return {};
7283
+ }
7284
+ }
7285
+
7286
+ // src/models/anthropic-llm.ts
7236
7287
  var DEFAULT_MAX_OUTPUT_TOKENS = 1024;
7237
7288
  var THOUGHT_OPEN_TAGS = [
7238
7289
  "<thinking>",
@@ -7438,7 +7489,7 @@ var AnthropicLlm = class extends BaseLlm {
7438
7489
  functionCall: {
7439
7490
  id: block.id,
7440
7491
  name: block.name,
7441
- args: JSON.parse(block.inputJson || "{}")
7492
+ args: safeParseToolArgs(block.inputJson, this.logger)
7442
7493
  }
7443
7494
  });
7444
7495
  }
@@ -7490,7 +7541,7 @@ var AnthropicLlm = class extends BaseLlm {
7490
7541
  throw new Error(`Live connection is not supported for ${this.model}.`);
7491
7542
  }
7492
7543
  /**
7493
- * Convert Anthropic Message to ADK LlmResponse
7544
+ * Convert Anthropic Message to ADK-TS LlmResponse
7494
7545
  */
7495
7546
  anthropicMessageToLlmResponse(message) {
7496
7547
  this.logger.debug(
@@ -7518,7 +7569,7 @@ var AnthropicLlm = class extends BaseLlm {
7518
7569
  });
7519
7570
  }
7520
7571
  /**
7521
- * Convert ADK Content to Anthropic MessageParam
7572
+ * Convert ADK-TS Content to Anthropic MessageParam
7522
7573
  */
7523
7574
  contentToAnthropicMessage(content) {
7524
7575
  return {
@@ -7529,39 +7580,39 @@ var AnthropicLlm = class extends BaseLlm {
7529
7580
  };
7530
7581
  }
7531
7582
  /**
7532
- * Convert ADK Part to Anthropic content block
7583
+ * Convert ADK-TS Part to Anthropic content block
7533
7584
  */
7534
7585
  partToAnthropicBlock(part) {
7535
7586
  if (part.text) return { type: "text", text: part.text };
7536
- if (part.function_call)
7587
+ if (part.functionCall)
7537
7588
  return {
7538
7589
  type: "tool_use",
7539
- id: part.function_call.id || "",
7540
- name: part.function_call.name,
7541
- input: part.function_call.args || {}
7590
+ id: part.functionCall.id || "",
7591
+ name: part.functionCall.name,
7592
+ input: part.functionCall.args || {}
7542
7593
  };
7543
- if (part.function_response)
7594
+ if (part.functionResponse)
7544
7595
  return {
7545
7596
  type: "tool_result",
7546
- tool_use_id: part.function_response.id || "",
7547
- content: String(part.function_response.response?.result || ""),
7597
+ tool_use_id: part.functionResponse.id || "",
7598
+ content: String(part.functionResponse.response?.result || ""),
7548
7599
  is_error: false
7549
7600
  };
7550
7601
  throw new Error("Unsupported part type for Anthropic conversion");
7551
7602
  }
7552
7603
  /**
7553
- * Convert Anthropic content block to ADK Part
7604
+ * Convert Anthropic content block to ADK-TS Part
7554
7605
  */
7555
7606
  anthropicBlockToPart(block) {
7556
7607
  if (block.type === "text") return { text: block.text };
7557
7608
  if (block.type === "tool_use")
7558
7609
  return {
7559
- function_call: { id: block.id, name: block.name, args: block.input }
7610
+ functionCall: { id: block.id, name: block.name, args: block.input }
7560
7611
  };
7561
7612
  throw new Error("Unsupported Anthropic content block type");
7562
7613
  }
7563
7614
  /**
7564
- * Convert ADK function declaration to Anthropic tool param
7615
+ * Convert ADK-TS function declaration to Anthropic tool param
7565
7616
  */
7566
7617
  functionDeclarationToAnthropicTool(functionDeclaration) {
7567
7618
  const properties = {};
@@ -7581,14 +7632,14 @@ var AnthropicLlm = class extends BaseLlm {
7581
7632
  };
7582
7633
  }
7583
7634
  /**
7584
- * Convert ADK role to Anthropic role format
7635
+ * Convert ADK-TS role to Anthropic role format
7585
7636
  */
7586
7637
  toAnthropicRole(role) {
7587
7638
  if (role === "model" || role === "assistant") return "assistant";
7588
7639
  return "user";
7589
7640
  }
7590
7641
  /**
7591
- * Convert Anthropic stop reason to ADK finish reason
7642
+ * Convert Anthropic stop reason to ADK-TS finish reason
7592
7643
  */
7593
7644
  toAdkFinishReason(anthropicStopReason) {
7594
7645
  if (["end_turn", "stop_sequence", "tool_use"].includes(
@@ -8185,7 +8236,10 @@ var OpenAiLlm = class extends BaseLlm {
8185
8236
  functionCall: {
8186
8237
  id: toolCall.id,
8187
8238
  name: toolCall.function.name,
8188
- args: JSON.parse(toolCall.function.arguments || "{}")
8239
+ args: safeParseToolArgs(
8240
+ toolCall.function.arguments,
8241
+ this.logger
8242
+ )
8189
8243
  }
8190
8244
  });
8191
8245
  }
@@ -8278,7 +8332,7 @@ var OpenAiLlm = class extends BaseLlm {
8278
8332
  functionCall: {
8279
8333
  id: toolCall.id || "",
8280
8334
  name: toolCall.function.name,
8281
- args: JSON.parse(toolCall.function.arguments || "{}")
8335
+ args: safeParseToolArgs(toolCall.function.arguments, this.logger)
8282
8336
  }
8283
8337
  });
8284
8338
  }
@@ -8297,7 +8351,7 @@ var OpenAiLlm = class extends BaseLlm {
8297
8351
  });
8298
8352
  }
8299
8353
  /**
8300
- * Convert OpenAI message to ADK LlmResponse
8354
+ * Convert OpenAI message to ADK-TS LlmResponse
8301
8355
  */
8302
8356
  openAiMessageToLlmResponse(choice, usage) {
8303
8357
  const message = choice.message;
@@ -8312,7 +8366,7 @@ var OpenAiLlm = class extends BaseLlm {
8312
8366
  functionCall: {
8313
8367
  id: toolCall.id,
8314
8368
  name: toolCall.function.name,
8315
- args: JSON.parse(toolCall.function.arguments || "{}")
8369
+ args: safeParseToolArgs(toolCall.function.arguments, this.logger)
8316
8370
  }
8317
8371
  });
8318
8372
  }
@@ -8332,7 +8386,7 @@ var OpenAiLlm = class extends BaseLlm {
8332
8386
  });
8333
8387
  }
8334
8388
  /**
8335
- * Convert ADK Content to OpenAI ChatCompletionMessage
8389
+ * Convert ADK-TS Content to OpenAI ChatCompletionMessage
8336
8390
  */
8337
8391
  contentToOpenAiMessage(content) {
8338
8392
  const role = this.toOpenAiRole(content.role);
@@ -8388,7 +8442,7 @@ var OpenAiLlm = class extends BaseLlm {
8388
8442
  };
8389
8443
  }
8390
8444
  /**
8391
- * Convert ADK Part to OpenAI message content
8445
+ * Convert ADK-TS Part to OpenAI message content
8392
8446
  */
8393
8447
  partToOpenAiContent(part) {
8394
8448
  if (part.text) {
@@ -8445,7 +8499,7 @@ var OpenAiLlm = class extends BaseLlm {
8445
8499
  return transformedSchema;
8446
8500
  }
8447
8501
  /**
8448
- * Convert ADK function declaration to OpenAI tool
8502
+ * Convert ADK-TS function declaration to OpenAI tool
8449
8503
  */
8450
8504
  functionDeclarationToOpenAiTool(functionDeclaration) {
8451
8505
  return {
@@ -8460,7 +8514,7 @@ var OpenAiLlm = class extends BaseLlm {
8460
8514
  };
8461
8515
  }
8462
8516
  /**
8463
- * Convert ADK role to OpenAI role format
8517
+ * Convert ADK-TS role to OpenAI role format
8464
8518
  */
8465
8519
  toOpenAiRole(role) {
8466
8520
  if (role === "model") {
@@ -8472,7 +8526,7 @@ var OpenAiLlm = class extends BaseLlm {
8472
8526
  return "user";
8473
8527
  }
8474
8528
  /**
8475
- * Convert OpenAI finish reason to ADK finish reason
8529
+ * Convert OpenAI finish reason to ADK-TS finish reason
8476
8530
  */
8477
8531
  toAdkFinishReason(openaiFinishReason) {
8478
8532
  switch (openaiFinishReason) {
@@ -8804,7 +8858,7 @@ var ReadonlyContext = class {
8804
8858
  // src/agents/callback-context.ts
8805
8859
  var CallbackContext = class extends ReadonlyContext {
8806
8860
  /**
8807
- * TODO: make this public for Agent Development Kit, but private for users.
8861
+ * TODO: make this public for ADK-TS, but private for users.
8808
8862
  */
8809
8863
  _eventActions;
8810
8864
  _state;
@@ -8880,7 +8934,7 @@ var ToolContext = class extends CallbackContext {
8880
8934
  /**
8881
8935
  * The function call id of the current tool call. This id was
8882
8936
  * returned in the function call event from LLM to identify a function call.
8883
- * If LLM didn't return this id, ADK will assign one to it. This id is used
8937
+ * If LLM didn't return this id, ADK-TS will assign one to it. This id is used
8884
8938
  * to map function call response to the original function call.
8885
8939
  */
8886
8940
  functionCallId;
@@ -9356,7 +9410,7 @@ function mergeParallelFunctionResponseEvents(functionResponseEvents) {
9356
9410
  }
9357
9411
  mergedActions.requestedAuthConfigs = mergedRequestedAuthConfigs;
9358
9412
  const mergedEvent = new Event({
9359
- invocationId: Event.newId(),
9413
+ invocationId: baseEvent.invocationId,
9360
9414
  author: baseEvent.author,
9361
9415
  branch: baseEvent.branch,
9362
9416
  content: { role: "user", parts: mergedParts },
@@ -9408,7 +9462,7 @@ var EnhancedAuthConfig = class {
9408
9462
  rawAuthCredential;
9409
9463
  /**
9410
9464
  * Exchanged auth credential after processing
9411
- * Filled by ADK and client working together
9465
+ * Filled by ADK-TS and client working together
9412
9466
  */
9413
9467
  exchangedAuthCredential;
9414
9468
  /**
@@ -10279,7 +10333,7 @@ var FileOperationsTool = class extends BaseTool {
10279
10333
  async runAsync(args, _context) {
10280
10334
  try {
10281
10335
  const resolvedPath = this.resolvePath(args.filepath);
10282
- this.validatePath(resolvedPath);
10336
+ await this.validatePath(resolvedPath);
10283
10337
  const encoding = args.encoding || "utf8";
10284
10338
  switch (args.operation) {
10285
10339
  case "read":
@@ -10321,15 +10375,38 @@ var FileOperationsTool = class extends BaseTool {
10321
10375
  return path.isAbsolute(filepath) ? filepath : path.resolve(this.basePath, filepath);
10322
10376
  }
10323
10377
  /**
10324
- * Validate that a path is within the base path for security
10378
+ * Validate that a path is within the base path for security.
10379
+ * Resolves symlinks to prevent symlink escape attacks.
10325
10380
  */
10326
- validatePath(filepath) {
10327
- const normalizedPath = path.normalize(filepath);
10328
- const normalizedBasePath = path.normalize(this.basePath);
10329
- if (!normalizedPath.startsWith(normalizedBasePath)) {
10330
- throw new Error(
10331
- `Access denied: Can't access paths outside the base directory`
10332
- );
10381
+ async validatePath(filepath) {
10382
+ const realBasePath = await fs.realpath(this.basePath);
10383
+ const isWithinBase = (p, base) => p === base || p.startsWith(base + path.sep);
10384
+ try {
10385
+ const realPath = await fs.realpath(filepath);
10386
+ if (!isWithinBase(realPath, realBasePath)) {
10387
+ throw new Error(
10388
+ "Access denied: Can't access paths outside the base directory"
10389
+ );
10390
+ }
10391
+ } catch (error) {
10392
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
10393
+ const parentDir = path.dirname(filepath);
10394
+ let realParent;
10395
+ try {
10396
+ realParent = await fs.realpath(parentDir);
10397
+ } catch {
10398
+ throw new Error(
10399
+ "Access denied: Can't access paths outside the base directory"
10400
+ );
10401
+ }
10402
+ if (!isWithinBase(realParent, realBasePath)) {
10403
+ throw new Error(
10404
+ "Access denied: Can't access paths outside the base directory"
10405
+ );
10406
+ }
10407
+ } else {
10408
+ throw error;
10409
+ }
10333
10410
  }
10334
10411
  }
10335
10412
  /**
@@ -10427,7 +10504,7 @@ var FileOperationsTool = class extends BaseTool {
10427
10504
  const results = await Promise.all(
10428
10505
  entries.map(async (entry) => {
10429
10506
  const entryPath = path.join(dirpath, entry.name);
10430
- const stats = await fs.stat(entryPath);
10507
+ const stats = await fs.lstat(entryPath);
10431
10508
  return {
10432
10509
  name: entry.name,
10433
10510
  path: entryPath,
@@ -10669,6 +10746,62 @@ var googleSearchArgsSchema = z2.object({
10669
10746
  // src/tools/common/http-request-tool.ts
10670
10747
  init_base_tool();
10671
10748
  import { Type as Type6 } from "@google/genai";
10749
+
10750
+ // src/tools/utils/url-validation.ts
10751
+ function validateUrlForFetch(urlString) {
10752
+ const url = new URL(urlString);
10753
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
10754
+ throw new Error(
10755
+ `Blocked URL: only http and https protocols are allowed, got ${url.protocol}`
10756
+ );
10757
+ }
10758
+ const hostname = url.hostname.toLowerCase();
10759
+ if (hostname === "localhost" || hostname === "[::1]") {
10760
+ throw new Error("Blocked URL: localhost is not allowed");
10761
+ }
10762
+ const ipv4 = extractIPv4(hostname);
10763
+ if (ipv4 !== null && isPrivateIP(ipv4)) {
10764
+ throw new Error(
10765
+ "Blocked URL: private/internal IP addresses are not allowed"
10766
+ );
10767
+ }
10768
+ if (isPrivateIP(hostname)) {
10769
+ throw new Error(
10770
+ "Blocked URL: private/internal IP addresses are not allowed"
10771
+ );
10772
+ }
10773
+ return url;
10774
+ }
10775
+ function extractIPv4(hostname) {
10776
+ const bare = hostname.replace(/^\[|\]$/g, "");
10777
+ const dottedMatch = bare.match(
10778
+ /^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/i
10779
+ );
10780
+ if (dottedMatch) return dottedMatch[1];
10781
+ const hexMatch = bare.match(/^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i);
10782
+ if (hexMatch) {
10783
+ const high = Number.parseInt(hexMatch[1], 16);
10784
+ const low = Number.parseInt(hexMatch[2], 16);
10785
+ return `${high >> 8 & 255}.${high & 255}.${low >> 8 & 255}.${low & 255}`;
10786
+ }
10787
+ return null;
10788
+ }
10789
+ function isPrivateIP(hostname) {
10790
+ const match = hostname.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
10791
+ if (!match) return false;
10792
+ const [, a, b] = match;
10793
+ const first = Number(a);
10794
+ const second = Number(b);
10795
+ if (first === 0) return true;
10796
+ if (first === 127) return true;
10797
+ if (first === 10) return true;
10798
+ if (first === 172 && second >= 16 && second <= 31) return true;
10799
+ if (first === 192 && second === 168) return true;
10800
+ if (first === 169 && second === 254) return true;
10801
+ return false;
10802
+ }
10803
+
10804
+ // src/tools/common/http-request-tool.ts
10672
10805
  var HttpRequestTool = class extends BaseTool {
10673
10806
  constructor() {
10674
10807
  super({
@@ -10731,7 +10864,7 @@ var HttpRequestTool = class extends BaseTool {
10731
10864
  params,
10732
10865
  timeout = 1e4
10733
10866
  } = args;
10734
- const urlObj = new URL(url);
10867
+ const urlObj = validateUrlForFetch(url);
10735
10868
  if (params) {
10736
10869
  Object.entries(params).forEach(([key, value]) => {
10737
10870
  urlObj.searchParams.append(key, value);
@@ -10745,7 +10878,8 @@ var HttpRequestTool = class extends BaseTool {
10745
10878
  method,
10746
10879
  headers: requestHeaders,
10747
10880
  body,
10748
- signal: AbortSignal.timeout(timeout)
10881
+ signal: AbortSignal.timeout(timeout),
10882
+ redirect: "manual"
10749
10883
  };
10750
10884
  const response = await fetch(urlObj.toString(), options);
10751
10885
  const responseHeaders = {};
@@ -11553,16 +11687,16 @@ var BashTool = class _BashTool extends BaseTool {
11553
11687
  // filesystem formatting
11554
11688
  /dd\s+if=/,
11555
11689
  // disk operations
11556
- /wget.*\|\s*sh/,
11690
+ /wget.*\|\s*(sh|bash)/,
11557
11691
  // download and execute
11558
- /curl.*\|\s*bash/,
11692
+ /curl.*\|\s*(bash|sh)/,
11559
11693
  // download and execute
11560
11694
  /eval\s+['"`]/,
11561
11695
  // eval with strings
11562
- /base64.*\|\s*sh/,
11696
+ /base64.*\|\s*(sh|bash)/,
11563
11697
  // decode and execute
11564
- /nc\s+-.*e/,
11565
- // netcat reverse shell
11698
+ /(nc|ncat|netcat)\s+-.*e/,
11699
+ // netcat reverse shell (nc, ncat, netcat)
11566
11700
  /\/proc\/.*\/mem/,
11567
11701
  // memory access
11568
11702
  /iptables/,
@@ -11573,8 +11707,18 @@ var BashTool = class _BashTool extends BaseTool {
11573
11707
  // ownership changes
11574
11708
  /sudo/,
11575
11709
  // privilege escalation
11576
- /su\s+/
11710
+ /su\s+/,
11577
11711
  // user switching
11712
+ /python[23]?(\.\d+)?\s+-c\s/,
11713
+ // python interpreter execution (python, python3, python3.11, etc.)
11714
+ /node\s+(-e|--eval)[\s=]/,
11715
+ // node interpreter execution (-e and --eval)
11716
+ /perl\s+-e\s/,
11717
+ // perl interpreter execution
11718
+ /ruby\s+-e\s/,
11719
+ // ruby interpreter execution
11720
+ /php\s+-r\s/
11721
+ // php interpreter execution
11578
11722
  ];
11579
11723
  // Special characters that enable command chaining/injection
11580
11724
  static DANGEROUS_CHARS = /[;&|`$()<>]/;
@@ -12352,11 +12496,16 @@ var WebFetchTool = class extends BaseTool {
12352
12496
  }
12353
12497
  async runAsync(args, _context) {
12354
12498
  try {
12499
+ validateUrlForFetch(args.url);
12355
12500
  const response = await axios2.get(args.url, {
12356
12501
  timeout: 3e4,
12357
12502
  maxRedirects: 5,
12358
12503
  headers: {
12359
12504
  "User-Agent": "Mozilla/5.0 (compatible; ADK/1.0; +http://example.com)"
12505
+ },
12506
+ beforeRedirect: (options) => {
12507
+ const redirectUrl = typeof options.href === "string" ? options.href : `${options.protocol}//${options.hostname}${options.path}`;
12508
+ validateUrlForFetch(redirectUrl);
12360
12509
  }
12361
12510
  });
12362
12511
  const contentType = response.headers["content-type"] || "";
@@ -12769,7 +12918,7 @@ var McpSamplingHandler = class {
12769
12918
  "INVALID_REQUEST_ERROR" /* INVALID_REQUEST_ERROR */
12770
12919
  );
12771
12920
  }
12772
- this.logger.debug("Converting MCP request to ADK format");
12921
+ this.logger.debug("Converting MCP request to ADK-TS format");
12773
12922
  const adkContents = this.convertMcpMessagesToADK(
12774
12923
  mcpParams.messages,
12775
12924
  mcpParams.systemPrompt
@@ -12783,9 +12932,9 @@ var McpSamplingHandler = class {
12783
12932
  maxOutputTokens: mcpParams.maxTokens
12784
12933
  }
12785
12934
  });
12786
- this.logger.debug("Calling ADK sampling handler");
12935
+ this.logger.debug("Calling ADK-TS sampling handler");
12787
12936
  const adkResponse = await this.samplingHandler(adkRequest);
12788
- this.logger.debug("Converting ADK response to MCP format");
12937
+ this.logger.debug("Converting ADK-TS response to MCP format");
12789
12938
  const mcpResponse = this.convertADKResponseToMcp(
12790
12939
  adkResponse,
12791
12940
  requestModel
@@ -12815,7 +12964,7 @@ var McpSamplingHandler = class {
12815
12964
  }
12816
12965
  }
12817
12966
  /**
12818
- * Convert MCP messages to ADK Content format
12967
+ * Convert MCP messages to ADK-TS Content format
12819
12968
  */
12820
12969
  convertMcpMessagesToADK(mcpMessages, systemPrompt) {
12821
12970
  const contents = [];
@@ -12833,7 +12982,7 @@ var McpSamplingHandler = class {
12833
12982
  return contents;
12834
12983
  }
12835
12984
  /**
12836
- * Convert a single MCP message to ADK Content format
12985
+ * Convert a single MCP message to ADK-TS Content format
12837
12986
  */
12838
12987
  convertSingleMcpMessageToADK(mcpMessage) {
12839
12988
  const adkRole = mcpMessage.role === "assistant" ? "model" : "user";
@@ -12848,7 +12997,7 @@ var McpSamplingHandler = class {
12848
12997
  return adkContent;
12849
12998
  }
12850
12999
  /**
12851
- * Convert MCP message content to ADK parts format
13000
+ * Convert MCP message content to ADK-TS parts format
12852
13001
  */
12853
13002
  convertMcpContentToADKParts(mcpContent) {
12854
13003
  const safeText = (value) => typeof value === "string" ? value : "";
@@ -12901,7 +13050,7 @@ var McpSamplingHandler = class {
12901
13050
  }
12902
13051
  }
12903
13052
  /**
12904
- * Convert ADK response to MCP response format
13053
+ * Convert ADK-TS response to MCP response format
12905
13054
  */
12906
13055
  convertADKResponseToMcp(adkResponse, model) {
12907
13056
  let responseText = "";
@@ -12922,7 +13071,7 @@ var McpSamplingHandler = class {
12922
13071
  model,
12923
13072
  // Use the model from the request
12924
13073
  role: "assistant",
12925
- // ADK responses are always from assistant
13074
+ // ADK-TS responses are always from assistant
12926
13075
  content: {
12927
13076
  type: "text",
12928
13077
  text: responseText
@@ -12932,11 +13081,11 @@ var McpSamplingHandler = class {
12932
13081
  return mcpResponse;
12933
13082
  }
12934
13083
  /**
12935
- * Update the ADK handler
13084
+ * Update the ADK-TS handler
12936
13085
  */
12937
13086
  updateHandler(handler) {
12938
13087
  this.samplingHandler = handler;
12939
- this.logger.debug("ADK sampling handler updated");
13088
+ this.logger.debug("ADK-TS sampling handler updated");
12940
13089
  }
12941
13090
  };
12942
13091
  function createSamplingHandler(handler) {
@@ -13209,13 +13358,13 @@ var McpClientService = class {
13209
13358
  }
13210
13359
  }
13211
13360
  /**
13212
- * Set a new ADK sampling handler
13361
+ * Set a new ADK-TS sampling handler
13213
13362
  */
13214
13363
  setSamplingHandler(handler) {
13215
13364
  this.mcpSamplingHandler = new McpSamplingHandler(handler);
13216
13365
  if (this.client) {
13217
13366
  this.setupSamplingHandler(this.client).catch((error) => {
13218
- this.logger.error("Failed to update ADK sampling handler:", error);
13367
+ this.logger.error("Failed to update ADK-TS sampling handler:", error);
13219
13368
  });
13220
13369
  }
13221
13370
  }
@@ -13798,6 +13947,9 @@ var McpToolset = class {
13798
13947
  }
13799
13948
  return true;
13800
13949
  }
13950
+ isCacheEnabled() {
13951
+ return this.config.cacheConfig?.enabled !== false;
13952
+ }
13801
13953
  /**
13802
13954
  * Initializes the client service and establishes a connection.
13803
13955
  */
@@ -13816,9 +13968,9 @@ var McpToolset = class {
13816
13968
  }
13817
13969
  /**
13818
13970
  * Set a sampling handler for this MCP toolset.
13819
- * This allows MCP servers to request LLM completions through your ADK agent.
13971
+ * This allows MCP servers to request LLM completions through your ADK-TS agent.
13820
13972
  *
13821
- * @param handler - ADK sampling handler that receives ADK-formatted messages
13973
+ * @param handler - ADK-TS sampling handler that receives ADK-TS-formatted messages
13822
13974
  */
13823
13975
  setSamplingHandler(handler) {
13824
13976
  if (!this.clientService) {
@@ -13852,7 +14004,7 @@ var McpToolset = class {
13852
14004
  "resource_closed_error" /* RESOURCE_CLOSED_ERROR */
13853
14005
  );
13854
14006
  }
13855
- if (this.tools.length > 0 && !this.config.cacheConfig?.enabled === false) {
14007
+ if (this.tools.length > 0 && this.isCacheEnabled()) {
13856
14008
  return this.tools;
13857
14009
  }
13858
14010
  if (!this.clientService) {
@@ -13881,7 +14033,7 @@ var McpToolset = class {
13881
14033
  }
13882
14034
  }
13883
14035
  }
13884
- if (this.config.cacheConfig?.enabled !== false) {
14036
+ if (this.isCacheEnabled()) {
13885
14037
  this.tools = tools;
13886
14038
  }
13887
14039
  return tools;
@@ -13898,7 +14050,7 @@ var McpToolset = class {
13898
14050
  }
13899
14051
  }
13900
14052
  /**
13901
- * Converts ADK tools to MCP tool format for bidirectional support
14053
+ * Converts ADK-TS tools to MCP tool format for bidirectional support
13902
14054
  */
13903
14055
  convertADKToolsToMCP(tools) {
13904
14056
  return tools.map((tool) => adkToMcpToolType(tool));
@@ -14591,10 +14743,7 @@ var CodeExecutionUtils = class _CodeExecutionUtils {
14591
14743
  * Gets the file content as a base64-encoded string
14592
14744
  */
14593
14745
  static getEncodedFileContent(data) {
14594
- let decodedData;
14595
- if (data instanceof ArrayBuffer) {
14596
- decodedData = new TextDecoder().decode(data);
14597
- }
14746
+ const decodedData = data instanceof ArrayBuffer ? new TextDecoder().decode(data) : data;
14598
14747
  if (_CodeExecutionUtils.isBase64Encoded(decodedData)) {
14599
14748
  return decodedData;
14600
14749
  }
@@ -16557,7 +16706,7 @@ var BaseAgent = class {
16557
16706
  }
16558
16707
  /**
16559
16708
  * The resolved beforeAgentCallback field as a list of SingleAgentCallback.
16560
- * This method is only for use by Agent Development Kit.
16709
+ * This method is only for use by ADK-TS.
16561
16710
  */
16562
16711
  get canonicalBeforeAgentCallbacks() {
16563
16712
  if (!this.beforeAgentCallback) {
@@ -16570,7 +16719,7 @@ var BaseAgent = class {
16570
16719
  }
16571
16720
  /**
16572
16721
  * The resolved afterAgentCallback field as a list of SingleAgentCallback.
16573
- * This method is only for use by Agent Development Kit.
16722
+ * This method is only for use by ADK-TS.
16574
16723
  */
16575
16724
  get canonicalAfterAgentCallbacks() {
16576
16725
  if (!this.afterAgentCallback) {
@@ -16872,7 +17021,7 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
16872
17021
  }
16873
17022
  /**
16874
17023
  * The resolved model field as BaseLLM
16875
- * This method is only for use by Agent Development Kit
17024
+ * This method is only for use by ADK-TS
16876
17025
  */
16877
17026
  get canonicalModel() {
16878
17027
  if (typeof this.model === "string") {
@@ -16897,7 +17046,7 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
16897
17046
  }
16898
17047
  /**
16899
17048
  * The resolved instruction field to construct instruction for this agent
16900
- * This method is only for use by Agent Development Kit
17049
+ * This method is only for use by ADK-TS
16901
17050
  */
16902
17051
  async canonicalInstruction(ctx) {
16903
17052
  if (typeof this.instruction === "string") {
@@ -16908,7 +17057,7 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
16908
17057
  }
16909
17058
  /**
16910
17059
  * The resolved global_instruction field to construct global instruction
16911
- * This method is only for use by Agent Development Kit
17060
+ * This method is only for use by ADK-TS
16912
17061
  */
16913
17062
  async canonicalGlobalInstruction(ctx) {
16914
17063
  if (typeof this.globalInstruction === "string") {
@@ -16919,7 +17068,7 @@ var LlmAgent = class _LlmAgent extends BaseAgent {
16919
17068
  }
16920
17069
  /**
16921
17070
  * The resolved tools field as a list of BaseTool based on the context
16922
- * This method is only for use by Agent Development Kit
17071
+ * This method is only for use by ADK-TS
16923
17072
  */
16924
17073
  async canonicalTools(_ctx) {
16925
17074
  const resolvedTools = [];
@@ -18324,6 +18473,7 @@ var LangGraphAgent = class extends BaseAgent {
18324
18473
  * Core logic to run this agent via text-based conversation.
18325
18474
  */
18326
18475
  async *runAsyncImpl(context4) {
18476
+ this.results = [];
18327
18477
  this.logger.debug(
18328
18478
  `Starting graph execution from root node "${this.rootNode}"`
18329
18479
  );
@@ -18515,7 +18665,7 @@ function createBranchContextForSubAgent(agent, subAgent, invocationContext) {
18515
18665
  agent: subAgent,
18516
18666
  userContent: invocationContext.userContent,
18517
18667
  session: invocationContext.session,
18518
- endInvocation: invocationContext.endInvocation,
18668
+ invocationFlags: invocationContext.getInvocationFlags(),
18519
18669
  liveRequestQueue: invocationContext.liveRequestQueue,
18520
18670
  activeStreamingTools: invocationContext.activeStreamingTools,
18521
18671
  transcriptionCache: invocationContext.transcriptionCache,
@@ -19483,8 +19633,29 @@ var GcsArtifactService = class {
19483
19633
  version
19484
19634
  );
19485
19635
  const blob = this.bucket.file(blobName);
19486
- await blob.save(artifact.inlineData.data, {
19487
- contentType: artifact.inlineData.mimeType,
19636
+ let data;
19637
+ let contentType;
19638
+ let partType;
19639
+ if (artifact.text !== void 0) {
19640
+ data = artifact.text;
19641
+ contentType = "text/plain";
19642
+ partType = "text";
19643
+ } else if (artifact.inlineData) {
19644
+ data = artifact.inlineData.data;
19645
+ contentType = artifact.inlineData.mimeType;
19646
+ partType = "inlineData";
19647
+ } else if (artifact.fileData) {
19648
+ data = artifact.fileData.fileUri;
19649
+ contentType = artifact.fileData.mimeType || "application/octet-stream";
19650
+ partType = "fileData";
19651
+ } else {
19652
+ throw new Error(
19653
+ "Unsupported artifact Part type: must have text, inlineData, or fileData"
19654
+ );
19655
+ }
19656
+ await blob.save(data, {
19657
+ contentType,
19658
+ metadata: { partType },
19488
19659
  preconditionOpts: { ifGenerationMatch: 0 }
19489
19660
  });
19490
19661
  return version;
@@ -19518,12 +19689,25 @@ var GcsArtifactService = class {
19518
19689
  if (!artifactBuffer) {
19519
19690
  return null;
19520
19691
  }
19521
- const part = {
19522
- inlineData: {
19523
- data: artifactBuffer.toString(),
19524
- mimeType: metadata.contentType || "application/octet-stream"
19525
- }
19526
- };
19692
+ const partType = metadata.metadata?.partType;
19693
+ let part;
19694
+ if (partType === "text") {
19695
+ part = { text: artifactBuffer.toString() };
19696
+ } else if (partType === "fileData") {
19697
+ part = {
19698
+ fileData: {
19699
+ fileUri: artifactBuffer.toString(),
19700
+ mimeType: metadata.contentType || "application/octet-stream"
19701
+ }
19702
+ };
19703
+ } else {
19704
+ part = {
19705
+ inlineData: {
19706
+ data: artifactBuffer.toString(),
19707
+ mimeType: metadata.contentType || "application/octet-stream"
19708
+ }
19709
+ };
19710
+ }
19527
19711
  return part;
19528
19712
  } catch (error) {
19529
19713
  if (error?.code === 404) {
@@ -19647,7 +19831,7 @@ var EvalResult = class {
19647
19831
  this.evalSetResultName = init.evalSetResultName;
19648
19832
  this.evalSetId = init.evalSetId || "";
19649
19833
  this.evalCaseResults = init.evalCaseResults || [];
19650
- this.creationTimestamp = init.creationTimestamp || Date.now() / 1e3;
19834
+ this.creationTimestamp = init.creationTimestamp || Date.now();
19651
19835
  }
19652
19836
  };
19653
19837
 
@@ -19675,6 +19859,8 @@ var BaseEvalService = class {
19675
19859
  };
19676
19860
 
19677
19861
  // src/evaluation/vertex-ai-eval-facade.ts
19862
+ import { GoogleAuth } from "google-auth-library";
19863
+ import axios4 from "axios";
19678
19864
  var ERROR_MESSAGE_SUFFIX = `
19679
19865
  You should specify both project id and location. This metric uses Vertex Gen AI
19680
19866
  Eval SDK, and it requires google cloud credentials.
@@ -19685,6 +19871,28 @@ the template below:
19685
19871
  process.env.GOOGLE_CLOUD_LOCATION = <LOCATION>
19686
19872
  process.env.GOOGLE_CLOUD_PROJECT = <PROJECT ID>
19687
19873
  `;
19874
+ var VERTEX_AI_EVAL_SCOPES = [
19875
+ "https://www.googleapis.com/auth/cloud-platform"
19876
+ ];
19877
+ var VERTEX_AI_METRIC_KEYS = {
19878
+ ["response_evaluation_score" /* RESPONSE_EVALUATION_SCORE */]: {
19879
+ inputKey: "coherence_input",
19880
+ resultKey: "coherenceResult"
19881
+ },
19882
+ ["safety_v1" /* SAFETY_V1 */]: {
19883
+ inputKey: "safety_input",
19884
+ resultKey: "safetyResult"
19885
+ }
19886
+ };
19887
+ function getMetricKeys(metric) {
19888
+ const keys = VERTEX_AI_METRIC_KEYS[metric];
19889
+ if (!keys) {
19890
+ throw new Error(
19891
+ `Metric "${metric}" is not supported by Vertex AI evaluation.`
19892
+ );
19893
+ }
19894
+ return keys;
19895
+ }
19688
19896
  var VertexAiEvalFacade = class _VertexAiEvalFacade {
19689
19897
  threshold;
19690
19898
  metricName;
@@ -19709,8 +19917,8 @@ var VertexAiEvalFacade = class _VertexAiEvalFacade {
19709
19917
  };
19710
19918
  try {
19711
19919
  const evalCaseResult = await _VertexAiEvalFacade._performEval(
19712
- [evalCase],
19713
- [this.metricName]
19920
+ evalCase,
19921
+ this.metricName
19714
19922
  );
19715
19923
  const score = this._getScore(evalCaseResult);
19716
19924
  perInvocationResults.push({
@@ -19754,8 +19962,9 @@ var VertexAiEvalFacade = class _VertexAiEvalFacade {
19754
19962
  return "";
19755
19963
  }
19756
19964
  _getScore(evalResult) {
19757
- if (evalResult?.summaryMetrics?.[0]?.meanScore !== void 0 && typeof evalResult.summaryMetrics[0].meanScore === "number" && !Number.isNaN(evalResult.summaryMetrics[0].meanScore)) {
19758
- return evalResult.summaryMetrics[0].meanScore;
19965
+ const meanScore = evalResult?.summaryMetrics?.[0]?.meanScore;
19966
+ if (typeof meanScore === "number" && !Number.isNaN(meanScore)) {
19967
+ return meanScore;
19759
19968
  }
19760
19969
  return void 0;
19761
19970
  }
@@ -19765,7 +19974,7 @@ var VertexAiEvalFacade = class _VertexAiEvalFacade {
19765
19974
  }
19766
19975
  return 3 /* NOT_EVALUATED */;
19767
19976
  }
19768
- static async _performEval(dataset, metrics3) {
19977
+ static async _performEval(evalCase, metric) {
19769
19978
  const projectId = process.env.GOOGLE_CLOUD_PROJECT;
19770
19979
  const location = process.env.GOOGLE_CLOUD_LOCATION;
19771
19980
  if (!projectId) {
@@ -19774,13 +19983,50 @@ var VertexAiEvalFacade = class _VertexAiEvalFacade {
19774
19983
  if (!location) {
19775
19984
  throw new Error(`Missing location. ${ERROR_MESSAGE_SUFFIX}`);
19776
19985
  }
19777
- console.warn(
19778
- "Vertex AI evaluation is not fully implemented. Using mock response."
19779
- );
19986
+ const auth = new GoogleAuth({ scopes: VERTEX_AI_EVAL_SCOPES });
19987
+ const accessToken = await auth.getAccessToken();
19988
+ if (!accessToken) {
19989
+ throw new Error(
19990
+ "Failed to obtain Google Cloud access token. Ensure Application Default Credentials are configured (e.g. run 'gcloud auth application-default login')."
19991
+ );
19992
+ }
19993
+ const { inputKey, resultKey } = getMetricKeys(metric);
19994
+ const url = `https://${location}-aiplatform.googleapis.com/v1beta1/projects/${projectId}/locations/${location}:evaluateInstances`;
19995
+ const instance = {
19996
+ prediction: evalCase.response
19997
+ };
19998
+ if (metric === "response_evaluation_score" /* RESPONSE_EVALUATION_SCORE */) {
19999
+ instance.reference = evalCase.reference;
20000
+ }
20001
+ const requestBody = {
20002
+ [inputKey]: {
20003
+ metric_spec: {},
20004
+ instance
20005
+ }
20006
+ };
20007
+ let responseData;
20008
+ try {
20009
+ const response = await axios4.post(url, requestBody, {
20010
+ headers: {
20011
+ Authorization: `Bearer ${accessToken}`,
20012
+ "Content-Type": "application/json"
20013
+ }
20014
+ });
20015
+ responseData = response.data;
20016
+ } catch (error) {
20017
+ if (axios4.isAxiosError(error)) {
20018
+ const detail = error.response?.data ? JSON.stringify(error.response.data) : "";
20019
+ throw new Error(
20020
+ `Vertex AI evaluation API request failed: ${error.message}${detail ? ` \u2014 ${detail}` : ""}`
20021
+ );
20022
+ }
20023
+ throw error;
20024
+ }
20025
+ const score = responseData?.[resultKey]?.score;
19780
20026
  return {
19781
20027
  summaryMetrics: [
19782
20028
  {
19783
- meanScore: Math.random() * 0.5 + 0.5
20029
+ meanScore: typeof score === "number" ? score : void 0
19784
20030
  }
19785
20031
  ]
19786
20032
  };
@@ -20236,9 +20482,13 @@ var LocalEvalService = class extends BaseEvalService {
20236
20482
  super();
20237
20483
  this.agent = agent;
20238
20484
  this.parallelism = parallelism;
20239
- this.initializeRunner();
20485
+ this.readyPromise = this.initializeRunner();
20240
20486
  }
20241
20487
  runner;
20488
+ readyPromise;
20489
+ ensureReady() {
20490
+ return this.readyPromise;
20491
+ }
20242
20492
  async initializeRunner() {
20243
20493
  if ("ask" in this.agent) {
20244
20494
  this.runner = this.agent;
@@ -20337,9 +20587,7 @@ var LocalEvalService = class extends BaseEvalService {
20337
20587
  }
20338
20588
  async runInference(evalCase) {
20339
20589
  const results = [];
20340
- if (!this.runner) {
20341
- await this.initializeRunner();
20342
- }
20590
+ await this.ensureReady();
20343
20591
  if (evalCase.sessionInput) {
20344
20592
  try {
20345
20593
  if (this.runner.initializeSession) {
@@ -22897,6 +23145,7 @@ import { sql } from "kysely";
22897
23145
  var DatabaseSessionService = class extends BaseSessionService {
22898
23146
  db;
22899
23147
  initialized = false;
23148
+ initPromise = null;
22900
23149
  constructor(config) {
22901
23150
  super();
22902
23151
  this.db = config.db;
@@ -22907,12 +23156,26 @@ var DatabaseSessionService = class extends BaseSessionService {
22907
23156
  }
22908
23157
  }
22909
23158
  /**
22910
- * Initialize the database by creating required tables if they don't exist
23159
+ * Initialize the database by creating required tables if they don't exist.
23160
+ * Uses promise deduplication so concurrent callers share a single initialization.
22911
23161
  */
22912
- async initializeDatabase() {
23162
+ initializeDatabase() {
22913
23163
  if (this.initialized) {
22914
- return;
23164
+ return Promise.resolve();
23165
+ }
23166
+ if (this.initPromise) {
23167
+ return this.initPromise;
22915
23168
  }
23169
+ const promise = this._doInitialize();
23170
+ this.initPromise = promise;
23171
+ promise.catch(() => {
23172
+ if (this.initPromise === promise) {
23173
+ this.initPromise = null;
23174
+ }
23175
+ });
23176
+ return promise;
23177
+ }
23178
+ async _doInitialize() {
22916
23179
  try {
22917
23180
  await this.db.schema.createTable("sessions").ifNotExists().addColumn("id", "varchar(128)", (col) => col.notNull()).addColumn("app_name", "varchar(128)", (col) => col.notNull()).addColumn("user_id", "varchar(128)", (col) => col.notNull()).addColumn("state", "text", (col) => col.defaultTo("{}")).addColumn(
22918
23181
  "create_time",
@@ -23179,7 +23442,8 @@ var DatabaseSessionService = class extends BaseSessionService {
23179
23442
  session.lastUpdateTime = this.timestampToUnixSeconds(
23180
23443
  updatedSession.update_time
23181
23444
  );
23182
- super.appendEvent(session, event);
23445
+ this.updateSessionState(session, event);
23446
+ session.events.push(event);
23183
23447
  return event;
23184
23448
  });
23185
23449
  }