@google/gemini-cli 0.42.0-preview.2 → 0.43.0-preview.0

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.
Files changed (80) hide show
  1. package/bundle/{chunk-FIIOJPLW.js → chunk-43AGRA7S.js} +3 -3
  2. package/bundle/{chunk-M6ZQAQKH.js → chunk-46T44JOY.js} +1 -1
  3. package/bundle/{chunk-OFOKTVUH.js → chunk-4TLQKGTR.js} +1 -1
  4. package/bundle/{chunk-4NXNVHPO.js → chunk-6XOSIMPZ.js} +8 -9
  5. package/bundle/{chunk-AAU5XCLJ.js → chunk-HQXINMBL.js} +2 -2
  6. package/bundle/{chunk-QM234EIA.js → chunk-JENIU3E3.js} +1 -1
  7. package/bundle/{chunk-R7BHIYZD.js → chunk-LBQFRHYD.js} +1 -1
  8. package/bundle/{chunk-WLPWIJ3Y.js → chunk-LFGJVOVZ.js} +486 -381
  9. package/bundle/{chunk-DEKZKOVU.js → chunk-MRHFLHPJ.js} +2 -2
  10. package/bundle/{chunk-ODIOD5TJ.js → chunk-MXKXLNQD.js} +3 -3
  11. package/bundle/{chunk-ECNYAST2.js → chunk-N6QYTC2T.js} +5417 -5376
  12. package/bundle/{chunk-WOGMVEEF.js → chunk-NBRZ4A3S.js} +2170 -791
  13. package/bundle/{chunk-Q24MYLMP.js → chunk-P4UQCQUB.js} +3 -3
  14. package/bundle/{chunk-S3WIE72K.js → chunk-PGJUNQPO.js} +34 -16
  15. package/bundle/{chunk-THNM4JU6.js → chunk-PSWUV2OO.js} +3 -3
  16. package/bundle/{chunk-6QBZKEWW.js → chunk-PYLHDAUK.js} +3 -3
  17. package/bundle/{chunk-2KRAWFEQ.js → chunk-Q23X5R4A.js} +486 -381
  18. package/bundle/{chunk-SJ6AOVZF.js → chunk-QYUN3J2L.js} +533 -441
  19. package/bundle/{chunk-77HSANAH.js → chunk-SAISHGWW.js} +1907 -716
  20. package/bundle/{chunk-I6IY72IP.js → chunk-SYD5SJFT.js} +38 -23
  21. package/bundle/{chunk-JW36FWGZ.js → chunk-T3SUXLQQ.js} +2 -2
  22. package/bundle/{chunk-BLNG7CSO.js → chunk-UIG2IVPJ.js} +34 -16
  23. package/bundle/{chunk-JEW7ZIWE.js → chunk-UJ26GAE5.js} +5326 -5290
  24. package/bundle/{chunk-E54WEGH3.js → chunk-UNAVBUTP.js} +14729 -7452
  25. package/bundle/{chunk-LYMYMKWM.js → chunk-WQOLTO3C.js} +1 -1
  26. package/bundle/{chunk-WFKT4UTI.js → chunk-X26T73X6.js} +3 -3
  27. package/bundle/{cleanup-5FPOUEHR.js → cleanup-EIZJH2E3.js} +3 -3
  28. package/bundle/{cleanup-G7DNOS4V.js → cleanup-MI76P55B.js} +3 -3
  29. package/bundle/{cleanup-GZM5KIZA.js → cleanup-NZBQYB7U.js} +3 -3
  30. package/bundle/{core-IYSSLWMM.js → core-ERSGIOMQ.js} +30 -2
  31. package/bundle/{dist-D7FZVGG3.js → core-T2TBFAYG.js} +30 -2
  32. package/bundle/{devtoolsService-UADEEKOH.js → devtoolsService-7KZDSYEF.js} +3 -3
  33. package/bundle/{devtoolsService-3XOQOECV.js → devtoolsService-FYTOIC37.js} +3 -3
  34. package/bundle/{devtoolsService-7ZN7CSSO.js → devtoolsService-LV5NJ2BT.js} +4 -5
  35. package/bundle/{dist-GF2RNVWZ.js → dist-ETX67B7P.js} +30 -2
  36. package/bundle/docs/changelogs/index.md +14 -0
  37. package/bundle/docs/changelogs/latest.md +108 -166
  38. package/bundle/docs/changelogs/preview.md +227 -103
  39. package/bundle/docs/cli/auto-memory.md +60 -38
  40. package/bundle/docs/cli/settings.md +1 -1
  41. package/bundle/docs/cli/tutorials/memory-management.md +1 -1
  42. package/bundle/docs/extensions/releasing.md +58 -24
  43. package/bundle/docs/reference/configuration.md +14 -1
  44. package/bundle/docs/reference/keyboard-shortcuts.md +23 -0
  45. package/bundle/{gemini-IRKIMLB4.js → gemini-IVKBXHDT.js} +160 -60
  46. package/bundle/{gemini-MWN2MSYV.js → gemini-JKWQQTKP.js} +160 -60
  47. package/bundle/{gemini-IMX43TZ4.js → gemini-Z77GAAR6.js} +331 -245
  48. package/bundle/gemini.js +8 -8
  49. package/bundle/{interactiveCli-SAMKYHUU.js → interactiveCli-36WZS6KT.js} +1704 -1457
  50. package/bundle/{interactiveCli-752P4PTI.js → interactiveCli-BQ36B66Z.js} +1703 -1457
  51. package/bundle/{interactiveCli-VX6GBWOV.js → interactiveCli-SME5QTEN.js} +1967 -1739
  52. package/bundle/{liteRtServerManager-CDLVKT7N.js → liteRtServerManager-2QD4R3A3.js} +5 -5
  53. package/bundle/{liteRtServerManager-FPYU5KEK.js → liteRtServerManager-ISYDOBNC.js} +5 -5
  54. package/bundle/{liteRtServerManager-OWPZ35U6.js → liteRtServerManager-N6OMT6W5.js} +5 -5
  55. package/bundle/{memoryDiscovery-FB7MMKTA.js → memoryDiscovery-LLSKN6HL.js} +1 -1
  56. package/bundle/{memoryDiscovery-KSYZVCWF.js → memoryDiscovery-SJ7P6RCN.js} +1 -1
  57. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  58. package/bundle/{oauth2-provider-446FDCUW.js → oauth2-provider-DOSIH6VE.js} +2 -2
  59. package/bundle/{oauth2-provider-RQNNLGWV.js → oauth2-provider-TZF6EZRX.js} +2 -2
  60. package/bundle/{oauth2-provider-6W4IY3LC.js → oauth2-provider-VFOABWBW.js} +73 -39
  61. package/bundle/{start-6U3XBAVH.js → start-3GPIRK3E.js} +7 -7
  62. package/bundle/{start-KUNHDGRA.js → start-6NONW677.js} +7 -7
  63. package/bundle/{start-TTLMBKNX.js → start-M6MUPEJS.js} +7 -7
  64. package/package.json +1 -1
  65. package/bundle/chunk-76KOJPMV.js +0 -391
  66. package/bundle/chunk-LHVIO4J4.js +0 -81544
  67. package/bundle/chunk-OP6THN3K.js +0 -118
  68. package/bundle/chunk-RO2XVFEU.js +0 -512
  69. package/bundle/chunk-WRDVEMWE.js +0 -1571
  70. package/bundle/chunk-YDC4M26X.js +0 -156
  71. package/bundle/chunk-ZDP2ZWKG.js +0 -17230
  72. package/bundle/chunk-ZFOGBX2H.js +0 -356008
  73. package/bundle/cleanup-J6AUEKWI.js +0 -33
  74. package/bundle/devtoolsService-KTUMQHXG.js +0 -857
  75. package/bundle/dist-HBMVDPXB.js +0 -2096
  76. package/bundle/gemini-SYFUC6XO.js +0 -16256
  77. package/bundle/interactiveCli-37SKHAKX.js +0 -34505
  78. package/bundle/liteRtServerManager-OWTQEYE6.js +0 -66
  79. package/bundle/oauth2-provider-TITPL3DN.js +0 -237
  80. package/bundle/start-TZXEJLTH.js +0 -19
@@ -89,6 +89,7 @@ import {
89
89
  PREVIEW_GEMINI_MODEL,
90
90
  PREVIEW_GEMINI_MODEL_AUTO,
91
91
  PRIORITY_SUBAGENT_TOOL,
92
+ PROJECT_MEMORY_INDEX_FILENAME,
92
93
  PolicyDecision,
93
94
  READ_FILE_DEFINITION,
94
95
  READ_FILE_DISPLAY_NAME,
@@ -217,7 +218,7 @@ import {
217
218
  toPathKey,
218
219
  unescapePath,
219
220
  zodToJsonSchema
220
- } from "./chunk-ECNYAST2.js";
221
+ } from "./chunk-N6QYTC2T.js";
221
222
  import {
222
223
  wrapper_default
223
224
  } from "./chunk-664ZODQF.js";
@@ -2568,7 +2569,7 @@ var require_lib = __commonJS({
2568
2569
  return numMessages > 0;
2569
2570
  }
2570
2571
  async function isBinaryFile2(file2, size) {
2571
- if (isString(file2)) {
2572
+ if (isString2(file2)) {
2572
2573
  const stat9 = await statAsync(file2);
2573
2574
  isStatFile(stat9);
2574
2575
  const fileDescriptor = await openAsync(file2, "r");
@@ -2596,7 +2597,7 @@ var require_lib = __commonJS({
2596
2597
  }
2597
2598
  exports2.isBinaryFile = isBinaryFile2;
2598
2599
  function isBinaryFileSync(file2, size) {
2599
- if (isString(file2)) {
2600
+ if (isString2(file2)) {
2600
2601
  const stat9 = fs84.statSync(file2);
2601
2602
  isStatFile(stat9);
2602
2603
  const fileDescriptor = fs84.openSync(file2, "r");
@@ -2676,7 +2677,7 @@ var require_lib = __commonJS({
2676
2677
  }
2677
2678
  return false;
2678
2679
  }
2679
- function isString(x) {
2680
+ function isString2(x) {
2680
2681
  return typeof x === "string";
2681
2682
  }
2682
2683
  function isStatFile(stat9) {
@@ -24444,7 +24445,7 @@ var require_minimal = __commonJS({
24444
24445
  function isInteger3(value) {
24445
24446
  return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
24446
24447
  };
24447
- util2.isString = function isString(value) {
24448
+ util2.isString = function isString2(value) {
24448
24449
  return typeof value === "string" || value instanceof String;
24449
24450
  };
24450
24451
  util2.isObject = function isObject6(value) {
@@ -25313,13 +25314,13 @@ var require_path = __commonJS({
25313
25314
  "node_modules/@protobufjs/path/index.js"(exports2) {
25314
25315
  "use strict";
25315
25316
  var path101 = exports2;
25316
- var isAbsolute8 = (
25317
+ var isAbsolute7 = (
25317
25318
  /**
25318
25319
  * Tests if the specified path is absolute.
25319
25320
  * @param {string} path Path to test
25320
25321
  * @returns {boolean} `true` if path is absolute
25321
25322
  */
25322
- path101.isAbsolute = function isAbsolute9(path102) {
25323
+ path101.isAbsolute = function isAbsolute8(path102) {
25323
25324
  return /^(?:\/|\w+:)/.test(path102);
25324
25325
  }
25325
25326
  );
@@ -25331,7 +25332,7 @@ var require_path = __commonJS({
25331
25332
  */
25332
25333
  path101.normalize = function normalize6(path102) {
25333
25334
  path102 = path102.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
25334
- var parts2 = path102.split("/"), absolute = isAbsolute8(path102), prefix = "";
25335
+ var parts2 = path102.split("/"), absolute = isAbsolute7(path102), prefix = "";
25335
25336
  if (absolute)
25336
25337
  prefix = parts2.shift() + "/";
25337
25338
  for (var i3 = 0; i3 < parts2.length; ) {
@@ -25353,7 +25354,7 @@ var require_path = __commonJS({
25353
25354
  path101.resolve = function resolve25(originPath, includePath, alreadyNormalized) {
25354
25355
  if (!alreadyNormalized)
25355
25356
  includePath = normalize5(includePath);
25356
- if (isAbsolute8(includePath))
25357
+ if (isAbsolute7(includePath))
25357
25358
  return includePath;
25358
25359
  if (!alreadyNormalized)
25359
25360
  originPath = normalize5(originPath);
@@ -42945,7 +42946,7 @@ var require_minimal2 = __commonJS({
42945
42946
  function isInteger3(value) {
42946
42947
  return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
42947
42948
  };
42948
- util2.isString = function isString(value) {
42949
+ util2.isString = function isString2(value) {
42949
42950
  return typeof value === "string" || value instanceof String;
42950
42951
  };
42951
42952
  util2.isObject = function isObject6(value) {
@@ -96320,7 +96321,7 @@ var require_object_inspect = __commonJS({
96320
96321
  if (isBoolean2(obj)) {
96321
96322
  return markBoxed(booleanValueOf.call(obj));
96322
96323
  }
96323
- if (isString(obj)) {
96324
+ if (isString2(obj)) {
96324
96325
  return markBoxed(inspect4(String(obj)));
96325
96326
  }
96326
96327
  if (typeof window !== "undefined" && obj === window) {
@@ -96369,7 +96370,7 @@ var require_object_inspect = __commonJS({
96369
96370
  function isError(obj) {
96370
96371
  return toStr(obj) === "[object Error]" && canTrustToString(obj);
96371
96372
  }
96372
- function isString(obj) {
96373
+ function isString2(obj) {
96373
96374
  return toStr(obj) === "[object String]" && canTrustToString(obj);
96374
96375
  }
96375
96376
  function isNumber3(obj) {
@@ -204417,8 +204418,8 @@ var require_ignore = __commonJS({
204417
204418
  (prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)),
204418
204419
  pattern
204419
204420
  );
204420
- var isString = (subject) => typeof subject === "string";
204421
- var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
204421
+ var isString2 = (subject) => typeof subject === "string";
204422
+ var checkPattern = (pattern) => pattern && isString2(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
204422
204423
  var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
204423
204424
  var IgnoreRule = class {
204424
204425
  constructor(pattern, mark, body2, ignoreCase, negative, prefix) {
@@ -204485,7 +204486,7 @@ var require_ignore = __commonJS({
204485
204486
  this._added = true;
204486
204487
  return;
204487
204488
  }
204488
- if (isString(pattern)) {
204489
+ if (isString2(pattern)) {
204489
204490
  pattern = {
204490
204491
  pattern
204491
204492
  };
@@ -204500,7 +204501,7 @@ var require_ignore = __commonJS({
204500
204501
  add(pattern) {
204501
204502
  this._added = false;
204502
204503
  makeArray(
204503
- isString(pattern) ? splitPattern(pattern) : pattern
204504
+ isString2(pattern) ? splitPattern(pattern) : pattern
204504
204505
  ).forEach(this._add, this);
204505
204506
  return this._added;
204506
204507
  }
@@ -204542,7 +204543,7 @@ var require_ignore = __commonJS({
204542
204543
  throw new Ctor(message);
204543
204544
  };
204544
204545
  var checkPath = (path101, originalPath, doThrow) => {
204545
- if (!isString(path101)) {
204546
+ if (!isString2(path101)) {
204546
204547
  return doThrow(
204547
204548
  `path must be a string, but got \`${originalPath}\``,
204548
204549
  TypeError
@@ -229139,13 +229140,13 @@ var require_implementation2 = __commonJS({
229139
229140
  var isObject6 = object3 !== null && typeof object3 === "object";
229140
229141
  var isFunction = toStr.call(object3) === "[object Function]";
229141
229142
  var isArguments = isArgs(object3);
229142
- var isString = isObject6 && toStr.call(object3) === "[object String]";
229143
+ var isString2 = isObject6 && toStr.call(object3) === "[object String]";
229143
229144
  var theKeys = [];
229144
229145
  if (!isObject6 && !isFunction && !isArguments) {
229145
229146
  throw new TypeError("Object.keys called on a non-object");
229146
229147
  }
229147
229148
  var skipProto = hasProtoEnumBug && isFunction;
229148
- if (isString && object3.length > 0 && !has.call(object3, 0)) {
229149
+ if (isString2 && object3.length > 0 && !has.call(object3, 0)) {
229149
229150
  for (var i3 = 0; i3 < object3.length; ++i3) {
229150
229151
  theKeys.push(String(i3));
229151
229152
  }
@@ -236746,6 +236747,8 @@ var BINARY_FILE_PATTERNS = [
236746
236747
  "**/*.bz2",
236747
236748
  "**/*.rar",
236748
236749
  "**/*.7z",
236750
+ "**/*.pak",
236751
+ "**/*.rpa",
236749
236752
  "**/*.doc",
236750
236753
  "**/*.docx",
236751
236754
  "**/*.xls",
@@ -237791,8 +237794,14 @@ function escapeShellArg(arg, shell) {
237791
237794
  }
237792
237795
  switch (shell) {
237793
237796
  case "powershell":
237797
+ if (/^[a-zA-Z0-9\-_.]+$/.test(arg)) {
237798
+ return arg;
237799
+ }
237794
237800
  return `'${arg.replace(/'/g, "''")}'`;
237795
237801
  case "cmd":
237802
+ if (/^[a-zA-Z0-9\-_.]+$/.test(arg)) {
237803
+ return arg;
237804
+ }
237796
237805
  return `"${arg.replace(/"/g, '""')}"`;
237797
237806
  case "bash":
237798
237807
  default:
@@ -242234,7 +242243,8 @@ function recordModelRoutingMetrics(config2, event) {
242234
242243
  "routing.approval_mode": event.approval_mode
242235
242244
  };
242236
242245
  if (event.reasoning) {
242237
- attributes["routing.reasoning"] = event.reasoning;
242246
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
242247
+ attributes["routing.reasoning"] = isStrictTelemetry && event.reasoning.length > 1e3 ? event.reasoning.substring(0, 1e3) + "..." : event.reasoning;
242238
242248
  }
242239
242249
  if (event.enable_numerical_routing !== void 0) {
242240
242250
  attributes["routing.enable_numerical_routing"] = event.enable_numerical_routing;
@@ -242244,9 +242254,10 @@ function recordModelRoutingMetrics(config2, event) {
242244
242254
  }
242245
242255
  modelRoutingLatencyHistogram.record(event.routing_latency_ms, attributes);
242246
242256
  if (event.failed) {
242257
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
242247
242258
  modelRoutingFailureCounter.add(1, {
242248
242259
  ...attributes,
242249
- "routing.error_message": event.error_message
242260
+ "routing.error_message": isStrictTelemetry && event.error_message && event.error_message.length > 1e3 ? event.error_message.substring(0, 1e3) + "..." : event.error_message
242250
242261
  });
242251
242262
  }
242252
242263
  }
@@ -245069,7 +245080,7 @@ var KeychainService = class {
245069
245080
  if (await this.isKeychainFunctional(keychainModule)) {
245070
245081
  return keychainModule;
245071
245082
  }
245072
- debugLogger.debug("Keychain functional verification failed");
245083
+ debugLogger.debug("Keychain functional verification failed or timed out");
245073
245084
  return null;
245074
245085
  } catch (error40) {
245075
245086
  const message = error40 instanceof Error ? error40.message : String(error40);
@@ -245096,16 +245107,30 @@ var KeychainService = class {
245096
245107
  return null;
245097
245108
  }
245098
245109
  // Performs a set-get-delete cycle to verify keychain functionality.
245110
+ // Capped with a 2s timeout so a non-responsive Secret Service (common on
245111
+ // headless Linux: WSL/SSH/Docker without gnome-keyring or D-Bus) falls back
245112
+ // to FileKeychain instead of hanging the CLI indefinitely.
245099
245113
  async isKeychainFunctional(keychain) {
245100
245114
  const testAccount = `${KEYCHAIN_TEST_PREFIX}${crypto7.randomBytes(8).toString("hex")}`;
245101
245115
  const testPassword = "test";
245102
- await keychain.setPassword(this.serviceName, testAccount, testPassword);
245103
- const retrieved = await keychain.getPassword(this.serviceName, testAccount);
245104
- const deleted = await keychain.deletePassword(
245105
- this.serviceName,
245106
- testAccount
245107
- );
245108
- return deleted && retrieved === testPassword;
245116
+ const probe = async () => {
245117
+ await keychain.setPassword(this.serviceName, testAccount, testPassword);
245118
+ const retrieved = await keychain.getPassword(
245119
+ this.serviceName,
245120
+ testAccount
245121
+ );
245122
+ const deleted = await keychain.deletePassword(
245123
+ this.serviceName,
245124
+ testAccount
245125
+ );
245126
+ return deleted && retrieved === testPassword;
245127
+ };
245128
+ return Promise.race([
245129
+ probe(),
245130
+ new Promise(
245131
+ (resolve25) => setTimeout(() => resolve25(false), 2e3).unref()
245132
+ )
245133
+ ]);
245109
245134
  }
245110
245135
  /**
245111
245136
  * MacOS-specific check to detect if a default keychain is available.
@@ -245639,7 +245664,8 @@ async function triggerPostAuthCallbacks(tokens) {
245639
245664
  refresh_token: tokens.refresh_token ?? void 0,
245640
245665
  // Ensure null is not passed
245641
245666
  type: "authorized_user",
245642
- client_email: userAccountManager2.getCachedGoogleAccount() ?? void 0
245667
+ client_email: userAccountManager2.getCachedGoogleAccount() ?? void 0,
245668
+ quota_project_id: process.env["GOOGLE_CLOUD_QUOTA_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"]
245643
245669
  };
245644
245670
  authEvents.emit("post_auth", jwtInput);
245645
245671
  }
@@ -246396,8 +246422,8 @@ import { createHash } from "node:crypto";
246396
246422
  import * as os12 from "node:os";
246397
246423
 
246398
246424
  // packages/core/src/generated/git-commit.ts
246399
- var GIT_COMMIT_INFO = "6837b08a0";
246400
- var CLI_VERSION = "0.42.0-preview.1";
246425
+ var GIT_COMMIT_INFO = "022e8baef";
246426
+ var CLI_VERSION = "0.43.0-preview.0";
246401
246427
 
246402
246428
  // packages/core/src/ide/detect-ide.ts
246403
246429
  var IDE_DEFINITIONS = {
@@ -248273,7 +248299,37 @@ var GcpMetricExporter = class extends import_opentelemetry_cloud_monitoring_expo
248273
248299
  prefix: "custom.googleapis.com/gemini_cli"
248274
248300
  });
248275
248301
  }
248302
+ export(metrics2, resultCallback) {
248303
+ super.export(metrics2, (result2) => {
248304
+ if (result2.code === import_core5.ExportResultCode.FAILED && result2.error) {
248305
+ const errorMessage = result2.error.message || String(result2.error);
248306
+ if (process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true" && errorMessage.includes(
248307
+ "written more frequently than the maximum sampling period"
248308
+ )) {
248309
+ resultCallback({ code: import_core5.ExportResultCode.SUCCESS });
248310
+ return;
248311
+ }
248312
+ }
248313
+ resultCallback(result2);
248314
+ });
248315
+ }
248276
248316
  };
248317
+ function truncateLogPayload(payload, limit = 2e5) {
248318
+ if (typeof payload === "string") {
248319
+ return payload.length > limit ? payload.substring(0, limit) + "... (truncated due to size)" : payload;
248320
+ }
248321
+ if (Array.isArray(payload)) {
248322
+ return payload.map((item) => truncateLogPayload(item, limit));
248323
+ }
248324
+ if (payload !== null && typeof payload === "object") {
248325
+ const truncatedObj = {};
248326
+ for (const [key, value] of Object.entries(payload)) {
248327
+ truncatedObj[key] = truncateLogPayload(value, limit);
248328
+ }
248329
+ return truncatedObj;
248330
+ }
248331
+ return payload;
248332
+ }
248277
248333
  var GcpLogExporter = class {
248278
248334
  logging;
248279
248335
  log;
@@ -248285,6 +248341,32 @@ var GcpLogExporter = class {
248285
248341
  export(logs3, resultCallback) {
248286
248342
  try {
248287
248343
  const entries = logs3.map((log) => {
248344
+ const rawPayload = {
248345
+ ...log.attributes,
248346
+ ...log.resource?.attributes,
248347
+ message: log.body
248348
+ };
248349
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
248350
+ let finalPayload = rawPayload;
248351
+ if (isStrictTelemetry) {
248352
+ let safePayload = truncateLogPayload(rawPayload, 1e4);
248353
+ let payloadString = JSON.stringify(safePayload);
248354
+ if (payloadString && payloadString.length > 1e5) {
248355
+ safePayload = truncateLogPayload(rawPayload, 2e3);
248356
+ payloadString = JSON.stringify(safePayload);
248357
+ if (payloadString && payloadString.length > 1e5) {
248358
+ safePayload = truncateLogPayload(rawPayload, 5e3);
248359
+ payloadString = JSON.stringify(safePayload);
248360
+ if (payloadString && payloadString.length > 1e5) {
248361
+ safePayload = {
248362
+ _warning: "Payload heavily truncated due to strict limits",
248363
+ data: payloadString.substring(0, 5e4) + "... (truncated)"
248364
+ };
248365
+ }
248366
+ }
248367
+ }
248368
+ finalPayload = safePayload;
248369
+ }
248288
248370
  const entry = this.log.entry(
248289
248371
  {
248290
248372
  severity: this.mapSeverityToCloudLogging(log.severityNumber),
@@ -248296,11 +248378,8 @@ var GcpLogExporter = class {
248296
248378
  }
248297
248379
  }
248298
248380
  },
248299
- {
248300
- ...log.attributes,
248301
- ...log.resource?.attributes,
248302
- message: log.body
248303
- }
248381
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
248382
+ finalPayload
248304
248383
  );
248305
248384
  return entry;
248306
248385
  });
@@ -269712,7 +269791,7 @@ function getVersion() {
269712
269791
  }
269713
269792
  versionPromise = (async () => {
269714
269793
  const pkgJson = await getPackageJson(__dirname4);
269715
- return "0.42.0-preview.1";
269794
+ return "0.43.0-preview.0";
269716
269795
  })();
269717
269796
  return versionPromise;
269718
269797
  }
@@ -270735,25 +270814,36 @@ function cloneChain(chain2) {
270735
270814
  return chain2.map(clonePolicy);
270736
270815
  }
270737
270816
 
270817
+ // packages/core/src/utils/modelUtils.ts
270818
+ function normalizeModelId(modelId) {
270819
+ return modelId.startsWith("models/") ? modelId.slice(7) : modelId;
270820
+ }
270821
+
270738
270822
  // packages/core/src/availability/policyHelpers.ts
270739
270823
  function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270740
- const modelFromConfig = preferredModel ?? config2.getActiveModel?.() ?? config2.getModel();
270741
- const configuredModel = config2.getModel();
270824
+ const normalizedPreferredModel = preferredModel ? normalizeModelId(preferredModel) : void 0;
270825
+ const modelFromConfig = normalizeModelId(
270826
+ normalizedPreferredModel ?? config2.getActiveModel?.() ?? config2.getModel()
270827
+ );
270828
+ const configuredModel = normalizeModelId(config2.getModel());
270742
270829
  let chain2;
270743
270830
  const useGemini31 = config2.getGemini31LaunchedSync?.() ?? false;
270744
270831
  const useGemini31FlashLite = config2.getGemini31FlashLiteLaunchedSync?.() ?? false;
270745
270832
  const useCustomToolModel = config2.getUseCustomToolModelSync?.() ?? false;
270746
270833
  const hasAccessToPreview = config2.getHasAccessToPreviewModel?.() ?? true;
270747
- const resolvedModel = resolveModel(
270748
- modelFromConfig,
270749
- useGemini31,
270750
- useGemini31FlashLite,
270751
- useCustomToolModel,
270752
- hasAccessToPreview,
270753
- config2
270834
+ const resolvedModel = normalizeModelId(
270835
+ resolveModel(
270836
+ modelFromConfig,
270837
+ useGemini31,
270838
+ useGemini31FlashLite,
270839
+ useCustomToolModel,
270840
+ hasAccessToPreview,
270841
+ config2
270842
+ )
270754
270843
  );
270755
- const isAutoPreferred = preferredModel ? isAutoModel(preferredModel, config2) : false;
270844
+ const isAutoPreferred = normalizedPreferredModel ? isAutoModel(normalizedPreferredModel, config2) : false;
270756
270845
  const isAutoConfigured = isAutoModel(configuredModel, config2);
270846
+ const effectiveWrapsAround = wrapsAround || isAutoPreferred || isAutoConfigured || isGemini3Model(resolvedModel, config2);
270757
270847
  if (config2.getExperimentalDynamicModelConfiguration?.() === true) {
270758
270848
  const context2 = {
270759
270849
  useGemini3_1: useGemini31,
@@ -270762,7 +270852,7 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270762
270852
  };
270763
270853
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270764
270854
  chain2 = config2.modelConfigService.resolveChain("lite", context2);
270765
- } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270855
+ } else if (isGemini3Model(normalizeModelId(resolvedModel), config2) || isAutoPreferred || isAutoConfigured) {
270766
270856
  if (isAutoConfigured && config2.modelConfigService.getModelChain(configuredModel)) {
270767
270857
  chain2 = config2.modelConfigService.resolveChain(
270768
270858
  configuredModel,
@@ -270771,7 +270861,7 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270771
270861
  }
270772
270862
  if (!chain2) {
270773
270863
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270774
- const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270864
+ const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270775
270865
  const autoPrefix = isAutoSelection ? "auto-" : "";
270776
270866
  const chainKey = previewEnabled ? "preview" : "default";
270777
270867
  chain2 = config2.modelConfigService.resolveChain(
@@ -270783,14 +270873,14 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270783
270873
  if (!chain2) {
270784
270874
  chain2 = createSingleModelChain(modelFromConfig);
270785
270875
  }
270786
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270876
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270787
270877
  } else {
270788
270878
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270789
270879
  chain2 = getFlashLitePolicyChain();
270790
270880
  } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270791
270881
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270792
270882
  if (hasAccessToPreview) {
270793
- const previewEnabled = isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270883
+ const previewEnabled = isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270794
270884
  chain2 = getModelPolicyChain({
270795
270885
  previewEnabled,
270796
270886
  isAutoSelection,
@@ -270812,7 +270902,7 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270812
270902
  } else {
270813
270903
  chain2 = createSingleModelChain(modelFromConfig);
270814
270904
  }
270815
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270905
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270816
270906
  }
270817
270907
  if (config2?.getApprovalMode?.() === "plan" /* PLAN */) {
270818
270908
  return chain2.map((policy) => ({
@@ -270823,8 +270913,9 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270823
270913
  return chain2;
270824
270914
  }
270825
270915
  function applyDynamicSlicing(chain2, resolvedModel, wrapsAround) {
270916
+ const normalizedResolved = normalizeModelId(resolvedModel);
270826
270917
  const activeIndex = chain2.findIndex(
270827
- (policy) => policy.model === resolvedModel
270918
+ (policy) => normalizeModelId(policy.model) === normalizedResolved
270828
270919
  );
270829
270920
  if (activeIndex !== -1) {
270830
270921
  return wrapsAround ? [...chain2.slice(activeIndex), ...chain2.slice(0, activeIndex)] : [...chain2.slice(activeIndex)];
@@ -270832,7 +270923,10 @@ function applyDynamicSlicing(chain2, resolvedModel, wrapsAround) {
270832
270923
  return [createDefaultPolicy(resolvedModel, { isLastResort: true })];
270833
270924
  }
270834
270925
  function buildFallbackPolicyContext(chain2, failedModel, wrapsAround = false) {
270835
- const index = chain2.findIndex((policy) => policy.model === failedModel);
270926
+ const normalizedFailed = normalizeModelId(failedModel);
270927
+ const index = chain2.findIndex(
270928
+ (policy) => normalizeModelId(policy.model) === normalizedFailed
270929
+ );
270836
270930
  if (index === -1) {
270837
270931
  return { failedPolicy: void 0, candidates: chain2 };
270838
270932
  }
@@ -271518,6 +271612,15 @@ var BaseLlmClient = class {
271518
271612
  }
271519
271613
  return text;
271520
271614
  }
271615
+ async countTokens(options) {
271616
+ const model = options.modelConfigKey ? this.config.modelConfigService.getResolvedConfig(options.modelConfigKey).model : this.config.getActiveModel();
271617
+ const result2 = await this.contentGenerator.countTokens({
271618
+ model,
271619
+ contents: options.contents,
271620
+ config: options.abortSignal ? { abortSignal: options.abortSignal } : void 0
271621
+ });
271622
+ return { totalTokens: result2.totalTokens || 0 };
271623
+ }
271521
271624
  async generateContent(options) {
271522
271625
  const {
271523
271626
  modelConfigKey,
@@ -272190,6 +272293,9 @@ function isEditToolParams(args2) {
272190
272293
  }
272191
272294
  return "file_path" in args2 && typeof args2.file_path === "string" && "old_string" in args2 && typeof args2.old_string === "string" && "new_string" in args2 && typeof args2.new_string === "string";
272192
272295
  }
272296
+ function fileDiffToSummary(diff, editData) {
272297
+ return diff.diffStat ? `${diff.diffStat.model_added_lines} added, ${diff.diffStat.model_removed_lines} removed` : `${editData.occurrences} replacements`;
272298
+ }
272193
272299
  var EditToolInvocation = class extends BaseToolInvocation {
272194
272300
  constructor(config2, params, messageBus, toolName, displayName) {
272195
272301
  super(
@@ -272632,8 +272738,20 @@ ${snippet2}`);
272632
272738
  if (jitContext) {
272633
272739
  llmContent = appendJitContext(llmContent, jitContext);
272634
272740
  }
272741
+ const resultSummary = typeof displayResult === "string" ? displayResult : fileDiffToSummary(displayResult, editData);
272635
272742
  return {
272636
272743
  llmContent,
272744
+ display: {
272745
+ name: this._toolDisplayName,
272746
+ description: this.getDescription(),
272747
+ resultSummary,
272748
+ result: {
272749
+ type: "diff",
272750
+ path: this.resolvedPath,
272751
+ beforeText: editData.currentContent ?? "",
272752
+ afterText: editData.newContent
272753
+ }
272754
+ },
272637
272755
  returnDisplay: displayResult
272638
272756
  };
272639
272757
  } catch (error40) {
@@ -273272,6 +273390,17 @@ ${snippet2}`);
273272
273390
  }
273273
273391
  return {
273274
273392
  llmContent,
273393
+ display: {
273394
+ name: WRITE_FILE_DISPLAY_NAME,
273395
+ description: this.getDescription(),
273396
+ resultSummary: diffStat ? `${diffStat.model_added_lines} added, ${diffStat.model_removed_lines} removed` : "Written",
273397
+ result: {
273398
+ type: "diff",
273399
+ path: this.resolvedPath,
273400
+ beforeText: correctedContentResult.originalContent ?? "",
273401
+ afterText: correctedContentResult.correctedContent
273402
+ }
273403
+ },
273275
273404
  returnDisplay: displayResult
273276
273405
  };
273277
273406
  } catch (error40) {
@@ -274111,6 +274240,14 @@ var ProjectIdRequiredError = class extends Error {
274111
274240
  this.name = "ProjectIdRequiredError";
274112
274241
  }
274113
274242
  };
274243
+ var InvalidNumericProjectIdError = class extends Error {
274244
+ constructor(projectId) {
274245
+ super(
274246
+ `Invalid Google Cloud Project ID: "${projectId}". The GOOGLE_CLOUD_PROJECT (or GOOGLE_CLOUD_PROJECT_ID) environment variable must be set to your string-based Project ID (e.g., "my-project-123"), not your numeric Project Number. Please update your environment variables.`
274247
+ );
274248
+ this.name = "InvalidNumericProjectIdError";
274249
+ }
274250
+ };
274114
274251
  var ValidationCancelledError = class extends Error {
274115
274252
  constructor() {
274116
274253
  super("User cancelled account validation");
@@ -274136,6 +274273,9 @@ function resetUserDataCacheForTesting() {
274136
274273
  }
274137
274274
  async function setupUser(client, config2, httpOptions = {}) {
274138
274275
  const projectId = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
274276
+ if (projectId && /^\d+$/.test(projectId)) {
274277
+ throw new InvalidNumericProjectIdError(projectId);
274278
+ }
274139
274279
  const projectCache = userDataCache.getOrCreate(
274140
274280
  client,
274141
274281
  () => createCache({
@@ -274315,13 +274455,26 @@ function validateLoadCodeAssistResponse(res) {
274315
274455
 
274316
274456
  // packages/core/src/utils/quotaErrorDetection.ts
274317
274457
  function isApiError(error40) {
274318
- return typeof error40 === "object" && error40 !== null && "error" in error40 && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
274319
- typeof error40.error === "object" && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
274320
- "message" in error40.error;
274458
+ if (typeof error40 !== "object" || error40 === null || !("error" in error40)) {
274459
+ return false;
274460
+ }
274461
+ const errorProp = error40.error;
274462
+ if (typeof errorProp !== "object" || errorProp === null) {
274463
+ return false;
274464
+ }
274465
+ return "code" in errorProp && typeof errorProp.code === "number" && "message" in errorProp && typeof errorProp.message === "string" && "status" in errorProp && typeof errorProp.status === "string";
274321
274466
  }
274322
274467
  function isStructuredError(error40) {
274323
- return typeof error40 === "object" && error40 !== null && "message" in error40 && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
274324
- typeof error40.message === "string";
274468
+ if (typeof error40 !== "object" || error40 === null || !("message" in error40)) {
274469
+ return false;
274470
+ }
274471
+ if (typeof error40.message !== "string") {
274472
+ return false;
274473
+ }
274474
+ if ("status" in error40 && typeof error40.status !== "number") {
274475
+ return false;
274476
+ }
274477
+ return true;
274325
274478
  }
274326
274479
 
274327
274480
  // packages/core/src/utils/tokenCalculation.ts
@@ -274338,9 +274491,10 @@ function estimateTextTokens(text, charsPerToken) {
274338
274491
  return text.length / charsPerToken;
274339
274492
  }
274340
274493
  let tokens = 0;
274494
+ const asciiTokensPerChar = 1 / charsPerToken;
274341
274495
  for (let i3 = 0; i3 < text.length; i3++) {
274342
274496
  if (text.charCodeAt(i3) <= 127) {
274343
- tokens += ASCII_TOKENS_PER_CHAR;
274497
+ tokens += asciiTokensPerChar;
274344
274498
  } else {
274345
274499
  tokens += NON_ASCII_TOKENS_PER_CHAR;
274346
274500
  }
@@ -275143,10 +275297,6 @@ function validateBaseUrl(baseUrl) {
275143
275297
  }
275144
275298
  }
275145
275299
  async function createContentGeneratorConfig(config2, authType, apiKey, baseUrl, customHeaders, vertexAiRouting) {
275146
- const geminiApiKey = apiKey || process.env["GEMINI_API_KEY"] || await loadApiKey() || void 0;
275147
- const googleApiKey = process.env["GOOGLE_API_KEY"] || void 0;
275148
- const googleCloudProject = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
275149
- const googleCloudLocation = process.env["GOOGLE_CLOUD_LOCATION"] || void 0;
275150
275300
  const contentGeneratorConfig = {
275151
275301
  authType,
275152
275302
  proxy: config2?.getProxy(),
@@ -275157,6 +275307,10 @@ async function createContentGeneratorConfig(config2, authType, apiKey, baseUrl,
275157
275307
  if (authType === "oauth-personal" /* LOGIN_WITH_GOOGLE */ || authType === "compute-default-credentials" /* COMPUTE_ADC */) {
275158
275308
  return contentGeneratorConfig;
275159
275309
  }
275310
+ const geminiApiKey = apiKey || process.env["GEMINI_API_KEY"] || await loadApiKey() || void 0;
275311
+ const googleApiKey = process.env["GOOGLE_API_KEY"] || void 0;
275312
+ const googleCloudProject = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
275313
+ const googleCloudLocation = process.env["GOOGLE_CLOUD_LOCATION"] || void 0;
275160
275314
  if (authType === "gemini-api-key" /* USE_GEMINI */ && geminiApiKey) {
275161
275315
  contentGeneratorConfig.apiKey = geminiApiKey;
275162
275316
  contentGeneratorConfig.vertexai = false;
@@ -276185,6 +276339,11 @@ ${directoryContent}`;
276185
276339
  }
276186
276340
  return {
276187
276341
  llmContent: resultMessage,
276342
+ display: {
276343
+ name: LS_DISPLAY_NAME,
276344
+ description: this.getDescription(),
276345
+ resultSummary: displayMessage
276346
+ },
276188
276347
  returnDisplay: {
276189
276348
  summary: displayMessage,
276190
276349
  files: entries.map(
@@ -276462,7 +276621,9 @@ var IgnoreFileParser = class {
276462
276621
  return this.patterns;
276463
276622
  }
276464
276623
  getIgnoreFilePaths() {
276465
- return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter((filePath) => fs34.existsSync(filePath));
276624
+ return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter(
276625
+ (filePath) => fs34.statSync(filePath, { throwIfNoEntry: false })?.isFile() ?? false
276626
+ );
276466
276627
  }
276467
276628
  /**
276468
276629
  * Returns true if at least one ignore file exists and has patterns.
@@ -276701,7 +276862,8 @@ var FileDiscoveryService = class {
276701
276862
  const paths = [];
276702
276863
  if (this.gitIgnoreFilter && this.defaultFilterFileOptions.respectGitIgnore) {
276703
276864
  const gitIgnorePath = path41.join(this.projectRoot, ".gitignore");
276704
- if (fs36.existsSync(gitIgnorePath)) {
276865
+ const stat9 = fs36.statSync(gitIgnorePath, { throwIfNoEntry: false });
276866
+ if (stat9?.isFile()) {
276705
276867
  paths.push(gitIgnorePath);
276706
276868
  }
276707
276869
  }
@@ -276810,8 +276972,15 @@ ${result2.llmContent}`;
276810
276972
  llmContent = appendJitContextToParts(llmContent, jitContext);
276811
276973
  }
276812
276974
  }
276975
+ const displayResultSummary = result2.isTruncated ? `${result2.linesShown[0]}-${result2.linesShown[1]} of ${result2.originalLineCount}` : lines !== void 0 ? `${lines} lines` : void 0;
276813
276976
  return {
276814
276977
  llmContent,
276978
+ display: {
276979
+ name: READ_FILE_DISPLAY_NAME,
276980
+ description: this.getDescription(),
276981
+ resultSummary: displayResultSummary,
276982
+ result: { type: "text", text: result2.returnDisplay || "" }
276983
+ },
276815
276984
  returnDisplay: result2.returnDisplay || ""
276816
276985
  };
276817
276986
  }
@@ -276851,12 +277020,6 @@ var ReadFileTool = class _ReadFileTool extends BaseDeclarativeTool {
276851
277020
  if (validationError) {
276852
277021
  return validationError;
276853
277022
  }
276854
- if (params.start_line !== void 0 && params.start_line < 1) {
276855
- return "start_line must be at least 1";
276856
- }
276857
- if (params.end_line !== void 0 && params.end_line < 1) {
276858
- return "end_line must be at least 1";
276859
- }
276860
277023
  if (params.start_line !== void 0 && params.end_line !== void 0 && params.start_line > params.end_line) {
276861
277024
  return "start_line cannot be greater than end_line";
276862
277025
  }
@@ -283127,10 +283290,10 @@ var Ignore = class {
283127
283290
  ignored(p) {
283128
283291
  const fullpath = p.fullpath();
283129
283292
  const fullpaths = `${fullpath}/`;
283130
- const relative12 = p.relative() || ".";
283131
- const relatives = `${relative12}/`;
283293
+ const relative11 = p.relative() || ".";
283294
+ const relatives = `${relative11}/`;
283132
283295
  for (const m of this.relative) {
283133
- if (m.match(relative12) || m.match(relatives))
283296
+ if (m.match(relative11) || m.match(relatives))
283134
283297
  return true;
283135
283298
  }
283136
283299
  for (const m of this.absolute) {
@@ -283141,9 +283304,9 @@ var Ignore = class {
283141
283304
  }
283142
283305
  childrenIgnored(p) {
283143
283306
  const fullpath = p.fullpath() + "/";
283144
- const relative12 = (p.relative() || ".") + "/";
283307
+ const relative11 = (p.relative() || ".") + "/";
283145
283308
  for (const m of this.relativeChildren) {
283146
- if (m.match(relative12))
283309
+ if (m.match(relative11))
283147
283310
  return true;
283148
283311
  }
283149
283312
  for (const m of this.absoluteChildren) {
@@ -284255,12 +284418,24 @@ var GrepToolInvocation = class extends BaseToolInvocation {
284255
284418
  } else {
284256
284419
  searchLocationDescription = `in path "${searchDirDisplay}"`;
284257
284420
  }
284258
- return await formatGrepResults(
284421
+ const result2 = await formatGrepResults(
284259
284422
  allMatches,
284260
284423
  this.params,
284261
284424
  searchLocationDescription,
284262
284425
  totalMaxMatches
284263
284426
  );
284427
+ return {
284428
+ ...result2,
284429
+ display: {
284430
+ name: this._toolDisplayName,
284431
+ description: this.getDescription(),
284432
+ resultSummary: result2.returnDisplay.summary,
284433
+ result: {
284434
+ type: "text",
284435
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
284436
+ }
284437
+ }
284438
+ };
284264
284439
  } catch (error40) {
284265
284440
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
284266
284441
  const errorMessage = getErrorMessage(error40);
@@ -284791,12 +284966,24 @@ var GrepToolInvocation2 = class extends BaseToolInvocation {
284791
284966
  timeoutController.signal
284792
284967
  );
284793
284968
  const searchLocationDescription = `in path "${searchDirDisplay}"`;
284794
- return await formatGrepResults(
284969
+ const result2 = await formatGrepResults(
284795
284970
  allMatches,
284796
284971
  this.params,
284797
284972
  searchLocationDescription,
284798
284973
  totalMaxMatches
284799
284974
  );
284975
+ return {
284976
+ ...result2,
284977
+ display: {
284978
+ name: this._toolDisplayName,
284979
+ description: this.getDescription(),
284980
+ resultSummary: result2.returnDisplay.summary,
284981
+ result: {
284982
+ type: "text",
284983
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
284984
+ }
284985
+ }
284986
+ };
284800
284987
  } catch (error40) {
284801
284988
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
284802
284989
  const errorMessage = getErrorMessage(error40);
@@ -288606,8 +288793,18 @@ ${result2.output}`;
288606
288793
  ...executionError
288607
288794
  };
288608
288795
  }
288796
+ const displayResultSummary = result2.backgrounded ? `PID: ${result2.pid}` : result2.exitCode !== null && result2.exitCode !== 0 ? `Exit Code: ${result2.exitCode}` : void 0;
288609
288797
  return {
288610
288798
  llmContent,
288799
+ display: {
288800
+ name: "Shell",
288801
+ description: this.getDescription(),
288802
+ resultSummary: displayResultSummary,
288803
+ result: typeof returnDisplay === "string" ? { type: "text", text: returnDisplay } : (
288804
+ // TODO: Add support for terminal display type (AnsiOutput)
288805
+ void 0
288806
+ )
288807
+ },
288611
288808
  returnDisplay,
288612
288809
  data,
288613
288810
  ...executionError
@@ -294844,6 +295041,11 @@ Strategic Intent: ${strategicIntent.trim()}`;
294844
295041
  }
294845
295042
  return {
294846
295043
  llmContent,
295044
+ display: {
295045
+ format: "notice",
295046
+ name: title || UPDATE_TOPIC_DISPLAY_NAME,
295047
+ description: this.getDescription()
295048
+ },
294847
295049
  returnDisplay
294848
295050
  };
294849
295051
  }
@@ -295310,6 +295512,9 @@ var GeminiChat = class {
295310
295512
  lastPromptTokenCount;
295311
295513
  callCounter = 0;
295312
295514
  agentHistory;
295515
+ get loopContext() {
295516
+ return this.context;
295517
+ }
295313
295518
  async initialize(resumedSessionData, kind = "main") {
295314
295519
  await this.chatRecordingService.initialize(resumedSessionData, kind);
295315
295520
  }
@@ -295626,10 +295831,11 @@ var GeminiChat = class {
295626
295831
  lastModelToUse = modelToUse;
295627
295832
  lastConfig = config2;
295628
295833
  lastContentsToUse = contentsToUse;
295834
+ const finalContents = stripToolCallIdPrefixes(contentsToUse);
295629
295835
  return this.context.config.getContentGenerator().generateContentStream(
295630
295836
  {
295631
295837
  model: modelToUse,
295632
- contents: contentsToUse,
295838
+ contents: finalContents,
295633
295839
  config: config2
295634
295840
  },
295635
295841
  prompt_id,
@@ -295811,7 +296017,9 @@ This error was probably caused by cyclic schema references in one of the followi
295811
296017
  const finalFunctionCallsMap = /* @__PURE__ */ new Map();
295812
296018
  const legacyFunctionCalls = [];
295813
296019
  const callIndexToId = /* @__PURE__ */ new Map();
296020
+ let runningFunctionCallCounter = 0;
295814
296021
  for await (const chunk of streamResponse) {
296022
+ const currentChunkStartCounter = runningFunctionCallCounter;
295815
296023
  const candidateWithReason = chunk?.candidates?.find(
295816
296024
  (candidate) => candidate.finishReason
295817
296025
  );
@@ -295822,20 +296030,32 @@ This error was probably caused by cyclic schema references in one of the followi
295822
296030
  if (this.context.config.isContextManagementEnabled()) {
295823
296031
  for (let i3 = 0; i3 < chunk.functionCalls.length; i3++) {
295824
296032
  const fnCall = chunk.functionCalls[i3];
296033
+ const globalIndex = currentChunkStartCounter + i3;
295825
296034
  if (!fnCall.id) {
295826
- let id = callIndexToId.get(i3);
296035
+ let id = callIndexToId.get(globalIndex);
295827
296036
  if (!id) {
295828
296037
  id = `synth_${this.context.promptId}_${Date.now()}_${this.callCounter++}`;
295829
- callIndexToId.set(i3, id);
296038
+ callIndexToId.set(globalIndex, id);
295830
296039
  debugLogger.log(
295831
- `[GeminiChat] Assigned synthetic ID: ${id} to tool at index ${i3}: ${fnCall.name}`
296040
+ `[GeminiChat] Assigned synthetic ID: ${id} to tool at index ${globalIndex}: ${fnCall.name}`
295832
296041
  );
295833
296042
  }
295834
296043
  fnCall.id = id;
295835
296044
  }
296045
+ const name3 = fnCall.name?.trim() || "generic_tool";
296046
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
296047
+ fnCall.id = `${name3}__${fnCall.id}`;
296048
+ }
295836
296049
  finalFunctionCallsMap.set(fnCall.id, fnCall);
295837
296050
  }
296051
+ runningFunctionCallCounter += chunk.functionCalls.length;
295838
296052
  } else {
296053
+ for (const fnCall of chunk.functionCalls) {
296054
+ const name3 = fnCall.name?.trim() || "generic_tool";
296055
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
296056
+ fnCall.id = `${name3}__${fnCall.id}`;
296057
+ }
296058
+ }
295839
296059
  legacyFunctionCalls.push(...chunk.functionCalls);
295840
296060
  }
295841
296061
  }
@@ -295849,16 +296069,19 @@ This error was probably caused by cyclic schema references in one of the followi
295849
296069
  if (content.parts.some((part) => part.functionCall)) {
295850
296070
  hasToolCall = true;
295851
296071
  }
296072
+ let localFunctionCallCounter = 0;
295852
296073
  modelResponseParts.push(
295853
296074
  ...content.parts.filter((part) => !part.thought).map((part) => {
295854
296075
  if (!this.context.config.isContextManagementEnabled()) {
295855
296076
  return part;
295856
296077
  }
296078
+ let callIndex;
296079
+ if (part.functionCall) {
296080
+ callIndex = currentChunkStartCounter + localFunctionCallCounter++;
296081
+ }
295857
296082
  return {
295858
296083
  ...part,
295859
- callIndex: chunk.functionCalls?.findIndex(
295860
- (fc) => fc.name === part.functionCall?.name
295861
- )
296084
+ callIndex
295862
296085
  };
295863
296086
  })
295864
296087
  );
@@ -296028,6 +296251,95 @@ function isSchemaDepthError(errorMessage) {
296028
296251
  function isInvalidArgumentError(errorMessage) {
296029
296252
  return errorMessage.includes("Request contains an invalid argument");
296030
296253
  }
296254
+ function stripToolCallIdPrefixes(contents) {
296255
+ return contents.map((content) => ({
296256
+ ...content,
296257
+ parts: (content.parts || []).map((part) => {
296258
+ const newPart = { ...part };
296259
+ if (newPart.functionCall) {
296260
+ const fc = newPart.functionCall;
296261
+ const name3 = fc.name?.trim() || "generic_tool";
296262
+ if (fc.id && fc.id.startsWith(`${name3}__`)) {
296263
+ newPart.functionCall = {
296264
+ name: fc.name,
296265
+ args: fc.args,
296266
+ id: fc.id.substring(name3.length + 2)
296267
+ };
296268
+ }
296269
+ }
296270
+ if (newPart.functionResponse) {
296271
+ const fr = newPart.functionResponse;
296272
+ const name3 = fr.name?.trim() || "generic_tool";
296273
+ if (fr.id && fr.id.startsWith(`${name3}__`)) {
296274
+ newPart.functionResponse = {
296275
+ name: fr.name,
296276
+ response: fr.response,
296277
+ id: fr.id.substring(name3.length + 2)
296278
+ };
296279
+ }
296280
+ }
296281
+ return newPart;
296282
+ })
296283
+ }));
296284
+ }
296285
+
296286
+ // packages/core/src/agent/tool-display-utils.ts
296287
+ function populateToolDisplay({
296288
+ name: name3,
296289
+ invocation,
296290
+ resultDisplay,
296291
+ displayName,
296292
+ display: prevDisplay
296293
+ }) {
296294
+ const display = {
296295
+ name: displayName || name3,
296296
+ description: invocation?.getDescription?.(),
296297
+ ...prevDisplay
296298
+ };
296299
+ if (resultDisplay !== void 0 && display.result === void 0) {
296300
+ display.result = toolResultDisplayToDisplayContent(resultDisplay);
296301
+ }
296302
+ return display;
296303
+ }
296304
+ function toolResultDisplayToDisplayContent(resultDisplay) {
296305
+ if (typeof resultDisplay === "string") {
296306
+ return { type: "text", text: resultDisplay };
296307
+ }
296308
+ if (typeof resultDisplay === "object" && resultDisplay !== null && "fileDiff" in resultDisplay && "newContent" in resultDisplay) {
296309
+ return {
296310
+ type: "diff",
296311
+ path: resultDisplay.filePath || resultDisplay.fileName,
296312
+ beforeText: resultDisplay.originalContent ?? "",
296313
+ afterText: resultDisplay.newContent
296314
+ };
296315
+ }
296316
+ return {
296317
+ type: "text",
296318
+ text: JSON.stringify(resultDisplay)
296319
+ };
296320
+ }
296321
+ function renderDisplayDiff(diff) {
296322
+ return createPatch(
296323
+ diff.path || "file",
296324
+ diff.beforeText,
296325
+ diff.afterText,
296326
+ "Original",
296327
+ "Modified",
296328
+ { context: 3 }
296329
+ );
296330
+ }
296331
+ function displayContentToString(display) {
296332
+ if (!display) {
296333
+ return void 0;
296334
+ }
296335
+ if (display.type === "text") {
296336
+ return display.text;
296337
+ }
296338
+ if (display.type === "diff") {
296339
+ return renderDisplayDiff(display);
296340
+ }
296341
+ return JSON.stringify(display);
296342
+ }
296031
296343
 
296032
296344
  // packages/core/src/core/turn.ts
296033
296345
  var GeminiEventType = /* @__PURE__ */ ((GeminiEventType2) => {
@@ -296194,13 +296506,33 @@ ${[...this.pendingCitations].sort().join("\n")}`
296194
296506
  }
296195
296507
  }
296196
296508
  handlePendingFunctionCall(fnCall, traceId) {
296197
- const name3 = fnCall.name || "undefined_tool_name";
296509
+ const name3 = fnCall.name?.trim() || "generic_tool";
296198
296510
  const args2 = fnCall.args || {};
296199
- const callId = fnCall.id ?? (this.chat.context.config.isContextManagementEnabled() ? `synth_${this.prompt_id}_${Date.now()}_${this.callCounter++}` : `${name3}_${Date.now()}_${this.callCounter++}`);
296511
+ const rawCallId = fnCall.id ?? (this.chat.context.config.isContextManagementEnabled() ? `synth_${this.prompt_id}_${Date.now()}_${this.callCounter++}` : `${name3}_${Date.now()}_${this.callCounter++}`);
296512
+ const callId = rawCallId.startsWith(`${name3}__`) ? rawCallId : `${name3}__${rawCallId}`;
296513
+ fnCall.id = callId;
296514
+ const tool = this.chat.loopContext.toolRegistry.getTool(name3);
296515
+ let display;
296516
+ if (tool) {
296517
+ let invocation;
296518
+ try {
296519
+ invocation = tool.build(args2);
296520
+ } catch {
296521
+ }
296522
+ display = populateToolDisplay({
296523
+ name: name3,
296524
+ invocation,
296525
+ displayName: tool.displayName
296526
+ });
296527
+ if (!display.description) {
296528
+ display.description = tool.description;
296529
+ }
296530
+ }
296200
296531
  const toolCallRequest = {
296201
296532
  callId,
296202
296533
  name: name3,
296203
296534
  args: args2,
296535
+ display,
296204
296536
  isClientInitiated: false,
296205
296537
  prompt_id: this.prompt_id,
296206
296538
  traceId
@@ -296337,7 +296669,7 @@ Use the following guidelines to optimize your search and read patterns.
296337
296669
  - Prefer using tools like ${GREP_TOOL_NAME} to identify points of interest instead of reading lots of files individually.
296338
296670
  - If you need to read multiple ranges in a file, do so parallel, in as few turns as possible.
296339
296671
  - It is more important to reduce extra turns, but please also try to minimize unnecessarily large file reads and search results, when doing so doesn't result in extra turns. Do this by always providing conservative limits and scopes to tools like ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME}.
296340
- - ${READ_FILE_TOOL_NAME} fails if ${EDIT_PARAM_OLD_STRING} is ambiguous, causing extra turns. Take care to read enough with ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME} to make the edit unambiguous.
296672
+ - ${EDIT_TOOL_NAME} fails if ${EDIT_PARAM_OLD_STRING} is ambiguous, causing extra turns. Take care to read enough with ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME} to make the edit unambiguous.
296341
296673
  - You can compensate for the risk of missing results with scoped or limited searches by doing multiple searches in parallel.
296342
296674
  - Your primary goal is still to do your best quality work. Efficiency is an important, but secondary concern.
296343
296675
  </guidelines>
@@ -298930,6 +299262,13 @@ var SubagentActivityErrorType = /* @__PURE__ */ ((SubagentActivityErrorType2) =>
298930
299262
  })(SubagentActivityErrorType || {});
298931
299263
  var SUBAGENT_REJECTED_ERROR_PREFIX = "User rejected this operation.";
298932
299264
  var SUBAGENT_CANCELLED_ERROR_MESSAGE = "Request cancelled.";
299265
+ var SubagentState = /* @__PURE__ */ ((SubagentState2) => {
299266
+ SubagentState2["RUNNING"] = "running";
299267
+ SubagentState2["COMPLETED"] = "completed";
299268
+ SubagentState2["ERROR"] = "error";
299269
+ SubagentState2["CANCELLED"] = "cancelled";
299270
+ return SubagentState2;
299271
+ })(SubagentState || {});
298933
299272
  function isSubagentProgress(obj) {
298934
299273
  return typeof obj === "object" && obj !== null && "isSubagentProgress" in obj && obj.isSubagentProgress === true;
298935
299274
  }
@@ -303280,7 +303619,7 @@ var A2AAuthProviderFactory = class _A2AAuthProviderFactory {
303280
303619
  return provider;
303281
303620
  }
303282
303621
  case "oauth2": {
303283
- const { OAuth2AuthProvider } = await import("./oauth2-provider-RQNNLGWV.js");
303622
+ const { OAuth2AuthProvider } = await import("./oauth2-provider-TZF6EZRX.js");
303284
303623
  const provider = new OAuth2AuthProvider(
303285
303624
  authConfig,
303286
303625
  options.agentName ?? "unknown",
@@ -304629,10 +304968,12 @@ var SchedulerStateManager = class {
304629
304968
  updateArgs(callId, newArgs, newInvocation) {
304630
304969
  const call = this.activeCalls.get(callId);
304631
304970
  if (!call || call.status === "error" /* Error */) return;
304971
+ const display = call.request.display ? { ...call.request.display } : { name: call.request.name };
304972
+ display.description = newInvocation.getDescription();
304632
304973
  this.activeCalls.set(
304633
304974
  callId,
304634
304975
  this.patchCall(call, {
304635
- request: { ...call.request, args: newArgs },
304976
+ request: { ...call.request, args: newArgs, display },
304636
304977
  invocation: newInvocation
304637
304978
  })
304638
304979
  );
@@ -307016,9 +307357,41 @@ function createNodeTruncationProcessor(id, env2, options) {
307016
307357
  import { randomUUID as randomUUID7 } from "node:crypto";
307017
307358
 
307018
307359
  // packages/core/src/context/graph/types.ts
307360
+ var NodeType = /* @__PURE__ */ ((NodeType2) => {
307361
+ NodeType2["USER_PROMPT"] = "USER_PROMPT";
307362
+ NodeType2["SYSTEM_EVENT"] = "SYSTEM_EVENT";
307363
+ NodeType2["AGENT_THOUGHT"] = "AGENT_THOUGHT";
307364
+ NodeType2["TOOL_EXECUTION"] = "TOOL_EXECUTION";
307365
+ NodeType2["MASKED_TOOL"] = "MASKED_TOOL";
307366
+ NodeType2["AGENT_YIELD"] = "AGENT_YIELD";
307367
+ NodeType2["SNAPSHOT"] = "SNAPSHOT";
307368
+ NodeType2["ROLLING_SUMMARY"] = "ROLLING_SUMMARY";
307369
+ return NodeType2;
307370
+ })(NodeType || {});
307371
+ function isAgentThought(node) {
307372
+ return node.type === "AGENT_THOUGHT" /* AGENT_THOUGHT */;
307373
+ }
307374
+ function isAgentYield(node) {
307375
+ return node.type === "AGENT_YIELD" /* AGENT_YIELD */;
307376
+ }
307019
307377
  function isToolExecution(node) {
307020
307378
  return node.type === "TOOL_EXECUTION" /* TOOL_EXECUTION */;
307021
307379
  }
307380
+ function isMaskedTool(node) {
307381
+ return node.type === "MASKED_TOOL" /* MASKED_TOOL */;
307382
+ }
307383
+ function isUserPrompt(node) {
307384
+ return node.type === "USER_PROMPT" /* USER_PROMPT */;
307385
+ }
307386
+ function isSystemEvent(node) {
307387
+ return node.type === "SYSTEM_EVENT" /* SYSTEM_EVENT */;
307388
+ }
307389
+ function isSnapshot(node) {
307390
+ return node.type === "SNAPSHOT" /* SNAPSHOT */;
307391
+ }
307392
+ function isRollingSummary(node) {
307393
+ return node.type === "ROLLING_SUMMARY" /* ROLLING_SUMMARY */;
307394
+ }
307022
307395
 
307023
307396
  // packages/core/src/context/processors/nodeDistillationProcessor.ts
307024
307397
  var NodeDistillationProcessorOptionsSchema = {
@@ -307161,43 +307534,289 @@ function createNodeDistillationProcessor(id, env2, options) {
307161
307534
  }
307162
307535
 
307163
307536
  // packages/core/src/context/processors/stateSnapshotProcessor.ts
307164
- import { randomUUID as randomUUID8 } from "node:crypto";
307537
+ import { randomUUID as randomUUID9 } from "node:crypto";
307538
+
307539
+ // packages/core/src/context/utils/formatNodesForLlm.ts
307540
+ function getSemanticToolWrapper(toolName) {
307541
+ if (toolName.includes("search") || toolName.includes("grep"))
307542
+ return `SEARCH RESULTS`;
307543
+ if (toolName.includes("list") || toolName.includes("dir"))
307544
+ return `WORKSPACE STRUCTURE`;
307545
+ if (toolName.includes("shell") || toolName.includes("cmd"))
307546
+ return `SHELL EXECUTION`;
307547
+ if (toolName.includes("read") || toolName.includes("fetch"))
307548
+ return `FILE/WEB CONTENT`;
307549
+ return `TOOL RESPONSE`;
307550
+ }
307551
+ function formatNodesForLlm(nodes, options = {}) {
307552
+ const maxToolChars = options.maxToolResponseChars ?? 2e3;
307553
+ let transcript = "";
307554
+ const uniqueTurns = Array.from(
307555
+ new Set(nodes.map((n3) => n3.turnId).filter(Boolean))
307556
+ );
307557
+ for (const node of nodes) {
307558
+ const payload = node.payload;
307559
+ let nodeContent = "";
307560
+ if (payload.text) {
307561
+ nodeContent = payload.text;
307562
+ } else if (payload.functionCall) {
307563
+ nodeContent = `CALL: ${payload.functionCall.name}(${JSON.stringify(payload.functionCall.args)})`;
307564
+ } else if (payload.functionResponse) {
307565
+ const toolName = payload.functionResponse.name || "unknown_tool";
307566
+ const rawResponse = JSON.stringify(payload.functionResponse.response);
307567
+ const semanticWrapper = getSemanticToolWrapper(toolName);
307568
+ let formattedResponse = rawResponse;
307569
+ if (rawResponse.length > maxToolChars) {
307570
+ const half = Math.floor(maxToolChars / 2);
307571
+ const truncatedCount = rawResponse.length - maxToolChars;
307572
+ formattedResponse = `${rawResponse.substring(0, half)}... [TRUNCATED ${truncatedCount} chars] ...${rawResponse.substring(rawResponse.length - half)}`;
307573
+ }
307574
+ nodeContent = `[${semanticWrapper} (${toolName})]: ${formattedResponse}`;
307575
+ } else {
307576
+ nodeContent = JSON.stringify(payload);
307577
+ }
307578
+ const role = (node.role || "system").toUpperCase();
307579
+ let turnMarker = "";
307580
+ if (node.turnId) {
307581
+ const idx = uniqueTurns.indexOf(node.turnId);
307582
+ if (idx !== -1) {
307583
+ const relativeIdx = idx - (uniqueTurns.length - 1);
307584
+ turnMarker = `[Turn ${relativeIdx}] `;
307585
+ }
307586
+ }
307587
+ transcript += `${turnMarker}[${role}] [${node.type}]: ${nodeContent}
307588
+ `;
307589
+ }
307590
+ return transcript;
307591
+ }
307165
307592
 
307166
307593
  // packages/core/src/context/utils/snapshotGenerator.ts
307594
+ import { randomUUID as randomUUID8 } from "node:crypto";
307595
+ function isStringArray(value) {
307596
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
307597
+ }
307598
+ function isNumberArray(value) {
307599
+ return Array.isArray(value) && value.every((item) => typeof item === "number");
307600
+ }
307601
+ function isTaskArray(value) {
307602
+ return Array.isArray(value) && value.every((item) => {
307603
+ if (!isRecord(item)) return false;
307604
+ const id = item["id"];
307605
+ const desc = item["description"];
307606
+ return typeof id === "string" && typeof desc === "string";
307607
+ });
307608
+ }
307609
+ function isString(value) {
307610
+ return typeof value === "string";
307611
+ }
307612
+ function findLatestSnapshotBaseline(targets) {
307613
+ const lastSnapshotNode = [...targets].reverse().find((n3) => n3.type === "SNAPSHOT" /* SNAPSHOT */ && n3.payload.text);
307614
+ if (lastSnapshotNode?.payload.text) {
307615
+ return {
307616
+ text: lastSnapshotNode.payload.text,
307617
+ abstractsIds: lastSnapshotNode.abstractsIds ? [...lastSnapshotNode.abstractsIds] : [],
307618
+ id: lastSnapshotNode.id
307619
+ };
307620
+ }
307621
+ return void 0;
307622
+ }
307167
307623
  var SnapshotGenerator = class {
307168
307624
  constructor(env2) {
307169
307625
  this.env = env2;
307170
307626
  }
307171
- async synthesizeSnapshot(nodes, systemInstruction) {
307172
- const systemPrompt = systemInstruction ?? `You are an expert Context Memory Manager. You will be provided with a raw transcript of older conversation turns between a user and an AI assistant.
307173
- Your task is to synthesize these turns into a single, dense, factual snapshot that preserves all critical context, preferences, active tasks, and factual knowledge.
307627
+ async synthesizeSnapshot(nodes, previousStateJson, options = {}) {
307628
+ const emptyState = {
307629
+ active_tasks: [],
307630
+ discovered_facts: [],
307631
+ constraints_and_preferences: [],
307632
+ recent_arc: []
307633
+ };
307634
+ let previousState = emptyState;
307635
+ if (previousStateJson) {
307636
+ try {
307637
+ const parsed = JSON.parse(previousStateJson);
307638
+ if (isRecord(parsed)) {
307639
+ let loadedArc = [];
307640
+ if (isStringArray(parsed["recent_arc"])) {
307641
+ loadedArc = parsed["recent_arc"];
307642
+ } else if (isString(parsed["summary"]) && parsed["summary"]) {
307643
+ loadedArc = [parsed["summary"]];
307644
+ }
307645
+ previousState = {
307646
+ active_tasks: isTaskArray(parsed["active_tasks"]) ? parsed["active_tasks"] : [],
307647
+ discovered_facts: isStringArray(parsed["discovered_facts"]) ? parsed["discovered_facts"] : [],
307648
+ constraints_and_preferences: isStringArray(
307649
+ parsed["constraints_and_preferences"]
307650
+ ) ? parsed["constraints_and_preferences"] : [],
307651
+ recent_arc: loadedArc
307652
+ };
307653
+ }
307654
+ } catch {
307655
+ }
307656
+ }
307657
+ let pressureWarning = "";
307658
+ const stateString = JSON.stringify(previousState);
307659
+ const estimatedTokens = this.env.tokenCalculator.estimateTokensForString(stateString);
307660
+ const maxTokens = options.maxStateTokens ?? 4e3;
307661
+ if (estimatedTokens > maxTokens * 0.8) {
307662
+ pressureWarning = `
307174
307663
 
307175
- Discard conversational filler, pleasantries, and redundant back-and-forth iterations. Output ONLY the raw factual snapshot, formatted compactly. Do not include markdown wrappers, prefixes like "Here is the snapshot", or conversational elements.`;
307176
- let userPromptText = "TRANSCRIPT TO SNAPSHOT:\n\n";
307177
- for (const node of nodes) {
307178
- const payload = node.payload;
307179
- let nodeContent = "";
307180
- if (payload.text) {
307181
- nodeContent = payload.text;
307182
- } else if (payload.functionCall) {
307183
- nodeContent = `CALL: ${payload.functionCall.name}(${JSON.stringify(payload.functionCall.args)})`;
307184
- } else if (payload.functionResponse) {
307185
- nodeContent = `RESPONSE: ${JSON.stringify(payload.functionResponse.response)}`;
307186
- }
307187
- userPromptText += `[${node.type}]: ${nodeContent}
307188
- `;
307664
+ [CRITICAL WARNING]: The Master State is currently at ${(estimatedTokens / maxTokens * 100).toFixed(0)}% of its maximum capacity! You MUST aggressively prune obsolete, irrelevant, or overly granular facts and constraints using \`obsolete_fact_indices\` and \`obsolete_constraint_indices\`.`;
307189
307665
  }
307190
- const response = await this.env.llmClient.generateContent({
307191
- role: "utility_state_snapshot_processor" /* UTILITY_STATE_SNAPSHOT_PROCESSOR */,
307192
- modelConfigKey: { model: "gemini-3-flash-base" },
307193
- contents: [{ role: "user", parts: [{ text: userPromptText }] }],
307194
- systemInstruction: { role: "system", parts: [{ text: systemPrompt }] },
307195
- promptId: this.env.promptId,
307196
- abortSignal: new AbortController().signal
307197
- });
307198
- const candidate = response.candidates?.[0];
307199
- const textPart = candidate?.content?.parts?.[0];
307200
- return textPart?.text || "";
307666
+ const systemPrompt = `You are an expert Context Memory Manager. You maintain the long-term "Master State" of the AI agent's memory.
307667
+ You will be provided with the CURRENT Master State and a raw transcript of new conversation turns.
307668
+ Your task is to generate a JSON Delta Patch representing what has changed in the transcript.${pressureWarning}
307669
+
307670
+ CRITICAL OPERATIONAL RULES:
307671
+ 1. FACTS: Extract explicit empirical facts (file paths, exact error codes, specific configs).
307672
+ 2. PRUNING: Keep facts dense. Use obsolete indices to aggressively delete facts that are no longer relevant to the current objective.
307673
+ 3. TASKS: Add any new active user requests to "new_tasks".
307674
+ 4. TASK RESOLUTION: A task may ONLY be placed in "resolved_task_ids" if a success message or explicit confirmation was provided in the transcript. If the task was being worked on but no final confirmation exists, it MUST remain active. Do not prematurely resolve tasks.`;
307675
+ const userPromptText = `CURRENT MASTER STATE:
307676
+ ${JSON.stringify(previousState, null, 2)}
307677
+
307678
+ TRANSCRIPT OF NEW TURNS:
307679
+ ${formatNodesForLlm(nodes)}`;
307680
+ const patchSchema = {
307681
+ type: "object",
307682
+ properties: {
307683
+ new_facts: {
307684
+ type: "array",
307685
+ items: { type: "string" },
307686
+ description: "New specific, empirical facts discovered in this transcript chunk."
307687
+ },
307688
+ new_constraints: {
307689
+ type: "array",
307690
+ items: { type: "string" },
307691
+ description: "New specific rules or instructions provided by the user in this chunk."
307692
+ },
307693
+ new_tasks: {
307694
+ type: "array",
307695
+ items: {
307696
+ type: "object",
307697
+ properties: {
307698
+ description: {
307699
+ type: "string",
307700
+ description: "The task goal/description."
307701
+ }
307702
+ }
307703
+ }
307704
+ },
307705
+ resolved_task_ids: {
307706
+ type: "array",
307707
+ items: { type: "string" },
307708
+ description: "IDs of tasks from the CURRENT MASTER STATE that were explicitly completed or abandoned in this transcript chunk."
307709
+ },
307710
+ obsolete_fact_indices: {
307711
+ type: "array",
307712
+ items: { type: "number" },
307713
+ description: "Array indices of facts from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
307714
+ },
307715
+ obsolete_constraint_indices: {
307716
+ type: "array",
307717
+ items: { type: "number" },
307718
+ description: "Array indices of constraints from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
307719
+ },
307720
+ chronological_summary: {
307721
+ type: "string",
307722
+ description: "A 1-2 sentence summary of the mechanical actions taken in this transcript chunk."
307723
+ }
307724
+ }
307725
+ };
307726
+ let patch = {};
307727
+ try {
307728
+ const result2 = await this.env.llmClient.generateJson({
307729
+ role: "utility_state_snapshot_processor" /* UTILITY_STATE_SNAPSHOT_PROCESSOR */,
307730
+ modelConfigKey: { model: "context-snapshotter" },
307731
+ contents: [{ role: "user", parts: [{ text: userPromptText }] }],
307732
+ systemInstruction: { role: "system", parts: [{ text: systemPrompt }] },
307733
+ schema: patchSchema,
307734
+ promptId: this.env.promptId,
307735
+ abortSignal: new AbortController().signal
307736
+ });
307737
+ if (isRecord(result2)) {
307738
+ patch = result2;
307739
+ }
307740
+ } catch {
307741
+ return JSON.stringify(previousState);
307742
+ }
307743
+ const newState = {
307744
+ active_tasks: [...previousState.active_tasks],
307745
+ discovered_facts: [...previousState.discovered_facts],
307746
+ constraints_and_preferences: [
307747
+ ...previousState.constraints_and_preferences
307748
+ ],
307749
+ recent_arc: [...previousState.recent_arc]
307750
+ };
307751
+ const resolvedIds = patch["resolved_task_ids"];
307752
+ if (isStringArray(resolvedIds)) {
307753
+ const resolvedSet = new Set(resolvedIds);
307754
+ newState.active_tasks = newState.active_tasks.filter(
307755
+ (t2) => !resolvedSet.has(t2.id)
307756
+ );
307757
+ }
307758
+ const obsFacts = patch["obsolete_fact_indices"];
307759
+ if (isNumberArray(obsFacts)) {
307760
+ const dropSet = new Set(obsFacts);
307761
+ newState.discovered_facts = newState.discovered_facts.filter(
307762
+ (_, i3) => !dropSet.has(i3)
307763
+ );
307764
+ }
307765
+ const obsConstraints = patch["obsolete_constraint_indices"];
307766
+ if (isNumberArray(obsConstraints)) {
307767
+ const dropSet = new Set(obsConstraints);
307768
+ newState.constraints_and_preferences = newState.constraints_and_preferences.filter((_, i3) => !dropSet.has(i3));
307769
+ }
307770
+ const newTasks = patch["new_tasks"];
307771
+ if (Array.isArray(newTasks)) {
307772
+ for (const t2 of newTasks) {
307773
+ if (isRecord(t2)) {
307774
+ const desc = t2["description"];
307775
+ if (typeof desc === "string" && desc) {
307776
+ newState.active_tasks.push({
307777
+ id: `task_${randomUUID8().slice(0, 8)}`,
307778
+ description: desc
307779
+ });
307780
+ }
307781
+ }
307782
+ }
307783
+ }
307784
+ const newFacts = patch["new_facts"];
307785
+ if (isStringArray(newFacts)) {
307786
+ newState.discovered_facts.push(...newFacts);
307787
+ }
307788
+ const newConstraints = patch["new_constraints"];
307789
+ if (isStringArray(newConstraints)) {
307790
+ newState.constraints_and_preferences.push(...newConstraints);
307791
+ }
307792
+ const chronoSummary = patch["chronological_summary"];
307793
+ if (typeof chronoSummary === "string" && chronoSummary) {
307794
+ newState.recent_arc.push(chronoSummary);
307795
+ const maxTurns = options.maxSummaryTurns ?? 5;
307796
+ if (newState.recent_arc.length > maxTurns) {
307797
+ newState.recent_arc = newState.recent_arc.slice(-maxTurns);
307798
+ }
307799
+ }
307800
+ let currentTokens = this.env.tokenCalculator.estimateTokensForString(
307801
+ JSON.stringify(newState)
307802
+ );
307803
+ while (currentTokens > maxTokens) {
307804
+ if (newState.discovered_facts.length > 0) {
307805
+ newState.discovered_facts.shift();
307806
+ } else if (newState.constraints_and_preferences.length > 0) {
307807
+ newState.constraints_and_preferences.shift();
307808
+ } else if (newState.recent_arc.length > 0) {
307809
+ newState.recent_arc.shift();
307810
+ } else if (newState.active_tasks.length > 0) {
307811
+ newState.active_tasks.shift();
307812
+ } else {
307813
+ break;
307814
+ }
307815
+ currentTokens = this.env.tokenCalculator.estimateTokensForString(
307816
+ JSON.stringify(newState)
307817
+ );
307818
+ }
307819
+ return JSON.stringify(newState);
307201
307820
  }
307202
307821
  };
307203
307822
 
@@ -307212,7 +307831,9 @@ var StateSnapshotProcessorOptionsSchema = {
307212
307831
  },
307213
307832
  freeTokensTarget: { type: "number", nullable: true },
307214
307833
  model: { type: "string", nullable: true },
307215
- systemInstruction: { type: "string", nullable: true }
307834
+ systemInstruction: { type: "string", nullable: true },
307835
+ maxSummaryTurns: { type: "number", nullable: true },
307836
+ maxStateTokens: { type: "number", nullable: true }
307216
307837
  },
307217
307838
  required: []
307218
307839
  };
@@ -307240,7 +307861,7 @@ function createStateSnapshotProcessor(id, env2, options) {
307240
307861
  const targetIds = new Set(targets.map((t2) => t2.id));
307241
307862
  const isValid = consumedIds.every((id2) => targetIds.has(id2));
307242
307863
  if (isValid) {
307243
- const newId = randomUUID8();
307864
+ const newId = randomUUID9();
307244
307865
  const snapshotNode = {
307245
307866
  id: newId,
307246
307867
  turnId: newId,
@@ -307283,12 +307904,37 @@ function createStateSnapshotProcessor(id, env2, options) {
307283
307904
  if (deficitAccumulator >= targetTokensToRemove) break;
307284
307905
  }
307285
307906
  if (nodesToSummarize.length < 2) return targets;
307907
+ let previousStateJson = void 0;
307908
+ let baselineIdToConsume = void 0;
307909
+ const baseline = findLatestSnapshotBaseline(targets);
307910
+ if (baseline) {
307911
+ previousStateJson = baseline.text;
307912
+ const summaryIdx = nodesToSummarize.findIndex(
307913
+ (n3) => n3.id === baseline.id
307914
+ );
307915
+ if (summaryIdx !== -1) {
307916
+ baselineIdToConsume = baseline.id;
307917
+ nodesToSummarize.splice(summaryIdx, 1);
307918
+ }
307919
+ } else {
307920
+ debugLogger.log(
307921
+ "[StateSnapshotProcessor] No previous snapshot found in context graph. Initializing new Master State baseline."
307922
+ );
307923
+ }
307286
307924
  try {
307287
307925
  const snapshotText = await generator.synthesizeSnapshot(
307288
307926
  nodesToSummarize,
307289
- options.systemInstruction
307927
+ previousStateJson,
307928
+ {
307929
+ maxSummaryTurns: options.maxSummaryTurns,
307930
+ maxStateTokens: options.maxStateTokens
307931
+ }
307290
307932
  );
307291
- const newId = randomUUID8();
307933
+ const newId = randomUUID9();
307934
+ const consumedIds = nodesToSummarize.map((n3) => n3.id);
307935
+ if (baselineIdToConsume && !consumedIds.includes(baselineIdToConsume)) {
307936
+ consumedIds.push(baselineIdToConsume);
307937
+ }
307292
307938
  const snapshotNode = {
307293
307939
  id: newId,
307294
307940
  turnId: newId,
@@ -307296,9 +307942,8 @@ function createStateSnapshotProcessor(id, env2, options) {
307296
307942
  timestamp: nodesToSummarize[nodesToSummarize.length - 1].timestamp,
307297
307943
  role: "user",
307298
307944
  payload: { text: snapshotText },
307299
- abstractsIds: nodesToSummarize.map((n3) => n3.id)
307945
+ abstractsIds: [...consumedIds]
307300
307946
  };
307301
- const consumedIds = nodesToSummarize.map((n3) => n3.id);
307302
307947
  const returnedNodes = targets.filter(
307303
307948
  (t2) => !consumedIds.includes(t2.id)
307304
307949
  );
@@ -307321,7 +307966,6 @@ function createStateSnapshotProcessor(id, env2, options) {
307321
307966
  }
307322
307967
 
307323
307968
  // packages/core/src/context/processors/stateSnapshotAsyncProcessor.ts
307324
- import { randomUUID as randomUUID9 } from "node:crypto";
307325
307969
  var StateSnapshotAsyncProcessorOptionsSchema = {
307326
307970
  type: "object",
307327
307971
  properties: {
@@ -307330,7 +307974,9 @@ var StateSnapshotAsyncProcessorOptionsSchema = {
307330
307974
  enum: ["accumulate", "point-in-time"],
307331
307975
  nullable: true
307332
307976
  },
307333
- systemInstruction: { type: "string", nullable: true }
307977
+ systemInstruction: { type: "string", nullable: true },
307978
+ maxSummaryTurns: { type: "number", nullable: true },
307979
+ maxStateTokens: { type: "number", nullable: true }
307334
307980
  },
307335
307981
  required: []
307336
307982
  };
@@ -307342,9 +307988,10 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
307342
307988
  process: async ({ targets, inbox }) => {
307343
307989
  if (targets.length === 0) return;
307344
307990
  try {
307345
- let nodesToSummarize = [...targets];
307346
307991
  let previousConsumedIds = [];
307347
307992
  const processorType = options.type ?? "point-in-time";
307993
+ const nodesToSummarize = [...targets];
307994
+ let previousStateJson = void 0;
307348
307995
  if (processorType === "accumulate") {
307349
307996
  const proposedSnapshots = inbox.getMessages("PROPOSED_SNAPSHOT");
307350
307997
  const accumulateSnapshots = proposedSnapshots.filter(
@@ -307357,21 +308004,35 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
307357
308004
  inbox.consume(latest.id);
307358
308005
  env2.inbox.drainConsumed(/* @__PURE__ */ new Set([latest.id]));
307359
308006
  previousConsumedIds = latest.payload.consumedIds;
307360
- const snapshotId = randomUUID9();
307361
- const previousStateNode = {
307362
- id: snapshotId,
307363
- turnId: snapshotId,
307364
- type: "SNAPSHOT" /* SNAPSHOT */,
307365
- timestamp: latest.timestamp,
307366
- role: "user",
307367
- payload: { text: latest.payload.newText }
307368
- };
307369
- nodesToSummarize = [previousStateNode, ...targets];
308007
+ previousStateJson = latest.payload.newText;
308008
+ } else {
308009
+ const baseline = findLatestSnapshotBaseline(targets);
308010
+ if (baseline) {
308011
+ previousStateJson = baseline.text;
308012
+ previousConsumedIds = [...baseline.abstractsIds];
308013
+ } else {
308014
+ debugLogger.log(
308015
+ "[StateSnapshotAsyncProcessor] No previous snapshot found in Inbox or Graph. Initializing new Master State baseline in background."
308016
+ );
308017
+ }
307370
308018
  }
307371
308019
  }
308020
+ if (previousStateJson) {
308021
+ const summaryIdx = nodesToSummarize.findIndex(
308022
+ (n3) => n3.type === "SNAPSHOT" /* SNAPSHOT */ && n3.payload.text === previousStateJson
308023
+ );
308024
+ if (summaryIdx !== -1) {
308025
+ nodesToSummarize.splice(summaryIdx, 1);
308026
+ }
308027
+ }
308028
+ if (nodesToSummarize.length === 0) return;
307372
308029
  const snapshotText = await generator.synthesizeSnapshot(
307373
308030
  nodesToSummarize,
307374
- options.systemInstruction
308031
+ previousStateJson,
308032
+ {
308033
+ maxSummaryTurns: options.maxSummaryTurns,
308034
+ maxStateTokens: options.maxStateTokens
308035
+ }
307375
308036
  );
307376
308037
  const newConsumedIds = [
307377
308038
  ...previousConsumedIds,
@@ -307471,7 +308132,9 @@ var generalistProfile = {
307471
308132
  "StateSnapshotSync",
307472
308133
  env2,
307473
308134
  resolveProcessorOptions(config2, "StateSnapshotSync", {
307474
- target: "max"
308135
+ target: "max",
308136
+ maxStateTokens: 4e3,
308137
+ maxSummaryTurns: 5
307475
308138
  })
307476
308139
  )
307477
308140
  ]
@@ -307487,7 +308150,9 @@ var generalistProfile = {
307487
308150
  "StateSnapshotAsync",
307488
308151
  env2,
307489
308152
  resolveProcessorOptions(config2, "StateSnapshotAsync", {
307490
- type: "accumulate"
308153
+ type: "accumulate",
308154
+ maxStateTokens: 4e3,
308155
+ maxSummaryTurns: 5
307491
308156
  })
307492
308157
  )
307493
308158
  ]
@@ -307695,6 +308360,12 @@ var ContextTracer = class {
307695
308360
  // packages/core/src/context/eventBus.ts
307696
308361
  import { EventEmitter as EventEmitter4 } from "node:events";
307697
308362
  var ContextEventBus = class extends EventEmitter4 {
308363
+ emitTokenGroundTruth(event) {
308364
+ this.emit("TOKEN_GROUND_TRUTH", event);
308365
+ }
308366
+ onTokenGroundTruth(listener) {
308367
+ this.on("TOKEN_GROUND_TRUTH", listener);
308368
+ }
307698
308369
  emitPristineHistoryUpdated(event) {
307699
308370
  this.emit("PRISTINE_HISTORY_UPDATED", event);
307700
308371
  }
@@ -307721,161 +308392,6 @@ var ContextEventBus = class extends EventEmitter4 {
307721
308392
  }
307722
308393
  };
307723
308394
 
307724
- // packages/core/src/context/utils/contextTokenCalculator.ts
307725
- var ContextTokenCalculator = class {
307726
- constructor(charsPerToken, registry2) {
307727
- this.charsPerToken = charsPerToken;
307728
- this.registry = registry2;
307729
- }
307730
- tokenCache = /* @__PURE__ */ new Map();
307731
- /**
307732
- * Estimates tokens for a simple string based on character count.
307733
- * Fast, but inherently inaccurate compared to real model tokenization.
307734
- */
307735
- estimateTokensForString(text) {
307736
- return Math.ceil(text.length / this.charsPerToken);
307737
- }
307738
- /**
307739
- * Fast, simple heuristic conversion from tokens to expected character length.
307740
- * Useful for calculating truncation thresholds.
307741
- */
307742
- tokensToChars(tokens) {
307743
- return tokens * this.charsPerToken;
307744
- }
307745
- /**
307746
- * Pre-calculates and caches the token cost of a newly minted node.
307747
- * Because nodes are immutable, this cost never changes for this node ID.
307748
- */
307749
- /**
307750
- * Removes cached token counts for any nodes that are no longer in the given live set.
307751
- * This prevents unbounded memory growth during long sessions.
307752
- */
307753
- garbageCollectCache(liveNodeIds) {
307754
- for (const [id] of this.tokenCache) {
307755
- if (!liveNodeIds.has(id)) {
307756
- this.tokenCache.delete(id);
307757
- }
307758
- }
307759
- }
307760
- cacheNodeTokens(node) {
307761
- const behavior = this.registry.get(node.type);
307762
- const parts2 = behavior.getEstimatableParts(node);
307763
- const tokens = this.estimateTokensForParts(parts2);
307764
- this.tokenCache.set(node.id, tokens);
307765
- return tokens;
307766
- }
307767
- /**
307768
- * Retrieves the token cost of a single node from the cache.
307769
- * If it misses the cache, it computes it and caches it.
307770
- */
307771
- getTokenCost(node) {
307772
- const cached2 = this.tokenCache.get(node.id);
307773
- if (cached2 !== void 0) return cached2;
307774
- return this.cacheNodeTokens(node);
307775
- }
307776
- /**
307777
- * Calculates a detailed breakdown of tokens by category for a list of nodes.
307778
- * Useful for calibration tracing and debugging overestimation.
307779
- */
307780
- calculateTokenBreakdown(nodes) {
307781
- const breakdown = { total: 0, text: 0, media: 0, tool: 0, overhead: 0 };
307782
- const seenIds = /* @__PURE__ */ new Set();
307783
- const seenTurnIds = /* @__PURE__ */ new Set();
307784
- for (const node of nodes) {
307785
- if (seenIds.has(node.id)) continue;
307786
- seenIds.add(node.id);
307787
- if (node.turnId) {
307788
- if (!seenTurnIds.has(node.turnId)) {
307789
- seenTurnIds.add(node.turnId);
307790
- breakdown.overhead += MSG_OVERHEAD_TOKENS;
307791
- breakdown.total += MSG_OVERHEAD_TOKENS;
307792
- }
307793
- }
307794
- const cost = this.getTokenCost(node);
307795
- breakdown.total += cost;
307796
- const behavior = this.registry.get(node.type);
307797
- const parts2 = behavior.getEstimatableParts(node);
307798
- for (const part of parts2) {
307799
- if (typeof part.text === "string") {
307800
- breakdown.text += estimateTokenCountSync(
307801
- [part],
307802
- 0,
307803
- this.charsPerToken
307804
- );
307805
- } else if (part.inlineData?.mimeType?.startsWith("image/") || part.fileData?.mimeType?.startsWith("image/")) {
307806
- breakdown.media += estimateTokenCountSync(
307807
- [part],
307808
- 0,
307809
- this.charsPerToken
307810
- );
307811
- } else if (part.functionCall || part.functionResponse) {
307812
- breakdown.tool += estimateTokenCountSync(
307813
- [part],
307814
- 0,
307815
- this.charsPerToken
307816
- );
307817
- } else {
307818
- breakdown.overhead += estimateTokenCountSync(
307819
- [part],
307820
- 0,
307821
- this.charsPerToken
307822
- );
307823
- }
307824
- }
307825
- }
307826
- return breakdown;
307827
- }
307828
- /**
307829
- * Fast calculation for a flat array of ConcreteNodes (The Nodes).
307830
- * It relies entirely on the O(1) sidecar token cache.
307831
- */
307832
- calculateConcreteListTokens(nodes) {
307833
- let tokens = 0;
307834
- const seenIds = /* @__PURE__ */ new Set();
307835
- const seenTurnIds = /* @__PURE__ */ new Set();
307836
- for (const node of nodes) {
307837
- if (!seenIds.has(node.id)) {
307838
- seenIds.add(node.id);
307839
- tokens += this.getTokenCost(node);
307840
- if (node.turnId) {
307841
- if (!seenTurnIds.has(node.turnId)) {
307842
- seenTurnIds.add(node.turnId);
307843
- tokens += MSG_OVERHEAD_TOKENS;
307844
- }
307845
- }
307846
- }
307847
- }
307848
- return tokens;
307849
- }
307850
- /**
307851
- * Calculates the token cost for a single Gemini Content object.
307852
- */
307853
- calculateContentTokens(content) {
307854
- return this.estimateTokensForParts(content.parts || []) + MSG_OVERHEAD_TOKENS;
307855
- }
307856
- /**
307857
- * Slower, precise estimation for a Gemini Content/Part graph.
307858
- * Deeply inspects the nested structure and uses the base tokenization math.
307859
- */
307860
- partTokenCache = /* @__PURE__ */ new WeakMap();
307861
- estimateTokensForParts(parts2) {
307862
- let total = 0;
307863
- for (const part of parts2) {
307864
- if (part !== null && typeof part === "object") {
307865
- let cost = this.partTokenCache.get(part);
307866
- if (cost === void 0) {
307867
- cost = estimateTokenCountSync([part], 0, this.charsPerToken);
307868
- this.partTokenCache.set(part, cost);
307869
- }
307870
- total += cost;
307871
- } else {
307872
- total += estimateTokenCountSync([part], 0, this.charsPerToken);
307873
- }
307874
- }
307875
- return total;
307876
- }
307877
- };
307878
-
307879
308395
  // packages/core/src/context/pipeline/inbox.ts
307880
308396
  import { randomUUID as randomUUID11 } from "node:crypto";
307881
308397
  var LiveInbox = class {
@@ -307913,81 +308429,6 @@ var InboxSnapshotImpl = class {
307913
308429
  }
307914
308430
  };
307915
308431
 
307916
- // packages/core/src/context/graph/behaviorRegistry.ts
307917
- var NodeBehaviorRegistry = class {
307918
- behaviors = /* @__PURE__ */ new Map();
307919
- register(behavior) {
307920
- this.behaviors.set(behavior.type, behavior);
307921
- }
307922
- get(type2) {
307923
- const behavior = this.behaviors.get(type2);
307924
- if (!behavior) {
307925
- throw new Error(`Unregistered Node type: ${type2}`);
307926
- }
307927
- return behavior;
307928
- }
307929
- };
307930
-
307931
- // packages/core/src/context/graph/builtinBehaviors.ts
307932
- var UserPromptBehavior = {
307933
- type: "USER_PROMPT" /* USER_PROMPT */,
307934
- getEstimatableParts(node) {
307935
- return [node.payload];
307936
- }
307937
- };
307938
- var AgentThoughtBehavior = {
307939
- type: "AGENT_THOUGHT" /* AGENT_THOUGHT */,
307940
- getEstimatableParts(node) {
307941
- return [node.payload];
307942
- }
307943
- };
307944
- var ToolExecutionBehavior = {
307945
- type: "TOOL_EXECUTION" /* TOOL_EXECUTION */,
307946
- getEstimatableParts(node) {
307947
- return [node.payload];
307948
- }
307949
- };
307950
- var MaskedToolBehavior = {
307951
- type: "MASKED_TOOL" /* MASKED_TOOL */,
307952
- getEstimatableParts(node) {
307953
- return [node.payload];
307954
- }
307955
- };
307956
- var AgentYieldBehavior = {
307957
- type: "AGENT_YIELD" /* AGENT_YIELD */,
307958
- getEstimatableParts() {
307959
- return [];
307960
- }
307961
- };
307962
- var SystemEventBehavior = {
307963
- type: "SYSTEM_EVENT" /* SYSTEM_EVENT */,
307964
- getEstimatableParts(node) {
307965
- return [node.payload];
307966
- }
307967
- };
307968
- var SnapshotBehavior = {
307969
- type: "SNAPSHOT" /* SNAPSHOT */,
307970
- getEstimatableParts(node) {
307971
- return [node.payload];
307972
- }
307973
- };
307974
- var RollingSummaryBehavior = {
307975
- type: "ROLLING_SUMMARY" /* ROLLING_SUMMARY */,
307976
- getEstimatableParts(node) {
307977
- return [node.payload];
307978
- }
307979
- };
307980
- function registerBuiltInBehaviors(registry2) {
307981
- registry2.register(UserPromptBehavior);
307982
- registry2.register(AgentThoughtBehavior);
307983
- registry2.register(ToolExecutionBehavior);
307984
- registry2.register(MaskedToolBehavior);
307985
- registry2.register(AgentYieldBehavior);
307986
- registry2.register(SystemEventBehavior);
307987
- registry2.register(SnapshotBehavior);
307988
- registry2.register(RollingSummaryBehavior);
307989
- }
307990
-
307991
308432
  // packages/core/src/context/graph/toGraph.ts
307992
308433
  import { randomUUID as randomUUID12, createHash as createHash7 } from "node:crypto";
307993
308434
  var PART_HASH_CACHE = /* @__PURE__ */ new WeakMap();
@@ -308058,9 +308499,9 @@ var ContextGraphBuilder = class {
308058
308499
  for (let turnIdx = 0; turnIdx < history.length; turnIdx++) {
308059
308500
  const msg = history[turnIdx];
308060
308501
  if (!msg.parts) continue;
308061
- if (turnIdx === 0 && msg.role === "user" && msg.parts.length === 1) {
308502
+ if (msg.role === "user" && msg.parts.length === 1) {
308062
308503
  const text = msg.parts[0].text;
308063
- if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI.")) {
308504
+ if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI")) {
308064
308505
  debugLogger.log(
308065
308506
  "[ContextGraphBuilder] Skipping legacy environment header turn from graph."
308066
308507
  );
@@ -308157,7 +308598,7 @@ var ContextGraphMapper = class {
308157
308598
 
308158
308599
  // packages/core/src/context/pipeline/environmentImpl.ts
308159
308600
  var ContextEnvironmentImpl = class {
308160
- constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus) {
308601
+ constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus, tokenCalculator, behaviorRegistry, renderOptions) {
308161
308602
  this.llmClientProvider = llmClientProvider;
308162
308603
  this.sessionId = sessionId;
308163
308604
  this.promptId = promptId;
@@ -308166,18 +308607,13 @@ var ContextEnvironmentImpl = class {
308166
308607
  this.tracer = tracer;
308167
308608
  this.charsPerToken = charsPerToken;
308168
308609
  this.eventBus = eventBus;
308169
- this.behaviorRegistry = new NodeBehaviorRegistry();
308170
- registerBuiltInBehaviors(this.behaviorRegistry);
308171
- this.tokenCalculator = new ContextTokenCalculator(
308172
- this.charsPerToken,
308173
- this.behaviorRegistry
308174
- );
308610
+ this.tokenCalculator = tokenCalculator;
308611
+ this.behaviorRegistry = behaviorRegistry;
308612
+ this.renderOptions = renderOptions;
308175
308613
  this.inbox = new LiveInbox();
308176
308614
  this.graphMapper = new ContextGraphMapper();
308177
308615
  }
308178
- tokenCalculator;
308179
308616
  inbox;
308180
- behaviorRegistry;
308181
308617
  graphMapper;
308182
308618
  get llmClient() {
308183
308619
  return this.llmClientProvider();
@@ -308219,33 +308655,6 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
308219
308655
  // Empty history
308220
308656
  );
308221
308657
  }
308222
- /**
308223
- * Appends newly observed pristine nodes (e.g. from a user message) to the working buffer.
308224
- * Ensures they are tracked in the pristine map and point to themselves in provenance.
308225
- */
308226
- appendPristineNodes(newNodes) {
308227
- if (newNodes.length === 0) return this;
308228
- const newPristineMap = new Map(this.pristineNodesMap);
308229
- const newProvenanceMap = new Map(this.provenanceMap);
308230
- const existingIds = new Set(this.nodes.map((n3) => n3.id));
308231
- const nodesToAdd = [];
308232
- const batchIds = /* @__PURE__ */ new Set();
308233
- for (const node of newNodes) {
308234
- if (!existingIds.has(node.id) && !batchIds.has(node.id)) {
308235
- newPristineMap.set(node.id, node);
308236
- newProvenanceMap.set(node.id, /* @__PURE__ */ new Set([node.id]));
308237
- nodesToAdd.push(node);
308238
- batchIds.add(node.id);
308239
- }
308240
- }
308241
- if (nodesToAdd.length === 0) return this;
308242
- return new _ContextWorkingBufferImpl(
308243
- [...this.nodes, ...nodesToAdd],
308244
- newPristineMap,
308245
- newProvenanceMap,
308246
- [...this.history]
308247
- );
308248
- }
308249
308658
  /**
308250
308659
  * Generates an entirely new buffer instance by calculating the delta between the processor's input and output.
308251
308660
  */
@@ -308325,12 +308734,90 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
308325
308734
  [...this.history, mutation]
308326
308735
  );
308327
308736
  }
308328
- /** Removes nodes from the working buffer that were completely dropped from the upstream pristine history */
308329
- prunePristineNodes(retainedIds) {
308330
- const newGraph = this.nodes.filter(
308331
- (n3) => retainedIds.has(n3.id) || !this.pristineNodesMap.has(n3.id)
308332
- );
308737
+ /**
308738
+ * Rebuilds the working buffer in the exact chronological order of the authoritative pristine history,
308739
+ * while preserving injected/summarized nodes at their relative positions.
308740
+ */
308741
+ syncPristineHistory(authoritativePristineNodes) {
308742
+ const newPristineMap = new Map(this.pristineNodesMap);
308333
308743
  const newProvenanceMap = new Map(this.provenanceMap);
308744
+ const authoritativeIds = new Set(
308745
+ authoritativePristineNodes.map((n3) => n3.id)
308746
+ );
308747
+ for (const node of authoritativePristineNodes) {
308748
+ if (!newPristineMap.has(node.id)) {
308749
+ newPristineMap.set(node.id, node);
308750
+ newProvenanceMap.set(node.id, /* @__PURE__ */ new Set([node.id]));
308751
+ }
308752
+ }
308753
+ const survivingCurrentNodes = this.nodes.filter((n3) => {
308754
+ if (authoritativeIds.has(n3.id)) return true;
308755
+ if (!this.pristineNodesMap.has(n3.id)) return true;
308756
+ const roots = newProvenanceMap.get(n3.id);
308757
+ return !roots || roots.size === 0;
308758
+ }).filter((n3) => {
308759
+ if (!authoritativeIds.has(n3.id) && !this.pristineNodesMap.has(n3.id)) {
308760
+ const roots = newProvenanceMap.get(n3.id);
308761
+ if (roots && roots.size > 0) {
308762
+ for (const root of roots) {
308763
+ if (!authoritativeIds.has(root)) {
308764
+ return false;
308765
+ }
308766
+ }
308767
+ }
308768
+ }
308769
+ return true;
308770
+ });
308771
+ const coveredPristineIds = /* @__PURE__ */ new Set();
308772
+ for (const node of survivingCurrentNodes) {
308773
+ if (!authoritativeIds.has(node.id)) {
308774
+ const roots = newProvenanceMap.get(node.id);
308775
+ if (roots) {
308776
+ for (const root of roots) {
308777
+ coveredPristineIds.add(root);
308778
+ }
308779
+ }
308780
+ }
308781
+ }
308782
+ const pristineIndexMap = new Map(
308783
+ authoritativePristineNodes.map((n3, idx) => [n3.id, idx])
308784
+ );
308785
+ const getPristineIndex = (nodeId) => {
308786
+ const roots = newProvenanceMap.get(nodeId);
308787
+ if (!roots || roots.size === 0) return -1;
308788
+ let maxIndex = -1;
308789
+ for (const root of roots) {
308790
+ const idx = pristineIndexMap.get(root);
308791
+ if (idx !== void 0 && idx > maxIndex) {
308792
+ maxIndex = idx;
308793
+ }
308794
+ }
308795
+ return maxIndex;
308796
+ };
308797
+ const nodeOrder = new Array();
308798
+ for (let i3 = 0; i3 < authoritativePristineNodes.length; i3++) {
308799
+ const node = authoritativePristineNodes[i3];
308800
+ if (!coveredPristineIds.has(node.id)) {
308801
+ nodeOrder.push({ node, sortKey: i3, originalIndex: -1 });
308802
+ }
308803
+ }
308804
+ for (let i3 = 0; i3 < survivingCurrentNodes.length; i3++) {
308805
+ const node = survivingCurrentNodes[i3];
308806
+ if (!authoritativeIds.has(node.id)) {
308807
+ const baseSortKey = getPristineIndex(node.id);
308808
+ nodeOrder.push({
308809
+ node,
308810
+ sortKey: baseSortKey === -1 ? -1 : baseSortKey + 0.5,
308811
+ // Interleave after pristine roots, or at start if injected
308812
+ originalIndex: i3
308813
+ });
308814
+ }
308815
+ }
308816
+ nodeOrder.sort((a2, b) => {
308817
+ if (a2.sortKey !== b.sortKey) return a2.sortKey - b.sortKey;
308818
+ return a2.originalIndex - b.originalIndex;
308819
+ });
308820
+ const newGraph = nodeOrder.map((item) => item.node);
308334
308821
  const reachablePristineIds = /* @__PURE__ */ new Set();
308335
308822
  const reachableCurrentIds = /* @__PURE__ */ new Set();
308336
308823
  for (const node of newGraph) {
@@ -308338,7 +308825,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
308338
308825
  const roots = newProvenanceMap.get(node.id);
308339
308826
  if (roots) {
308340
308827
  for (const root of roots) {
308341
- if (retainedIds.has(root) || !this.pristineNodesMap.has(root)) {
308828
+ if (authoritativeIds.has(root) || !this.pristineNodesMap.has(root)) {
308342
308829
  reachablePristineIds.add(root);
308343
308830
  }
308344
308831
  }
@@ -308351,7 +308838,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
308351
308838
  }
308352
308839
  const prunedPristineMap = /* @__PURE__ */ new Map();
308353
308840
  for (const id of reachablePristineIds) {
308354
- const node = this.pristineNodesMap.get(id);
308841
+ const node = newPristineMap.get(id);
308355
308842
  if (node) prunedPristineMap.set(id, node);
308356
308843
  }
308357
308844
  return new _ContextWorkingBufferImpl(
@@ -308386,6 +308873,7 @@ var PipelineOrchestrator = class {
308386
308873
  activeTimers = [];
308387
308874
  pendingPipelines = /* @__PURE__ */ new Map();
308388
308875
  pipelineMutex = /* @__PURE__ */ new Map();
308876
+ pipelineScheduled = /* @__PURE__ */ new Set();
308389
308877
  nodeProvider;
308390
308878
  /**
308391
308879
  * Sets the provider for the latest live nodes.
@@ -308420,22 +308908,50 @@ var PipelineOrchestrator = class {
308420
308908
  this.activeTimers.push(timer);
308421
308909
  } else if (trigger === "retained_exceeded" || trigger === "nodes_aged_out") {
308422
308910
  this.eventBus.onConsolidationNeeded((event) => {
308423
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
308911
+ void executeFn(
308912
+ pipeline,
308913
+ event.nodes,
308914
+ event.targetNodeIds,
308915
+ /* @__PURE__ */ new Set()
308916
+ );
308424
308917
  });
308425
308918
  } else if (trigger === "new_message" || trigger === "nodes_added") {
308426
308919
  this.eventBus.onChunkReceived((event) => {
308427
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
308920
+ void executeFn(
308921
+ pipeline,
308922
+ event.nodes,
308923
+ event.targetNodeIds,
308924
+ /* @__PURE__ */ new Set()
308925
+ );
308428
308926
  });
308429
308927
  }
308430
308928
  }
308431
308929
  }
308432
308930
  };
308433
- bindTriggers(this.pipelines, (pipeline, nodes, targets, protectedIds) => {
308931
+ const handleSyncExecution = async (pipeline, nodes, targets, protectedIds) => {
308932
+ if (this.pipelineScheduled.has(pipeline.name)) {
308933
+ debugLogger.log(
308934
+ `[Orchestrator] Pipeline ${pipeline.name} already scheduled (sync), dropping.`
308935
+ );
308936
+ return;
308937
+ }
308938
+ this.pipelineScheduled.add(pipeline.name);
308434
308939
  const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
308435
308940
  const nextPromise = (async () => {
308436
308941
  try {
308437
308942
  await existing;
308438
- const latestNodes = this.nodeProvider();
308943
+ this.pipelineScheduled.delete(pipeline.name);
308944
+ const latestNodes = this.nodeProvider ? this.nodeProvider() : nodes;
308945
+ const latestTargets = latestNodes.filter((n3) => targets.has(n3.id));
308946
+ debugLogger.log(
308947
+ `[Orchestrator] Executing sync pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`
308948
+ );
308949
+ if (latestTargets.length === 0) {
308950
+ debugLogger.log(
308951
+ `[Orchestrator] No latest targets for sync pipeline ${pipeline.name}, returning.`
308952
+ );
308953
+ return;
308954
+ }
308439
308955
  await this.executePipelineAsync(
308440
308956
  pipeline,
308441
308957
  latestNodes,
@@ -308443,7 +308959,7 @@ var PipelineOrchestrator = class {
308443
308959
  new Set(protectedIds)
308444
308960
  );
308445
308961
  } catch (e2) {
308446
- debugLogger.error(`Pipeline chain ${pipeline.name} failed:`, e2);
308962
+ debugLogger.error(`Sync pipeline chain ${pipeline.name} failed:`, e2);
308447
308963
  }
308448
308964
  })();
308449
308965
  this.pipelineMutex.set(pipeline.name, nextPromise);
@@ -308455,22 +308971,61 @@ var PipelineOrchestrator = class {
308455
308971
  this.pipelineMutex.delete(pipeline.name);
308456
308972
  }
308457
308973
  });
308458
- });
308459
- bindTriggers(this.asyncPipelines, (pipeline, nodes, targetIds) => {
308460
- const inboxSnapshot = new InboxSnapshotImpl(
308461
- this.env.inbox.getMessages() || []
308462
- );
308463
- const targets = nodes.filter((n3) => targetIds.has(n3.id));
308464
- for (const processor of pipeline.processors) {
308465
- processor.process({
308466
- targets,
308467
- inbox: inboxSnapshot,
308468
- buffer: ContextWorkingBufferImpl.initialize(nodes)
308469
- }).catch(
308470
- (e2) => debugLogger.error(`AsyncProcessor ${processor.name} failed:`, e2)
308974
+ };
308975
+ const handleAsyncExecution = async (pipeline, nodes, targets) => {
308976
+ if (this.pipelineScheduled.has(pipeline.name)) {
308977
+ debugLogger.log(
308978
+ `[Orchestrator] Pipeline ${pipeline.name} already scheduled (async), dropping.`
308471
308979
  );
308980
+ return;
308472
308981
  }
308473
- });
308982
+ this.pipelineScheduled.add(pipeline.name);
308983
+ const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
308984
+ const nextPromise = (async () => {
308985
+ try {
308986
+ await existing;
308987
+ this.pipelineScheduled.delete(pipeline.name);
308988
+ const latestNodes = this.nodeProvider ? this.nodeProvider() : nodes;
308989
+ const latestTargets = latestNodes.filter((n3) => targets.has(n3.id));
308990
+ debugLogger.log(
308991
+ `[Orchestrator] Executing async pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`
308992
+ );
308993
+ const inboxSnapshot = new InboxSnapshotImpl(
308994
+ this.env.inbox.getMessages() || []
308995
+ );
308996
+ for (const processor of pipeline.processors) {
308997
+ debugLogger.log(
308998
+ `[Orchestrator] Running async processor ${processor.id}`
308999
+ );
309000
+ await processor.process({
309001
+ targets: latestTargets,
309002
+ inbox: inboxSnapshot,
309003
+ buffer: ContextWorkingBufferImpl.initialize(latestNodes)
309004
+ });
309005
+ }
309006
+ this.env.inbox.drainConsumed(inboxSnapshot.getConsumedIds());
309007
+ } catch (e2) {
309008
+ debugLogger.error(`Async pipeline chain ${pipeline.name} failed:`, e2);
309009
+ }
309010
+ })();
309011
+ this.pipelineMutex.set(pipeline.name, nextPromise);
309012
+ const pipelineId = `${pipeline.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
309013
+ this.pendingPipelines.set(pipelineId, nextPromise);
309014
+ void nextPromise.finally(() => {
309015
+ this.pendingPipelines.delete(pipelineId);
309016
+ if (this.pipelineMutex.get(pipeline.name) === nextPromise) {
309017
+ this.pipelineMutex.delete(pipeline.name);
309018
+ }
309019
+ });
309020
+ };
309021
+ bindTriggers(
309022
+ this.pipelines,
309023
+ (pipeline, nodes, targets, protectedIds) => handleSyncExecution(pipeline, nodes, targets, protectedIds)
309024
+ );
309025
+ bindTriggers(
309026
+ this.asyncPipelines,
309027
+ (pipeline, nodes, targets) => handleAsyncExecution(pipeline, nodes, targets)
309028
+ );
308474
309029
  }
308475
309030
  shutdown() {
308476
309031
  for (const timer of this.activeTimers) {
@@ -308668,17 +309223,56 @@ var HistoryObserver = class {
308668
309223
  }
308669
309224
  };
308670
309225
 
309226
+ // packages/core/src/context/utils/tokenCalibration.ts
309227
+ function performCalibration(env2, finalNodes, finalContents) {
309228
+ if (!env2.renderOptions?.calibrateTokenCalculation) {
309229
+ return;
309230
+ }
309231
+ void (async () => {
309232
+ try {
309233
+ const exactResp = await env2.llmClient.countTokens({
309234
+ contents: finalContents
309235
+ });
309236
+ const exactTokens = typeof exactResp.totalTokens === "number" ? exactResp.totalTokens : 0;
309237
+ const estimatedTokens = env2.tokenCalculator.calculateConcreteListTokens(finalNodes);
309238
+ const delta = Math.abs(exactTokens - estimatedTokens);
309239
+ const tolerance = Math.max(exactTokens, estimatedTokens) * 0.2;
309240
+ env2.tracer.logEvent("Render", "Token Calibration Measurement", {
309241
+ exactTokens,
309242
+ estimatedTokens,
309243
+ delta,
309244
+ isWithinTolerance: delta <= tolerance
309245
+ });
309246
+ if (delta > tolerance) {
309247
+ debugLogger.error(
309248
+ `[Token Calibration] Large deviation detected: exact ${exactTokens} vs estimated ${estimatedTokens} (delta: ${delta})`
309249
+ );
309250
+ }
309251
+ } catch {
309252
+ }
309253
+ })();
309254
+ }
309255
+
308671
309256
  // packages/core/src/context/graph/render.ts
308672
- async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionReasons = /* @__PURE__ */ new Map(), headerTokens = 0) {
309257
+ async function render2(nodes, orchestrator, sidecar, tracer, env2, advancedTokenCalculator, protectionReasons = /* @__PURE__ */ new Map(), header, previewNodeIds = /* @__PURE__ */ new Set()) {
309258
+ let headerTokens = 0;
309259
+ let headerBaseUnits = 0;
309260
+ if (header) {
309261
+ const costs = advancedTokenCalculator.calculateContentTokensAndBaseUnits(header);
309262
+ headerTokens = costs.tokens;
309263
+ headerBaseUnits = costs.baseUnits;
309264
+ }
308673
309265
  if (!sidecar.config.budget) {
308674
- const contents2 = env2.graphMapper.fromGraph(nodes);
309266
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
309267
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
308675
309268
  tracer.logEvent("Render", "Render Context to LLM (No Budget)", {
308676
309269
  renderedContext: contents2
308677
309270
  });
308678
- return { history: contents2, didApplyManagement: false };
309271
+ const baseUnits = advancedTokenCalculator.getRawBaseUnits(nodes) + headerBaseUnits;
309272
+ return { history: contents2, didApplyManagement: false, baseUnits };
308679
309273
  }
308680
309274
  const maxTokens = sidecar.config.budget.maxTokens;
308681
- const graphTokens = env2.tokenCalculator.calculateConcreteListTokens(nodes);
309275
+ const { tokens: graphTokens, baseUnits: graphBaseUnits } = advancedTokenCalculator.calculateTokensAndBaseUnits(nodes);
308682
309276
  const currentTokens = graphTokens + headerTokens;
308683
309277
  const protectedIds = new Set(protectionReasons.keys());
308684
309278
  tracer.logEvent("Render", "Budget Audit", {
@@ -308701,11 +309295,17 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
308701
309295
  "Render",
308702
309296
  `View is within maxTokens (${currentTokens} <= ${maxTokens}). Returning view.`
308703
309297
  );
308704
- const contents2 = env2.graphMapper.fromGraph(nodes);
309298
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
309299
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
308705
309300
  tracer.logEvent("Render", "Render Context for LLM", {
308706
309301
  renderedContext: contents2
308707
309302
  });
308708
- return { history: contents2, didApplyManagement: false };
309303
+ performCalibration(env2, visibleNodes2, contents2);
309304
+ return {
309305
+ history: contents2,
309306
+ didApplyManagement: false,
309307
+ baseUnits: graphBaseUnits + headerBaseUnits
309308
+ };
308709
309309
  }
308710
309310
  const targetDelta = currentTokens - sidecar.config.budget.retainedTokens;
308711
309311
  tracer.logEvent(
@@ -308717,9 +309317,10 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
308717
309317
  let rollingTokens = 0;
308718
309318
  for (let i3 = nodes.length - 1; i3 >= 0; i3--) {
308719
309319
  const node = nodes[i3];
309320
+ const priorTokens = rollingTokens;
308720
309321
  const nodeTokens = env2.tokenCalculator.calculateConcreteListTokens([node]);
308721
309322
  rollingTokens += nodeTokens;
308722
- if (rollingTokens > sidecar.config.budget.retainedTokens) {
309323
+ if (priorTokens > sidecar.config.budget.retainedTokens) {
308723
309324
  agedOutNodes.add(node.id);
308724
309325
  }
308725
309326
  }
@@ -308735,12 +309336,19 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
308735
309336
  for (const id of node.abstractsIds) skipList.add(id);
308736
309337
  }
308737
309338
  }
308738
- const visibleNodes = processedNodes.filter((n3) => !skipList.has(n3.id));
309339
+ const visibleNodes = processedNodes.filter(
309340
+ (n3) => !skipList.has(n3.id) && !previewNodeIds.has(n3.id)
309341
+ );
308739
309342
  const contents = env2.graphMapper.fromGraph(visibleNodes);
308740
309343
  tracer.logEvent("Render", "Render Sanitized Context for LLM", {
308741
309344
  renderedContextSanitized: contents
308742
309345
  });
308743
- return { history: contents, didApplyManagement: true };
309346
+ performCalibration(env2, visibleNodes, contents);
309347
+ return {
309348
+ history: contents,
309349
+ didApplyManagement: true,
309350
+ baseUnits: advancedTokenCalculator.getRawBaseUnits(visibleNodes) + headerBaseUnits
309351
+ };
308744
309352
  }
308745
309353
 
308746
309354
  // packages/core/src/context/utils/invariantChecker.ts
@@ -308776,10 +309384,11 @@ function checkContextInvariants(nodes, context2) {
308776
309384
 
308777
309385
  // packages/core/src/context/contextManager.ts
308778
309386
  var ContextManager = class {
308779
- constructor(sidecar, env2, tracer, orchestrator, chatHistory, headerProvider) {
309387
+ constructor(sidecar, env2, tracer, orchestrator, chatHistory, advancedTokenCalculator, headerProvider) {
308780
309388
  this.sidecar = sidecar;
308781
309389
  this.env = env2;
308782
309390
  this.tracer = tracer;
309391
+ this.advancedTokenCalculator = advancedTokenCalculator;
308783
309392
  this.headerProvider = headerProvider;
308784
309393
  this.eventBus = env2.eventBus;
308785
309394
  this.orchestrator = orchestrator;
@@ -308791,12 +309400,7 @@ var ContextManager = class {
308791
309400
  this.env.graphMapper
308792
309401
  );
308793
309402
  this.eventBus.onPristineHistoryUpdated((event) => {
308794
- const newIds = new Set(event.nodes.map((n3) => n3.id));
308795
- const addedNodes = event.nodes.filter((n3) => event.newNodes.has(n3.id));
308796
- this.buffer = this.buffer.prunePristineNodes(newIds);
308797
- if (addedNodes.length > 0) {
308798
- this.buffer = this.buffer.appendPristineNodes(addedNodes);
308799
- }
309403
+ this.buffer = this.buffer.syncPristineHistory(event.nodes);
308800
309404
  this.evaluateTriggers(event.newNodes);
308801
309405
  });
308802
309406
  this.eventBus.onProcessorResult((event) => {
@@ -308814,8 +309418,11 @@ var ContextManager = class {
308814
309418
  // Internal sub-components
308815
309419
  orchestrator;
308816
309420
  historyObserver;
309421
+ // Hysteresis tracking to prevent utility call churn
309422
+ lastTriggeredDeficit = 0;
308817
309423
  // Cache for Anomaly 3 (Redundant Renders)
308818
309424
  lastRenderCache;
309425
+ hasPerformedHotStart = false;
308819
309426
  /**
308820
309427
  * Returns a promise that resolves when all currently executing async pipelines have finished.
308821
309428
  */
@@ -308855,10 +309462,11 @@ var ContextManager = class {
308855
309462
  }
308856
309463
  for (let i3 = this.buffer.nodes.length - 1; i3 >= 0; i3--) {
308857
309464
  const node = this.buffer.nodes[i3];
309465
+ const priorTokens = rollingTokens;
308858
309466
  rollingTokens += this.env.tokenCalculator.calculateConcreteListTokens([
308859
309467
  node
308860
309468
  ]);
308861
- if (rollingTokens > this.sidecar.config.budget.retainedTokens) {
309469
+ if (priorTokens > this.sidecar.config.budget.retainedTokens) {
308862
309470
  if (!protectedIds.has(node.id)) {
308863
309471
  agedOutNodes.add(node.id);
308864
309472
  }
@@ -308866,8 +309474,13 @@ var ContextManager = class {
308866
309474
  }
308867
309475
  if (agedOutNodes.size > 0) {
308868
309476
  const targetDeficit = currentTokens - this.sidecar.config.budget.retainedTokens;
309477
+ if (targetDeficit < this.lastTriggeredDeficit) {
309478
+ this.lastTriggeredDeficit = targetDeficit;
309479
+ }
308869
309480
  const threshold = this.sidecar.config.budget.coalescingThresholdTokens || 0;
308870
- if (targetDeficit >= threshold) {
309481
+ const growthSinceLast = targetDeficit - this.lastTriggeredDeficit;
309482
+ if (targetDeficit >= threshold && (growthSinceLast >= threshold || this.lastTriggeredDeficit === 0)) {
309483
+ this.lastTriggeredDeficit = targetDeficit;
308871
309484
  this.env.tokenCalculator.garbageCollectCache(
308872
309485
  new Set(this.buffer.nodes.map((n3) => n3.id))
308873
309486
  );
@@ -308877,6 +309490,8 @@ var ContextManager = class {
308877
309490
  targetNodeIds: agedOutNodes
308878
309491
  });
308879
309492
  }
309493
+ } else {
309494
+ this.lastTriggeredDeficit = 0;
308880
309495
  }
308881
309496
  }
308882
309497
  }
@@ -308936,24 +309551,42 @@ var ContextManager = class {
308936
309551
  getNodes() {
308937
309552
  return [...this.buffer.nodes];
308938
309553
  }
309554
+ getEnvironment() {
309555
+ return this.env;
309556
+ }
308939
309557
  /**
308940
309558
  * Executes the final 'gc_backstop' pipeline if necessary, enforcing the token budget,
308941
309559
  * and maps the Episodic Context Graph back into a raw Gemini Content[] array for transmission.
308942
309560
  * This is the primary method called by the agent framework before sending a request.
308943
309561
  */
308944
- async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set()) {
309562
+ async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set(), abortSignal) {
308945
309563
  this.tracer.logEvent("ContextManager", "Starting rendering of LLM context");
308946
- await this.orchestrator.waitForPipelines();
308947
- let nodes = this.buffer.nodes;
309564
+ let previewNodes = [];
308948
309565
  if (pendingRequest) {
308949
- const previewNodes = this.env.graphMapper.applyEvent({
309566
+ previewNodes = this.env.graphMapper.applyEvent({
308950
309567
  type: "PUSH",
308951
309568
  payload: [pendingRequest]
308952
309569
  });
309570
+ }
309571
+ const hotStartPromise = (async () => {
309572
+ if (!this.hasPerformedHotStart) {
309573
+ this.hasPerformedHotStart = true;
309574
+ if (this.buffer.nodes.length > 0) {
309575
+ const nodesForHotStart = [...this.buffer.nodes, ...previewNodes];
309576
+ await this.performHotStartCalibration(nodesForHotStart, abortSignal);
309577
+ }
309578
+ }
309579
+ })();
309580
+ await Promise.all([this.orchestrator.waitForPipelines(), hotStartPromise]);
309581
+ let nodes = this.buffer.nodes;
309582
+ const previewNodeIds = /* @__PURE__ */ new Set();
309583
+ if (previewNodes.length > 0) {
309584
+ for (const n3 of previewNodes) {
309585
+ previewNodeIds.add(n3.id);
309586
+ }
308953
309587
  nodes = [...nodes, ...previewNodes];
308954
309588
  }
308955
309589
  const header = this.headerProvider ? await this.headerProvider() : void 0;
308956
- const headerTokens = header ? this.env.tokenCalculator.calculateContentTokens(header) : 0;
308957
309590
  const graphHash = nodes.map((n3) => n3.id).join("|");
308958
309591
  const headerHash = header ? JSON.stringify(header.parts) : "no-header";
308959
309592
  const totalHash = `${graphHash}::${headerHash}`;
@@ -308964,14 +309597,20 @@ var ContextManager = class {
308964
309597
  return this.lastRenderCache.result;
308965
309598
  }
308966
309599
  const protectionReasons = this.getProtectedNodeIds(nodes, activeTaskIds);
308967
- const { history: renderedHistory, didApplyManagement } = await render2(
309600
+ const {
309601
+ history: renderedHistory,
309602
+ didApplyManagement,
309603
+ baseUnits
309604
+ } = await render2(
308968
309605
  nodes,
308969
309606
  this.orchestrator,
308970
309607
  this.sidecar,
308971
309608
  this.tracer,
308972
309609
  this.env,
309610
+ this.advancedTokenCalculator,
308973
309611
  protectionReasons,
308974
- headerTokens
309612
+ header,
309613
+ previewNodeIds
308975
309614
  );
308976
309615
  checkContextInvariants(this.buffer.nodes, "RenderHistory");
308977
309616
  this.tracer.logEvent("ContextManager", "Finished rendering");
@@ -308980,11 +309619,42 @@ var ContextManager = class {
308980
309619
  history: hardenHistory(combinedHistory, {
308981
309620
  sentinels: this.sidecar.sentinels
308982
309621
  }),
308983
- didApplyManagement
309622
+ didApplyManagement,
309623
+ baseUnits
308984
309624
  };
308985
309625
  this.lastRenderCache = { nodesHash: totalHash, result: result2 };
308986
309626
  return result2;
308987
309627
  }
309628
+ async performHotStartCalibration(nodes, abortSignal) {
309629
+ try {
309630
+ this.tracer.logEvent(
309631
+ "ContextManager",
309632
+ "Performing Hot Start Token Calibration"
309633
+ );
309634
+ const contents = this.env.graphMapper.fromGraph(nodes);
309635
+ const header = this.headerProvider ? await this.headerProvider() : void 0;
309636
+ const combinedHistory = header ? [header, ...contents] : contents;
309637
+ const baseUnits = this.advancedTokenCalculator.getRawBaseUnits(nodes) + (header ? this.advancedTokenCalculator.getRawBaseUnitsForContent(header) : 0);
309638
+ if (combinedHistory.length > 0) {
309639
+ const result2 = await this.env.llmClient.countTokens({
309640
+ contents: combinedHistory,
309641
+ abortSignal
309642
+ });
309643
+ if (result2.totalTokens > 0) {
309644
+ this.env.eventBus.emitTokenGroundTruth({
309645
+ actualTokens: result2.totalTokens,
309646
+ promptBaseUnits: baseUnits
309647
+ });
309648
+ }
309649
+ }
309650
+ } catch (error40) {
309651
+ this.tracer.logEvent(
309652
+ "ContextManager",
309653
+ "Hot Start Token Calibration Failed (Ignored)",
309654
+ { error: error40 }
309655
+ );
309656
+ }
309657
+ }
308988
309658
  };
308989
309659
 
308990
309660
  // packages/core/src/context/processors/historyTruncationProcessor.ts
@@ -309017,6 +309687,350 @@ var RollingSummaryProcessorOptionsSchema = {
309017
309687
  required: []
309018
309688
  };
309019
309689
 
309690
+ // packages/core/src/context/utils/contextTokenCalculator.ts
309691
+ var StaticTokenCalculator = class {
309692
+ constructor(charsPerToken, registry2) {
309693
+ this.charsPerToken = charsPerToken;
309694
+ this.registry = registry2;
309695
+ }
309696
+ tokenCache = /* @__PURE__ */ new Map();
309697
+ /**
309698
+ * Estimates tokens for a simple string based on character count.
309699
+ * Fast, but inherently inaccurate compared to real model tokenization.
309700
+ */
309701
+ estimateTokensForString(text) {
309702
+ return Math.ceil(text.length / this.charsPerToken);
309703
+ }
309704
+ /**
309705
+ * Fast, simple heuristic conversion from tokens to expected character length.
309706
+ * Useful for calculating truncation thresholds.
309707
+ */
309708
+ tokensToChars(tokens) {
309709
+ return tokens * this.charsPerToken;
309710
+ }
309711
+ /**
309712
+ * Pre-calculates and caches the token cost of a newly minted node.
309713
+ * Because nodes are immutable, this cost never changes for this node ID.
309714
+ */
309715
+ /**
309716
+ * Removes cached token counts for any nodes that are no longer in the given live set.
309717
+ * This prevents unbounded memory growth during long sessions.
309718
+ */
309719
+ garbageCollectCache(liveNodeIds) {
309720
+ for (const [id] of this.tokenCache) {
309721
+ if (!liveNodeIds.has(id)) {
309722
+ this.tokenCache.delete(id);
309723
+ }
309724
+ }
309725
+ }
309726
+ cacheNodeTokens(node) {
309727
+ const behavior = this.registry.get(node.type);
309728
+ const parts2 = behavior.getEstimatableParts(node);
309729
+ const tokens = this.estimateTokensForParts(parts2);
309730
+ this.tokenCache.set(node.id, tokens);
309731
+ return tokens;
309732
+ }
309733
+ /**
309734
+ * Retrieves the token cost of a single node from the cache.
309735
+ * If it misses the cache, it computes it and caches it.
309736
+ */
309737
+ getTokenCost(node) {
309738
+ const cached2 = this.tokenCache.get(node.id);
309739
+ if (cached2 !== void 0) return cached2;
309740
+ return this.cacheNodeTokens(node);
309741
+ }
309742
+ /**
309743
+ * Calculates a detailed breakdown of tokens by category for a list of nodes.
309744
+ * Useful for calibration tracing and debugging overestimation.
309745
+ */
309746
+ calculateTokenBreakdown(nodes) {
309747
+ const breakdown = { total: 0, text: 0, media: 0, tool: 0, overhead: 0 };
309748
+ const seenIds = /* @__PURE__ */ new Set();
309749
+ const seenTurnIds = /* @__PURE__ */ new Set();
309750
+ for (const node of nodes) {
309751
+ if (seenIds.has(node.id)) continue;
309752
+ seenIds.add(node.id);
309753
+ if (node.turnId) {
309754
+ if (!seenTurnIds.has(node.turnId)) {
309755
+ seenTurnIds.add(node.turnId);
309756
+ breakdown.overhead += MSG_OVERHEAD_TOKENS;
309757
+ breakdown.total += MSG_OVERHEAD_TOKENS;
309758
+ }
309759
+ }
309760
+ const cost = this.getTokenCost(node);
309761
+ breakdown.total += cost;
309762
+ const behavior = this.registry.get(node.type);
309763
+ const parts2 = behavior.getEstimatableParts(node);
309764
+ for (const part of parts2) {
309765
+ if (typeof part.text === "string") {
309766
+ breakdown.text += estimateTokenCountSync(
309767
+ [part],
309768
+ 0,
309769
+ this.charsPerToken
309770
+ );
309771
+ } else if (part.inlineData?.mimeType?.startsWith("image/") || part.fileData?.mimeType?.startsWith("image/")) {
309772
+ breakdown.media += estimateTokenCountSync(
309773
+ [part],
309774
+ 0,
309775
+ this.charsPerToken
309776
+ );
309777
+ } else if (part.functionCall || part.functionResponse) {
309778
+ breakdown.tool += estimateTokenCountSync(
309779
+ [part],
309780
+ 0,
309781
+ this.charsPerToken
309782
+ );
309783
+ } else {
309784
+ breakdown.overhead += estimateTokenCountSync(
309785
+ [part],
309786
+ 0,
309787
+ this.charsPerToken
309788
+ );
309789
+ }
309790
+ }
309791
+ }
309792
+ return breakdown;
309793
+ }
309794
+ /**
309795
+ * For the static calculator, Raw Base Units are exactly the same as the final tokens,
309796
+ * because there is no dynamic learned weight (the multiplier is effectively 1.0).
309797
+ */
309798
+ getRawBaseUnits(nodes) {
309799
+ return this.calculateConcreteListTokens(nodes);
309800
+ }
309801
+ getRawBaseUnitsForContent(content) {
309802
+ return this.calculateContentTokens(content);
309803
+ }
309804
+ calculateTokensAndBaseUnits(nodes) {
309805
+ const baseUnits = this.calculateConcreteListTokens(nodes);
309806
+ return { tokens: baseUnits, baseUnits };
309807
+ }
309808
+ calculateContentTokensAndBaseUnits(content) {
309809
+ const baseUnits = this.calculateContentTokens(content);
309810
+ return { tokens: baseUnits, baseUnits };
309811
+ }
309812
+ /**
309813
+ * Fast calculation for a flat array of ConcreteNodes (The Nodes).
309814
+ * It relies entirely on the O(1) sidecar token cache.
309815
+ */
309816
+ calculateConcreteListTokens(nodes) {
309817
+ let tokens = 0;
309818
+ const seenIds = /* @__PURE__ */ new Set();
309819
+ const seenTurnIds = /* @__PURE__ */ new Set();
309820
+ for (const node of nodes) {
309821
+ if (!seenIds.has(node.id)) {
309822
+ seenIds.add(node.id);
309823
+ tokens += this.getTokenCost(node);
309824
+ if (node.turnId) {
309825
+ if (!seenTurnIds.has(node.turnId)) {
309826
+ seenTurnIds.add(node.turnId);
309827
+ tokens += MSG_OVERHEAD_TOKENS;
309828
+ }
309829
+ }
309830
+ }
309831
+ }
309832
+ return tokens;
309833
+ }
309834
+ /**
309835
+ * Calculates the token cost for a single Gemini Content object.
309836
+ */
309837
+ calculateContentTokens(content) {
309838
+ return this.estimateTokensForParts(content.parts || []) + MSG_OVERHEAD_TOKENS;
309839
+ }
309840
+ /**
309841
+ * Slower, precise estimation for a Gemini Content/Part graph.
309842
+ * Deeply inspects the nested structure and uses the base tokenization math.
309843
+ */
309844
+ partTokenCache = /* @__PURE__ */ new WeakMap();
309845
+ estimateTokensForParts(parts2) {
309846
+ let total = 0;
309847
+ for (const part of parts2) {
309848
+ if (part !== null && typeof part === "object") {
309849
+ let cost = this.partTokenCache.get(part);
309850
+ if (cost === void 0) {
309851
+ cost = estimateTokenCountSync([part], 0, this.charsPerToken);
309852
+ this.partTokenCache.set(part, cost);
309853
+ }
309854
+ total += cost;
309855
+ } else {
309856
+ total += estimateTokenCountSync([part], 0, this.charsPerToken);
309857
+ }
309858
+ }
309859
+ return total;
309860
+ }
309861
+ };
309862
+
309863
+ // packages/core/src/context/utils/adaptiveTokenCalculator.ts
309864
+ var AdaptiveTokenCalculator = class {
309865
+ learnedWeight = 1;
309866
+ baseCalculator;
309867
+ constructor(charsPerToken, registry2, eventBus) {
309868
+ this.baseCalculator = new StaticTokenCalculator(charsPerToken, registry2);
309869
+ eventBus.onTokenGroundTruth((event) => {
309870
+ this.handleGroundTruth(event.actualTokens, event.promptBaseUnits);
309871
+ });
309872
+ }
309873
+ handleGroundTruth(actualTokens, promptBaseUnits) {
309874
+ if (promptBaseUnits <= 0) return;
309875
+ const targetWeight = actualTokens / promptBaseUnits;
309876
+ const oldWeight = this.learnedWeight;
309877
+ const learningRate = 0.2;
309878
+ const newWeight = oldWeight * (1 - learningRate) + targetWeight * learningRate;
309879
+ this.learnedWeight = Math.max(0.5, Math.min(newWeight, 2));
309880
+ debugLogger.log(
309881
+ `[AdaptiveTokenCalculator] Learned weight updated to ${this.learnedWeight.toFixed(3)} (API Tokens: ${actualTokens}, Base Units: ${promptBaseUnits}, Target Ratio: ${targetWeight.toFixed(3)})`
309882
+ );
309883
+ }
309884
+ /**
309885
+ * Retrieves the current learned weight multiplier.
309886
+ */
309887
+ getLearnedWeight() {
309888
+ return this.learnedWeight;
309889
+ }
309890
+ /**
309891
+ * Returns the exact, unweighted Base Heuristic Units for the graph.
309892
+ * This is used exactly once per interaction to capture the baseline sent to the API.
309893
+ */
309894
+ getRawBaseUnits(nodes) {
309895
+ return this.baseCalculator.calculateConcreteListTokens(nodes);
309896
+ }
309897
+ /**
309898
+ * Returns the exact, unweighted Base Heuristic Units for a raw content chunk.
309899
+ */
309900
+ getRawBaseUnitsForContent(content) {
309901
+ return this.baseCalculator.calculateContentTokens(content);
309902
+ }
309903
+ calculateTokensAndBaseUnits(nodes) {
309904
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
309905
+ return {
309906
+ tokens: Math.round(baseUnits * this.learnedWeight),
309907
+ baseUnits
309908
+ };
309909
+ }
309910
+ calculateContentTokensAndBaseUnits(content) {
309911
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
309912
+ return {
309913
+ tokens: Math.round(baseUnits * this.learnedWeight),
309914
+ baseUnits
309915
+ };
309916
+ }
309917
+ // --- Delegation and Weighting ---
309918
+ garbageCollectCache(liveNodeIds) {
309919
+ this.baseCalculator.garbageCollectCache(liveNodeIds);
309920
+ }
309921
+ cacheNodeTokens(node) {
309922
+ return this.baseCalculator.cacheNodeTokens(node);
309923
+ }
309924
+ calculateTokenBreakdown(nodes) {
309925
+ const raw = this.baseCalculator.calculateTokenBreakdown(nodes);
309926
+ return {
309927
+ text: Math.round(raw.text * this.learnedWeight),
309928
+ media: Math.round(raw.media * this.learnedWeight),
309929
+ tool: Math.round(raw.tool * this.learnedWeight),
309930
+ overhead: Math.round(raw.overhead * this.learnedWeight),
309931
+ total: Math.round(raw.total * this.learnedWeight)
309932
+ };
309933
+ }
309934
+ estimateTokensForParts(parts2) {
309935
+ const baseUnits = this.baseCalculator.estimateTokensForParts(parts2);
309936
+ return Math.round(baseUnits * this.learnedWeight);
309937
+ }
309938
+ getTokenCost(node) {
309939
+ const baseUnits = this.baseCalculator.getTokenCost(node);
309940
+ return Math.round(baseUnits * this.learnedWeight);
309941
+ }
309942
+ calculateConcreteListTokens(nodes) {
309943
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
309944
+ return Math.round(baseUnits * this.learnedWeight);
309945
+ }
309946
+ calculateContentTokens(content) {
309947
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
309948
+ return Math.round(baseUnits * this.learnedWeight);
309949
+ }
309950
+ estimateTokensForString(text) {
309951
+ const baseUnits = this.baseCalculator.estimateTokensForString(text);
309952
+ return Math.round(baseUnits * this.learnedWeight);
309953
+ }
309954
+ tokensToChars(tokens) {
309955
+ return this.baseCalculator.tokensToChars(tokens / this.learnedWeight);
309956
+ }
309957
+ };
309958
+
309959
+ // packages/core/src/context/graph/behaviorRegistry.ts
309960
+ var NodeBehaviorRegistry = class {
309961
+ behaviors = /* @__PURE__ */ new Map();
309962
+ register(behavior) {
309963
+ this.behaviors.set(behavior.type, behavior);
309964
+ }
309965
+ get(type2) {
309966
+ const behavior = this.behaviors.get(type2);
309967
+ if (!behavior) {
309968
+ throw new Error(`Unregistered Node type: ${type2}`);
309969
+ }
309970
+ return behavior;
309971
+ }
309972
+ };
309973
+
309974
+ // packages/core/src/context/graph/builtinBehaviors.ts
309975
+ var UserPromptBehavior = {
309976
+ type: "USER_PROMPT" /* USER_PROMPT */,
309977
+ getEstimatableParts(node) {
309978
+ return [node.payload];
309979
+ }
309980
+ };
309981
+ var AgentThoughtBehavior = {
309982
+ type: "AGENT_THOUGHT" /* AGENT_THOUGHT */,
309983
+ getEstimatableParts(node) {
309984
+ return [node.payload];
309985
+ }
309986
+ };
309987
+ var ToolExecutionBehavior = {
309988
+ type: "TOOL_EXECUTION" /* TOOL_EXECUTION */,
309989
+ getEstimatableParts(node) {
309990
+ return [node.payload];
309991
+ }
309992
+ };
309993
+ var MaskedToolBehavior = {
309994
+ type: "MASKED_TOOL" /* MASKED_TOOL */,
309995
+ getEstimatableParts(node) {
309996
+ return [node.payload];
309997
+ }
309998
+ };
309999
+ var AgentYieldBehavior = {
310000
+ type: "AGENT_YIELD" /* AGENT_YIELD */,
310001
+ getEstimatableParts() {
310002
+ return [];
310003
+ }
310004
+ };
310005
+ var SystemEventBehavior = {
310006
+ type: "SYSTEM_EVENT" /* SYSTEM_EVENT */,
310007
+ getEstimatableParts(node) {
310008
+ return [node.payload];
310009
+ }
310010
+ };
310011
+ var SnapshotBehavior = {
310012
+ type: "SNAPSHOT" /* SNAPSHOT */,
310013
+ getEstimatableParts(node) {
310014
+ return [node.payload];
310015
+ }
310016
+ };
310017
+ var RollingSummaryBehavior = {
310018
+ type: "ROLLING_SUMMARY" /* ROLLING_SUMMARY */,
310019
+ getEstimatableParts(node) {
310020
+ return [node.payload];
310021
+ }
310022
+ };
310023
+ function registerBuiltInBehaviors(registry2) {
310024
+ registry2.register(UserPromptBehavior);
310025
+ registry2.register(AgentThoughtBehavior);
310026
+ registry2.register(ToolExecutionBehavior);
310027
+ registry2.register(MaskedToolBehavior);
310028
+ registry2.register(AgentYieldBehavior);
310029
+ registry2.register(SystemEventBehavior);
310030
+ registry2.register(SnapshotBehavior);
310031
+ registry2.register(RollingSummaryBehavior);
310032
+ }
310033
+
309020
310034
  // packages/core/src/context/initializer.ts
309021
310035
  async function initializeContextManager(config2, chat, lastPromptId) {
309022
310036
  const isV1Enabled = config2.getContextManagementConfig().enabled;
@@ -309069,6 +310083,14 @@ async function initializeContextManager(config2, chat, lastPromptId) {
309069
310083
  sessionId: lastPromptId
309070
310084
  });
309071
310085
  const eventBus = new ContextEventBus();
310086
+ const charsPerToken = 3;
310087
+ const behaviorRegistry = new NodeBehaviorRegistry();
310088
+ registerBuiltInBehaviors(behaviorRegistry);
310089
+ const calculator = new AdaptiveTokenCalculator(
310090
+ charsPerToken,
310091
+ behaviorRegistry,
310092
+ eventBus
310093
+ );
309072
310094
  const env2 = new ContextEnvironmentImpl(
309073
310095
  () => config2.getBaseLlmClient(),
309074
310096
  config2.getSessionId(),
@@ -309076,8 +310098,13 @@ async function initializeContextManager(config2, chat, lastPromptId) {
309076
310098
  logDir,
309077
310099
  projectTempDir,
309078
310100
  tracer,
309079
- 4,
309080
- eventBus
310101
+ charsPerToken,
310102
+ eventBus,
310103
+ calculator,
310104
+ behaviorRegistry,
310105
+ {
310106
+ calibrateTokenCalculation: !!process.env["GEMINI_CONTEXT_CALIBRATE_TOKEN_CALCULATIONS"]
310107
+ }
309081
310108
  );
309082
310109
  const orchestrator = new PipelineOrchestrator(
309083
310110
  sidecarProfile.buildPipelines(env2),
@@ -309092,6 +310119,7 @@ async function initializeContextManager(config2, chat, lastPromptId) {
309092
310119
  tracer,
309093
310120
  orchestrator,
309094
310121
  chat.agentHistory,
310122
+ calculator,
309095
310123
  async () => {
309096
310124
  const parts2 = await getEnvironmentContext(config2);
309097
310125
  return { role: "user", parts: parts2 };
@@ -309506,10 +310534,20 @@ var GeminiClient = class {
309506
310534
  return turn;
309507
310535
  }
309508
310536
  const modelForLimitCheck = this._getActiveModelForCurrentTurn();
310537
+ let currentBaseUnits = 0;
309509
310538
  if (this.config.getContextManagementConfig().enabled) {
309510
310539
  if (this.contextManager) {
309511
310540
  const pendingRequest = createUserContent(request);
309512
- const { history: newHistory, didApplyManagement } = await this.contextManager.renderHistory(pendingRequest);
310541
+ const {
310542
+ history: newHistory,
310543
+ didApplyManagement,
310544
+ baseUnits
310545
+ } = await this.contextManager.renderHistory(
310546
+ pendingRequest,
310547
+ void 0,
310548
+ signal
310549
+ );
310550
+ currentBaseUnits = baseUnits;
309513
310551
  if (didApplyManagement) {
309514
310552
  this.getChat().setHistory(newHistory, { silent: true });
309515
310553
  }
@@ -309633,6 +310671,15 @@ var GeminiClient = class {
309633
310671
  break;
309634
310672
  }
309635
310673
  yield event;
310674
+ if (event.type === "finished" /* Finished */ && this.contextManager) {
310675
+ const usageMetadata = event.value.usageMetadata;
310676
+ if (usageMetadata && usageMetadata.promptTokenCount !== void 0) {
310677
+ this.contextManager.getEnvironment().eventBus.emitTokenGroundTruth({
310678
+ actualTokens: usageMetadata.promptTokenCount,
310679
+ promptBaseUnits: currentBaseUnits
310680
+ });
310681
+ }
310682
+ }
309636
310683
  this.updateTelemetryTokenCount();
309637
310684
  if (event.type === "error" /* Error */) {
309638
310685
  isError = true;
@@ -310277,7 +311324,8 @@ var ToolExecutor = class {
310277
311324
  new Error(toolResult.error.message),
310278
311325
  toolResult.error.type,
310279
311326
  displayText,
310280
- toolResult.tailToolCallRequest
311327
+ toolResult.tailToolCallRequest,
311328
+ toolResult.display
310281
311329
  );
310282
311330
  }
310283
311331
  } catch (executionError) {
@@ -310420,6 +311468,7 @@ var ToolExecutor = class {
310420
311468
  response: {
310421
311469
  callId: call.request.callId,
310422
311470
  responseParts,
311471
+ display: toolResult?.display,
310423
311472
  resultDisplay: toolResult?.returnDisplay,
310424
311473
  error: void 0,
310425
311474
  errorType: void 0,
@@ -310448,6 +311497,7 @@ var ToolExecutor = class {
310448
311497
  const successResponse = {
310449
311498
  callId,
310450
311499
  responseParts: response,
311500
+ display: toolResult.display,
310451
311501
  resultDisplay: toolResult.returnDisplay,
310452
311502
  error: void 0,
310453
311503
  errorType: void 0,
@@ -310472,12 +311522,13 @@ var ToolExecutor = class {
310472
311522
  tailToolCallRequest: toolResult.tailToolCallRequest
310473
311523
  };
310474
311524
  }
310475
- createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest) {
311525
+ createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest, display) {
310476
311526
  const response = this.createErrorResponse(
310477
311527
  call.request,
310478
311528
  error40,
310479
311529
  errorType,
310480
- returnDisplay
311530
+ returnDisplay,
311531
+ display
310481
311532
  );
310482
311533
  const startTime = "startTime" in call ? call.startTime : void 0;
310483
311534
  return {
@@ -310492,11 +311543,12 @@ var ToolExecutor = class {
310492
311543
  tailToolCallRequest
310493
311544
  };
310494
311545
  }
310495
- createErrorResponse(request, error40, errorType, returnDisplay) {
311546
+ createErrorResponse(request, error40, errorType, returnDisplay, display) {
310496
311547
  const displayText = returnDisplay ?? error40.message;
310497
311548
  return {
310498
311549
  callId: request.callId,
310499
311550
  error: error40,
311551
+ display,
310500
311552
  responseParts: [
310501
311553
  {
310502
311554
  functionResponse: {
@@ -310809,6 +311861,16 @@ var Scheduler = class {
310809
311861
  () => {
310810
311862
  try {
310811
311863
  const invocation = tool.build(request.args);
311864
+ if (!request.display) {
311865
+ request.display = populateToolDisplay({
311866
+ name: tool.name,
311867
+ invocation,
311868
+ displayName: tool.displayName
311869
+ });
311870
+ if (!request.display.description) {
311871
+ request.display.description = tool.description;
311872
+ }
311873
+ }
310812
311874
  return {
310813
311875
  status: "validating" /* Validating */,
310814
311876
  request,
@@ -311674,8 +312736,8 @@ var WorkspaceContext = class {
311674
312736
  * @returns True if the path is within the root directory, false otherwise
311675
312737
  */
311676
312738
  isPathWithinRoot(pathToCheck, rootDirectory) {
311677
- const relative12 = path61.relative(rootDirectory, pathToCheck);
311678
- return !relative12.startsWith(`..${path61.sep}`) && relative12 !== ".." && !path61.isAbsolute(relative12);
312739
+ const relative11 = path61.relative(rootDirectory, pathToCheck);
312740
+ return !relative11.startsWith(`..${path61.sep}`) && relative11 !== ".." && !path61.isAbsolute(relative11);
311679
312741
  }
311680
312742
  };
311681
312743
 
@@ -312023,6 +313085,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
312023
313085
  compressionService;
312024
313086
  parentCallId;
312025
313087
  hasFailedCompressionAttempt = false;
313088
+ cache;
312026
313089
  get executionContext() {
312027
313090
  return {
312028
313091
  config: this.context.config,
@@ -312159,6 +313222,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
312159
313222
  this.onActivity = onActivity;
312160
313223
  this.compressionService = new ChatCompressionService();
312161
313224
  this.parentCallId = parentCallId;
313225
+ this.cache = new import_lru_cache.default(10);
312162
313226
  this.agentId = Math.random().toString(36).slice(2, 8);
312163
313227
  }
312164
313228
  /**
@@ -312397,7 +313461,14 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
312397
313461
  "user_steering"
312398
313462
  );
312399
313463
  const formattedInitialHints = formatUserHintsForModel(initialHints);
312400
- const environmentMemory = this.context.config.isJitContextEnabled?.() ? this.context.config.getSessionMemory() : this.context.config.getEnvironmentMemory();
313464
+ let environmentMemory;
313465
+ if (this.context.config.isJitContextEnabled?.()) {
313466
+ environmentMemory = this.definition.includeExtensionContext === false ? this.context.config.getSessionMemory({
313467
+ includeExtensionContext: false
313468
+ }) : this.context.config.getSessionMemory();
313469
+ } else {
313470
+ environmentMemory = this.context.config.getEnvironmentMemory();
313471
+ }
312401
313472
  const initialParts = [];
312402
313473
  if (environmentMemory) {
312403
313474
  initialParts.push({ text: environmentMemory });
@@ -312627,22 +313698,26 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
312627
313698
  const requestedModel = resolvedConfig.model;
312628
313699
  let modelToUse;
312629
313700
  if (isAutoModel(requestedModel)) {
312630
- try {
312631
- const routingContext = {
312632
- history: chat.getHistory(
312633
- /*curated=*/
312634
- true
312635
- ),
312636
- request: message.parts || [],
312637
- signal,
312638
- requestedModel
312639
- };
312640
- const router = this.context.config.getModelRouterService();
312641
- const decision = await router.route(routingContext);
312642
- modelToUse = decision.model;
312643
- } catch (error40) {
312644
- debugLogger.warn(`Error during model routing: ${error40}`);
312645
- modelToUse = DEFAULT_GEMINI_MODEL;
313701
+ modelToUse = this.cache.get("modelToUse");
313702
+ if (!modelToUse) {
313703
+ try {
313704
+ const routingContext = {
313705
+ history: chat.getHistory(
313706
+ /*curated=*/
313707
+ true
313708
+ ),
313709
+ request: message.parts || [],
313710
+ signal,
313711
+ requestedModel
313712
+ };
313713
+ const router = this.context.config.getModelRouterService();
313714
+ const decision = await router.route(routingContext);
313715
+ modelToUse = decision.model;
313716
+ } catch (error40) {
313717
+ debugLogger.warn(`Error during model routing: ${error40}`);
313718
+ modelToUse = DEFAULT_GEMINI_MODEL;
313719
+ }
313720
+ this.cache.set("modelToUse", modelToUse);
312646
313721
  }
312647
313722
  } else {
312648
313723
  modelToUse = requestedModel;
@@ -312879,12 +313954,16 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
312879
313954
  const part = syncResults.get(callId);
312880
313955
  if (part) {
312881
313956
  toolResponseParts.push(part);
313957
+ continue;
312882
313958
  }
312883
- }
312884
- if (functionCalls.length > 0 && toolResponseParts.length === 0 && !taskCompleted) {
312885
- toolResponseParts.push({
312886
- text: "All tool calls failed or were unauthorized. Please analyze the errors and try an alternative approach."
312887
- });
313959
+ const isAborted = signal.aborted;
313960
+ const isTaskComplete = functionCall.name === COMPLETE_TASK_TOOL_NAME && taskCompleted;
313961
+ if (isAborted || isTaskComplete) {
313962
+ continue;
313963
+ }
313964
+ throw new Error(
313965
+ `[LocalAgentExecutor] Critical System Failure: Tool execution result was lost/dropped by the scheduler for callId ${callId} (${functionCall.name}). This indicates an internal race condition or scheduler bug.`
313966
+ );
312888
313967
  }
312889
313968
  return {
312890
313969
  nextMessage: { role: "user", parts: toolResponseParts },
@@ -313218,7 +314297,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313218
314297
  isSubagentProgress: true,
313219
314298
  agentName: this.definition.name,
313220
314299
  recentActivity: [],
313221
- state: "running"
314300
+ state: "running" /* RUNNING */
313222
314301
  };
313223
314302
  updateOutput(initialProgress);
313224
314303
  }
@@ -313229,14 +314308,14 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313229
314308
  case "THOUGHT_CHUNK": {
313230
314309
  const text = String(activity.data["text"]);
313231
314310
  const lastItem = recentActivity[recentActivity.length - 1];
313232
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
314311
+ if (lastItem && lastItem.type === "thought" && lastItem.status === "running" /* RUNNING */) {
313233
314312
  lastItem.content = sanitizeThoughtContent(text);
313234
314313
  } else {
313235
314314
  recentActivity.push({
313236
314315
  id: randomUUID14(),
313237
314316
  type: "thought",
313238
314317
  content: sanitizeThoughtContent(text),
313239
- status: "running"
314318
+ status: "running" /* RUNNING */
313240
314319
  });
313241
314320
  }
313242
314321
  updated = true;
@@ -313260,7 +314339,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313260
314339
  displayName,
313261
314340
  description,
313262
314341
  args: args2,
313263
- status: "running"
314342
+ status: "running" /* RUNNING */
313264
314343
  });
313265
314344
  updated = true;
313266
314345
  const latestTool = recentActivity[recentActivity.length - 1];
@@ -313274,8 +314353,8 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313274
314353
  const data = activity.data["data"];
313275
314354
  const isError = isToolActivityError(data);
313276
314355
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
313277
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === name3 && recentActivity[i3].status === "running") {
313278
- recentActivity[i3].status = isError ? "error" : "completed";
314356
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === name3 && recentActivity[i3].status === "running" /* RUNNING */) {
314357
+ recentActivity[i3].status = isError ? "error" /* ERROR */ : "completed" /* COMPLETED */;
313279
314358
  updated = true;
313280
314359
  this.publishActivity(recentActivity[i3]);
313281
314360
  break;
@@ -313292,16 +314371,16 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313292
314371
  const toolName = activity.data["name"] ? String(activity.data["name"]) : void 0;
313293
314372
  if (toolName && (isCancellation || isRejection)) {
313294
314373
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
313295
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running") {
313296
- recentActivity[i3].status = "cancelled";
314374
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running" /* RUNNING */) {
314375
+ recentActivity[i3].status = "cancelled" /* CANCELLED */;
313297
314376
  updated = true;
313298
314377
  break;
313299
314378
  }
313300
314379
  }
313301
314380
  } else if (toolName) {
313302
314381
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
313303
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running") {
313304
- recentActivity[i3].status = "error";
314382
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running" /* RUNNING */) {
314383
+ recentActivity[i3].status = "error" /* ERROR */;
313305
314384
  updated = true;
313306
314385
  break;
313307
314386
  }
@@ -313311,7 +314390,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313311
314390
  id: randomUUID14(),
313312
314391
  type: "thought",
313313
314392
  content: isCancellation || isRejection ? sanitizedError : `Error: ${sanitizedError}`,
313314
- status: isCancellation || isRejection ? "cancelled" : "error"
314393
+ status: isCancellation || isRejection ? "cancelled" /* CANCELLED */ : "error" /* ERROR */
313315
314394
  });
313316
314395
  updated = true;
313317
314396
  break;
@@ -313325,7 +314404,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313325
314404
  agentName: this.definition.name,
313326
314405
  recentActivity: [...recentActivity],
313327
314406
  // Copy to avoid mutation issues
313328
- state: "running"
314407
+ state: "running" /* RUNNING */
313329
314408
  };
313330
314409
  updateOutput(progress2);
313331
314410
  }
@@ -313341,7 +314420,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313341
314420
  isSubagentProgress: true,
313342
314421
  agentName: this.definition.name,
313343
314422
  recentActivity: [...recentActivity],
313344
- state: "cancelled"
314423
+ state: "cancelled" /* CANCELLED */
313345
314424
  };
313346
314425
  if (updateOutput) {
313347
314426
  updateOutput(progress2);
@@ -313354,7 +314433,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
313354
314433
  isSubagentProgress: true,
313355
314434
  agentName: this.definition.name,
313356
314435
  recentActivity: [...recentActivity],
313357
- state: "completed",
314436
+ state: "completed" /* COMPLETED */,
313358
314437
  result: output.result,
313359
314438
  terminateReason: output.terminate_reason
313360
314439
  };
@@ -313375,18 +314454,18 @@ ${output.result}`;
313375
314454
  debugLogger.error(`Subagent '${this.definition.name}' failed:`, error40);
313376
314455
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || errorMessage.includes("Aborted");
313377
314456
  for (const item of recentActivity) {
313378
- if (item.status === "running") {
313379
- item.status = isAbort ? "cancelled" : "error";
314457
+ if (item.status === "running" /* RUNNING */) {
314458
+ item.status = isAbort ? "cancelled" /* CANCELLED */ : "error" /* ERROR */;
313380
314459
  }
313381
314460
  }
313382
314461
  if (!isAbort) {
313383
314462
  const lastActivity = recentActivity[recentActivity.length - 1];
313384
- if (!lastActivity || lastActivity.status !== "error") {
314463
+ if (!lastActivity || lastActivity.status !== "error" /* ERROR */) {
313385
314464
  recentActivity.push({
313386
314465
  id: randomUUID14(),
313387
314466
  type: "thought",
313388
314467
  content: `Error: ${errorMessage}`,
313389
- status: "error"
314468
+ status: "error" /* ERROR */
313390
314469
  });
313391
314470
  }
313392
314471
  }
@@ -313394,7 +314473,7 @@ ${output.result}`;
313394
314473
  isSubagentProgress: true,
313395
314474
  agentName: this.definition.name,
313396
314475
  recentActivity: [...recentActivity],
313397
- state: isAbort ? "cancelled" : "error"
314476
+ state: isAbort ? "cancelled" /* CANCELLED */ : "error" /* ERROR */
313398
314477
  };
313399
314478
  if (updateOutput) {
313400
314479
  updateOutput(progress);
@@ -313506,7 +314585,7 @@ var A2AResultReassembler = class {
313506
314585
  id: "auth-required",
313507
314586
  type: "thought",
313508
314587
  content: AUTH_REQUIRED_MSG,
313509
- status: "running"
314588
+ status: "running" /* RUNNING */
313510
314589
  });
313511
314590
  }
313512
314591
  this.messageLog.forEach((msg, index) => {
@@ -313514,7 +314593,7 @@ var A2AResultReassembler = class {
313514
314593
  id: `msg-${index}`,
313515
314594
  type: "thought",
313516
314595
  content: msg.trim(),
313517
- status: "completed"
314596
+ status: "completed" /* COMPLETED */
313518
314597
  });
313519
314598
  });
313520
314599
  if (items.length === 0 && !isAuthRequired) {
@@ -313522,7 +314601,7 @@ var A2AResultReassembler = class {
313522
314601
  id: "pending",
313523
314602
  type: "thought",
313524
314603
  content: "Working...",
313525
- status: "running"
314604
+ status: "running" /* RUNNING */
313526
314605
  });
313527
314606
  }
313528
314607
  return items;
@@ -313714,13 +314793,13 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
313714
314793
  updateOutput({
313715
314794
  isSubagentProgress: true,
313716
314795
  agentName,
313717
- state: "running",
314796
+ state: "running" /* RUNNING */,
313718
314797
  recentActivity: [
313719
314798
  {
313720
314799
  id: "pending",
313721
314800
  type: "thought",
313722
314801
  content: "Working...",
313723
- status: "running"
314802
+ status: "running" /* RUNNING */
313724
314803
  }
313725
314804
  ]
313726
314805
  });
@@ -313761,7 +314840,7 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
313761
314840
  updateOutput({
313762
314841
  isSubagentProgress: true,
313763
314842
  agentName,
313764
- state: "running",
314843
+ state: "running" /* RUNNING */,
313765
314844
  recentActivity: reassembler.toActivityItems(),
313766
314845
  result: reassembler.toString()
313767
314846
  });
@@ -313787,7 +314866,7 @@ ${JSON.stringify(finalResponse, null, 2)}`
313787
314866
  const finalProgress = {
313788
314867
  isSubagentProgress: true,
313789
314868
  agentName,
313790
- state: "completed",
314869
+ state: "completed" /* COMPLETED */,
313791
314870
  result: finalOutput,
313792
314871
  recentActivity: reassembler.toActivityItems()
313793
314872
  };
@@ -313807,7 +314886,7 @@ ${errorMessage}` : errorMessage;
313807
314886
  const errorProgress = {
313808
314887
  isSubagentProgress: true,
313809
314888
  agentName,
313810
- state: "error",
314889
+ state: "error" /* ERROR */,
313811
314890
  result: fullDisplay,
313812
314891
  recentActivity: reassembler.toActivityItems()
313813
314892
  };
@@ -315512,7 +316591,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315512
316591
  isSubagentProgress: true,
315513
316592
  agentName: this.agentName,
315514
316593
  recentActivity: [],
315515
- state: "running"
316594
+ state: "running" /* RUNNING */
315516
316595
  };
315517
316596
  updateOutput(initialProgress);
315518
316597
  }
@@ -315522,7 +316601,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315522
316601
  id: randomUUID15(),
315523
316602
  type: "thought",
315524
316603
  content: sanitizedMsg,
315525
- status: "completed"
316604
+ status: "completed" /* COMPLETED */
315526
316605
  });
315527
316606
  if (recentActivity.length > MAX_RECENT_ACTIVITY) {
315528
316607
  recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
@@ -315531,7 +316610,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315531
316610
  isSubagentProgress: true,
315532
316611
  agentName: this.agentName,
315533
316612
  recentActivity: [...recentActivity],
315534
- state: "running"
316613
+ state: "running" /* RUNNING */
315535
316614
  });
315536
316615
  } : void 0;
315537
316616
  const result2 = await createBrowserAgentDefinition(
@@ -315550,14 +316629,14 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315550
316629
  case "THOUGHT_CHUNK": {
315551
316630
  const text = String(activity.data["text"]);
315552
316631
  const lastItem = recentActivity[recentActivity.length - 1];
315553
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
316632
+ if (lastItem && lastItem.type === "thought" && lastItem.status === "running" /* RUNNING */) {
315554
316633
  lastItem.content = sanitizeThoughtContent(text);
315555
316634
  } else {
315556
316635
  recentActivity.push({
315557
316636
  id: randomUUID15(),
315558
316637
  type: "thought",
315559
316638
  content: sanitizeThoughtContent(text),
315560
- status: "running"
316639
+ status: "running" /* RUNNING */
315561
316640
  });
315562
316641
  }
315563
316642
  updated = true;
@@ -315578,7 +316657,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315578
316657
  displayName,
315579
316658
  description,
315580
316659
  args: args2,
315581
- status: "running"
316660
+ status: "running" /* RUNNING */
315582
316661
  });
315583
316662
  updated = true;
315584
316663
  break;
@@ -315588,8 +316667,8 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315588
316667
  const data = activity.data["data"];
315589
316668
  const isError = isToolActivityError(data);
315590
316669
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
315591
- if (recentActivity[i3].type === "tool_call" && callId != null && recentActivity[i3].id === callId && recentActivity[i3].status === "running") {
315592
- recentActivity[i3].status = isError ? "error" : "completed";
316670
+ if (recentActivity[i3].type === "tool_call" && callId != null && recentActivity[i3].id === callId && recentActivity[i3].status === "running" /* RUNNING */) {
316671
+ recentActivity[i3].status = isError ? "error" /* ERROR */ : "completed" /* COMPLETED */;
315593
316672
  updated = true;
315594
316673
  break;
315595
316674
  }
@@ -315600,10 +316679,10 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315600
316679
  const error40 = String(activity.data["error"]);
315601
316680
  const isCancellation = error40 === "Request cancelled.";
315602
316681
  const callId = activity.data["callId"] ? String(activity.data["callId"]) : void 0;
315603
- const newStatus = isCancellation ? "cancelled" : "error";
316682
+ const newStatus = isCancellation ? "cancelled" /* CANCELLED */ : "error" /* ERROR */;
315604
316683
  if (callId) {
315605
316684
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
315606
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === "running") {
316685
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === "running" /* RUNNING */) {
315607
316686
  recentActivity[i3].status = newStatus;
315608
316687
  updated = true;
315609
316688
  break;
@@ -315611,7 +316690,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315611
316690
  }
315612
316691
  } else {
315613
316692
  for (const item of recentActivity) {
315614
- if (item.type === "tool_call" && item.status === "running") {
316693
+ if (item.type === "tool_call" && item.status === "running" /* RUNNING */) {
315615
316694
  item.status = newStatus;
315616
316695
  updated = true;
315617
316696
  }
@@ -315638,7 +316717,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
315638
316717
  isSubagentProgress: true,
315639
316718
  agentName: this.agentName,
315640
316719
  recentActivity: [...recentActivity],
315641
- state: "running"
316720
+ state: "running" /* RUNNING */
315642
316721
  };
315643
316722
  updateOutput(progress2);
315644
316723
  }
@@ -315664,11 +316743,11 @@ Result:
315664
316743
  ${output.result}`;
315665
316744
  let progressState;
315666
316745
  if (output.terminate_reason === "ABORTED" /* ABORTED */) {
315667
- progressState = "cancelled";
316746
+ progressState = "cancelled" /* CANCELLED */;
315668
316747
  } else if (output.terminate_reason === "GOAL" /* GOAL */) {
315669
- progressState = "completed";
316748
+ progressState = "completed" /* COMPLETED */;
315670
316749
  } else {
315671
- progressState = "error";
316750
+ progressState = "error" /* ERROR */;
315672
316751
  }
315673
316752
  const progress = {
315674
316753
  isSubagentProgress: true,
@@ -315690,15 +316769,15 @@ ${output.result}`;
315690
316769
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || rawErrorMessage.includes("Aborted");
315691
316770
  const errorMessage = sanitizeErrorMessage(rawErrorMessage);
315692
316771
  for (const item of recentActivity) {
315693
- if (item.status === "running") {
315694
- item.status = isAbort ? "cancelled" : "error";
316772
+ if (item.status === "running" /* RUNNING */) {
316773
+ item.status = isAbort ? "cancelled" /* CANCELLED */ : "error" /* ERROR */;
315695
316774
  }
315696
316775
  }
315697
316776
  const progress = {
315698
316777
  isSubagentProgress: true,
315699
316778
  agentName: this.agentName,
315700
316779
  recentActivity: [...recentActivity],
315701
- state: isAbort ? "cancelled" : "error"
316780
+ state: isAbort ? "cancelled" /* CANCELLED */ : "error" /* ERROR */
315702
316781
  };
315703
316782
  if (updateOutput) {
315704
316783
  updateOutput(progress);
@@ -321099,9 +322178,18 @@ var GitService = class _GitService {
321099
322178
  const gitConfigPath = path66.join(repoDir, ".gitconfig");
321100
322179
  const systemConfigPath = path66.join(repoDir, ".gitconfig_system_empty");
321101
322180
  return {
322181
+ ...sanitizeEnvironment(
322182
+ process.env,
322183
+ getSecureSanitizationConfig({
322184
+ enableEnvironmentVariableRedaction: true
322185
+ })
322186
+ ),
321102
322187
  // Prevent git from using the user's global git config.
321103
322188
  GIT_CONFIG_GLOBAL: gitConfigPath,
321104
322189
  GIT_CONFIG_SYSTEM: systemConfigPath,
322190
+ // Ensure we don't inherit isolation-breaking variables from the user environment.
322191
+ GIT_DIR: void 0,
322192
+ GIT_WORK_TREE: void 0,
321105
322193
  // Explicitly provide identity to prevent "Author identity unknown" errors
321106
322194
  // inside sandboxed environments like Docker where the gitconfig might not
321107
322195
  // be picked up properly.
@@ -321158,9 +322246,9 @@ var GitService = class _GitService {
321158
322246
  get shadowGitRepository() {
321159
322247
  const repoDir = this.getHistoryDir();
321160
322248
  return simpleGit(this.projectRoot).env({
322249
+ ...this.getShadowRepoEnv(repoDir),
321161
322250
  GIT_DIR: path66.join(repoDir, ".git"),
321162
- GIT_WORK_TREE: this.projectRoot,
321163
- ...this.getShadowRepoEnv(repoDir)
322251
+ GIT_WORK_TREE: this.projectRoot
321164
322252
  });
321165
322253
  }
321166
322254
  async getCurrentCommitHash() {
@@ -322109,16 +323197,19 @@ var TrackerVisualizeTool = class _TrackerVisualizeTool extends BaseDeclarativeTo
322109
323197
  // packages/core/src/availability/modelAvailabilityService.ts
322110
323198
  var ModelAvailabilityService = class {
322111
323199
  health = /* @__PURE__ */ new Map();
322112
- markTerminal(model, reason) {
323200
+ markTerminal(modelId, reason) {
323201
+ const model = normalizeModelId(modelId);
322113
323202
  this.setState(model, {
322114
323203
  status: "terminal",
322115
323204
  reason
322116
323205
  });
322117
323206
  }
322118
- markHealthy(model) {
323207
+ markHealthy(modelId) {
323208
+ const model = normalizeModelId(modelId);
322119
323209
  this.clearState(model);
322120
323210
  }
322121
- markRetryOncePerTurn(model, attempts = 1) {
323211
+ markRetryOncePerTurn(modelId, attempts = 1) {
323212
+ const model = normalizeModelId(modelId);
322122
323213
  const currentState = this.health.get(model);
322123
323214
  if (currentState?.status === "terminal") {
322124
323215
  return;
@@ -322134,13 +323225,15 @@ var ModelAvailabilityService = class {
322134
323225
  attempts
322135
323226
  });
322136
323227
  }
322137
- consumeStickyAttempt(model) {
323228
+ consumeStickyAttempt(modelId) {
323229
+ const model = normalizeModelId(modelId);
322138
323230
  const state = this.health.get(model);
322139
323231
  if (state?.status === "sticky_retry") {
322140
323232
  this.setState(model, { ...state, consumed: true });
322141
323233
  }
322142
323234
  }
322143
- snapshot(model) {
323235
+ snapshot(modelId) {
323236
+ const model = normalizeModelId(modelId);
322144
323237
  const state = this.health.get(model);
322145
323238
  if (!state) {
322146
323239
  return { available: true };
@@ -322153,9 +323246,10 @@ var ModelAvailabilityService = class {
322153
323246
  }
322154
323247
  return { available: true };
322155
323248
  }
322156
- selectFirstAvailable(models) {
323249
+ selectFirstAvailable(modelIds) {
322157
323250
  const skipped = [];
322158
- for (const model of models) {
323251
+ for (const modelId of modelIds) {
323252
+ const model = normalizeModelId(modelId);
322159
323253
  const snapshot = this.snapshot(model);
322160
323254
  if (snapshot.available) {
322161
323255
  const state = this.health.get(model);
@@ -322331,9 +323425,25 @@ ${formattedHistory}
322331
323425
  const routerResponse = ClassifierResponseSchema.parse(jsonResponse);
322332
323426
  const reasoning = routerResponse.reasoning;
322333
323427
  const latencyMs = Date.now() - startTime;
323428
+ const [
323429
+ useGemini3_1,
323430
+ useGemini3_1FlashLite,
323431
+ useCustomToolModel,
323432
+ hasAccessToPreview
323433
+ ] = await Promise.all([
323434
+ config2.getGemini31Launched(),
323435
+ config2.getGemini31FlashLiteLaunched(),
323436
+ config2.getUseCustomToolModel(),
323437
+ config2.getHasAccessToPreviewModel?.() ?? true
323438
+ ]);
322334
323439
  const selectedModel = resolveClassifierModel(
322335
323440
  context2.requestedModel ?? config2.getModel(),
322336
- routerResponse.model_choice
323441
+ routerResponse.model_choice,
323442
+ useGemini3_1,
323443
+ useGemini3_1FlashLite,
323444
+ useCustomToolModel,
323445
+ hasAccessToPreview,
323446
+ config2
322337
323447
  );
322338
323448
  return {
322339
323449
  model: selectedModel,
@@ -322501,15 +323611,25 @@ var ClassifierStrategy = class {
322501
323611
  config2.getGemini31FlashLiteLaunched(),
322502
323612
  config2.getUseCustomToolModel()
322503
323613
  ]);
322504
- const selectedModel = resolveClassifierModel(
322505
- model,
322506
- routerResponse.model_choice,
322507
- useGemini3_1,
322508
- useGemini3_1FlashLite,
322509
- useCustomToolModel,
322510
- config2.getHasAccessToPreviewModel?.() ?? true,
322511
- config2
323614
+ const selectedModel = normalizeModelId(
323615
+ resolveClassifierModel(
323616
+ normalizeModelId(model),
323617
+ routerResponse.model_choice,
323618
+ useGemini3_1,
323619
+ useGemini3_1FlashLite,
323620
+ useCustomToolModel,
323621
+ config2.getHasAccessToPreviewModel?.() ?? true,
323622
+ config2
323623
+ )
322512
323624
  );
323625
+ const service = config2.getModelAvailabilityService();
323626
+ const snapshot = service.snapshot(selectedModel);
323627
+ if (!snapshot.available) {
323628
+ debugLogger.warn(
323629
+ `[Routing] Classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`
323630
+ );
323631
+ return null;
323632
+ }
322513
323633
  return {
322514
323634
  model: selectedModel,
322515
323635
  metadata: {
@@ -322607,7 +323727,15 @@ var NumericalClassifierStrategy = class {
322607
323727
  return null;
322608
323728
  }
322609
323729
  const promptId = getPromptIdWithFallback("classifier-router");
322610
- const finalHistory = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
323730
+ const candidateSlice = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
323731
+ let firstTextIndex = -1;
323732
+ for (let i3 = 0; i3 < candidateSlice.length; i3++) {
323733
+ if (!isFunctionCall(candidateSlice[i3]) && !isFunctionResponse(candidateSlice[i3])) {
323734
+ firstTextIndex = i3;
323735
+ break;
323736
+ }
323737
+ }
323738
+ const finalHistory = firstTextIndex === -1 ? [] : candidateSlice.slice(firstTextIndex);
322611
323739
  const requestParts = Array.isArray(context2.request) ? context2.request : [context2.request];
322612
323740
  const sanitizedRequest = requestParts.map((part) => {
322613
323741
  if (typeof part === "string") {
@@ -322635,15 +323763,25 @@ var NumericalClassifierStrategy = class {
322635
323763
  config2.getGemini31FlashLiteLaunched(),
322636
323764
  config2.getUseCustomToolModel()
322637
323765
  ]);
322638
- const selectedModel = resolveClassifierModel(
322639
- model,
322640
- modelAlias,
322641
- useGemini3_1,
322642
- useGemini3_1FlashLite,
322643
- useCustomToolModel,
322644
- config2.getHasAccessToPreviewModel?.() ?? true,
322645
- config2
323766
+ const selectedModel = normalizeModelId(
323767
+ resolveClassifierModel(
323768
+ normalizeModelId(model),
323769
+ modelAlias,
323770
+ useGemini3_1,
323771
+ useGemini3_1FlashLite,
323772
+ useCustomToolModel,
323773
+ config2.getHasAccessToPreviewModel?.() ?? true,
323774
+ config2
323775
+ )
322646
323776
  );
323777
+ const service = config2.getModelAvailabilityService();
323778
+ const snapshot = service.snapshot(selectedModel);
323779
+ if (!snapshot.available) {
323780
+ debugLogger.warn(
323781
+ `[Routing] Numerical classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`
323782
+ );
323783
+ return null;
323784
+ }
322647
323785
  const latencyMs = Date.now() - startTime;
322648
323786
  return {
322649
323787
  model: selectedModel,
@@ -322819,16 +323957,26 @@ var ApprovalModeStrategy = class {
322819
323957
  const startTime = Date.now();
322820
323958
  const approvalMode = config2.getApprovalMode();
322821
323959
  const approvedPlanPath = config2.getApprovedPlanPath();
322822
- const [useGemini3_1, useCustomToolModel] = await Promise.all([
323960
+ const [
323961
+ useGemini3_1,
323962
+ useGemini3_1FlashLite,
323963
+ useCustomToolModel,
323964
+ hasAccessToPreview
323965
+ ] = await Promise.all([
322823
323966
  config2.getGemini31Launched(),
322824
- config2.getUseCustomToolModel()
323967
+ config2.getGemini31FlashLiteLaunched(),
323968
+ config2.getUseCustomToolModel(),
323969
+ config2.getHasAccessToPreviewModel()
322825
323970
  ]);
322826
323971
  if (approvalMode === "plan" /* PLAN */) {
322827
323972
  const proModel = resolveClassifierModel(
322828
323973
  model,
322829
323974
  GEMINI_MODEL_ALIAS_PRO,
322830
323975
  useGemini3_1,
322831
- useCustomToolModel
323976
+ useGemini3_1FlashLite,
323977
+ useCustomToolModel,
323978
+ hasAccessToPreview,
323979
+ config2
322832
323980
  );
322833
323981
  return {
322834
323982
  model: proModel,
@@ -322843,7 +323991,10 @@ var ApprovalModeStrategy = class {
322843
323991
  model,
322844
323992
  GEMINI_MODEL_ALIAS_FLASH,
322845
323993
  useGemini3_1,
322846
- useCustomToolModel
323994
+ useGemini3_1FlashLite,
323995
+ useCustomToolModel,
323996
+ hasAccessToPreview,
323997
+ config2
322847
323998
  );
322848
323999
  return {
322849
324000
  model: flashModel,
@@ -323170,6 +324321,19 @@ var DEFAULT_MODEL_CONFIGS = {
323170
324321
  extends: "gemini-3-flash-base",
323171
324322
  modelConfig: {}
323172
324323
  },
324324
+ "context-snapshotter": {
324325
+ extends: "gemini-3-flash-base",
324326
+ modelConfig: {
324327
+ generateContentConfig: {
324328
+ thinkingConfig: {
324329
+ thinkingLevel: ThinkingLevel.HIGH
324330
+ },
324331
+ temperature: 1,
324332
+ topP: 0.95,
324333
+ topK: 64
324334
+ }
324335
+ }
324336
+ },
323173
324337
  "chat-compression-3-pro": {
323174
324338
  modelConfig: {
323175
324339
  model: "gemini-3-pro-preview"
@@ -326076,7 +327240,7 @@ var HookEventHandler = class {
326076
327240
  result2.error?.message
326077
327241
  );
326078
327242
  logHookCall(this.context.config, hookCallEvent);
326079
- if (result2.output?.systemMessage && result2.outputFormat === "json") {
327243
+ if (result2.output?.systemMessage) {
326080
327244
  coreEvents.emitHookSystemMessage({
326081
327245
  hookName,
326082
327246
  eventName,
@@ -328287,8 +329451,8 @@ var AllowedPathChecker = class {
328287
329451
  while (current && current !== path73.dirname(current)) {
328288
329452
  if (fs65.existsSync(current)) {
328289
329453
  const canonical = fs65.realpathSync(current);
328290
- const relative12 = path73.relative(current, resolved);
328291
- return path73.join(canonical, relative12);
329454
+ const relative11 = path73.relative(current, resolved);
329455
+ return path73.join(canonical, relative11);
328292
329456
  }
328293
329457
  current = path73.dirname(current);
328294
329458
  }
@@ -328298,8 +329462,8 @@ var AllowedPathChecker = class {
328298
329462
  }
328299
329463
  }
328300
329464
  isPathAllowed(targetPath, allowedDir) {
328301
- const relative12 = path73.relative(allowedDir, targetPath);
328302
- return relative12 === "" || !relative12.startsWith("..") && !path73.isAbsolute(relative12);
329465
+ const relative11 = path73.relative(allowedDir, targetPath);
329466
+ return relative11 === "" || !relative11.startsWith("..") && !path73.isAbsolute(relative11);
328303
329467
  }
328304
329468
  collectPathsToCheck(args2, includedArgs, excludedArgs, prefix = "") {
328305
329469
  const paths = [];
@@ -332050,6 +333214,14 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
332050
333214
  }
332051
333215
  }
332052
333216
  function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
333217
+ const baseFetch = transportOptions.fetch ?? globalThis.fetch;
333218
+ const httpOptions = {
333219
+ ...transportOptions,
333220
+ fetch: async (url3, init2) => {
333221
+ const res = await baseFetch(url3, init2);
333222
+ return init2?.method === "GET" && res.status === 404 ? new Response(null, { status: 405, statusText: "Method Not Allowed" }) : res;
333223
+ }
333224
+ };
332053
333225
  if (mcpServerConfig.httpUrl) {
332054
333226
  if (mcpServerConfig.url) {
332055
333227
  debugLogger.warn(
@@ -332058,14 +333230,14 @@ function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
332058
333230
  }
332059
333231
  return new StreamableHTTPClientTransport(
332060
333232
  new URL(mcpServerConfig.httpUrl),
332061
- transportOptions
333233
+ httpOptions
332062
333234
  );
332063
333235
  }
332064
333236
  if (mcpServerConfig.url && mcpServerConfig.type) {
332065
333237
  if (mcpServerConfig.type === "http") {
332066
333238
  return new StreamableHTTPClientTransport(
332067
333239
  new URL(mcpServerConfig.url),
332068
- transportOptions
333240
+ httpOptions
332069
333241
  );
332070
333242
  } else if (mcpServerConfig.type === "sse") {
332071
333243
  return new SSEClientTransport(
@@ -332077,7 +333249,7 @@ function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
332077
333249
  if (mcpServerConfig.url) {
332078
333250
  return new StreamableHTTPClientTransport(
332079
333251
  new URL(mcpServerConfig.url),
332080
- transportOptions
333252
+ httpOptions
332081
333253
  );
332082
333254
  }
332083
333255
  throw new Error(`No URL configured for MCP server '${mcpServerName}'`);
@@ -341137,7 +342309,19 @@ var Config = class {
341137
342309
  this.workspaceContext.addDirectory(dir);
341138
342310
  }
341139
342311
  if (this.planEnabled) {
341140
- const plansDir = this.storage.getPlansDir();
342312
+ let plansDir;
342313
+ try {
342314
+ plansDir = this.storage.getPlansDir();
342315
+ } catch (error40) {
342316
+ const errorMessage = error40 instanceof Error ? error40.message : String(error40);
342317
+ coreEvents.emitFeedback(
342318
+ "warning",
342319
+ "Invalid custom plans directory: " + errorMessage + ". Falling back to default project temp directory.",
342320
+ error40
342321
+ );
342322
+ this.storage.setCustomPlansDir(void 0);
342323
+ plansDir = this.storage.getPlansDir();
342324
+ }
341141
342325
  try {
341142
342326
  await fs68.promises.access(plansDir);
341143
342327
  this.workspaceContext.addDirectory(plansDir);
@@ -341891,7 +343075,7 @@ var Config = class {
341891
343075
  if (this.experimentalJitContext && this.memoryContextManager) {
341892
343076
  await this.memoryContextManager.refresh();
341893
343077
  } else {
341894
- const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-FB7MMKTA.js");
343078
+ const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-SJ7P6RCN.js");
341895
343079
  await refreshServerHierarchicalMemory2(this);
341896
343080
  }
341897
343081
  if (this._geminiClient?.isInitialized()) {
@@ -341926,12 +343110,13 @@ var Config = class {
341926
343110
  * user message when JIT is enabled. Returns empty string when JIT is
341927
343111
  * disabled (Tier 2 memory is already in the system instruction).
341928
343112
  */
341929
- getSessionMemory() {
343113
+ getSessionMemory(options) {
341930
343114
  if (!this.experimentalJitContext || !this.memoryContextManager) {
341931
343115
  return "";
341932
343116
  }
341933
343117
  const sections = [];
341934
- const extension = this.memoryContextManager.getExtensionMemory();
343118
+ const includeExtensionContext = options?.includeExtensionContext ?? true;
343119
+ const extension = includeExtensionContext ? this.memoryContextManager.getExtensionMemory() : "";
341935
343120
  const project = this.memoryContextManager.getEnvironmentMemory();
341936
343121
  if (extension?.trim()) {
341937
343122
  sections.push(
@@ -342360,20 +343545,36 @@ ${sections.join("\n")}
342360
343545
  setIdeMode(value) {
342361
343546
  this.ideMode = value;
342362
343547
  }
342363
- isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot) {
343548
+ isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot, checkType = "write") {
342364
343549
  if (!hasScopedMemoryInboxAccess()) {
342365
343550
  return false;
342366
343551
  }
342367
343552
  const normalizedPath = path76.resolve(absolutePath);
343553
+ const resolvedMemoryRoot = resolveToRealPath(
343554
+ this.storage.getProjectMemoryTempDir()
343555
+ );
343556
+ if (checkType === "read") {
343557
+ const resolvedInboxRoot = resolveToRealPath(inboxRoot);
343558
+ const normalizedInboxRoot = path76.resolve(inboxRoot);
343559
+ if (resolvedPath === resolvedInboxRoot || normalizedPath === normalizedInboxRoot) {
343560
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
343561
+ }
343562
+ for (const kind of ["private", "global"]) {
343563
+ const kindRoot = path76.join(inboxRoot, kind);
343564
+ const resolvedKindRoot = resolveToRealPath(kindRoot);
343565
+ const normalizedKindRoot = path76.resolve(kindRoot);
343566
+ if (resolvedPath === resolvedKindRoot || normalizedPath === normalizedKindRoot || isSubpath(resolvedKindRoot, resolvedPath) || isSubpath(normalizedKindRoot, normalizedPath)) {
343567
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
343568
+ }
343569
+ }
343570
+ return false;
343571
+ }
342368
343572
  const isCanonicalPatchPath = ["private", "global"].some(
342369
343573
  (kind) => normalizedPath === path76.resolve(inboxRoot, kind, "extraction.patch")
342370
343574
  );
342371
343575
  if (!isCanonicalPatchPath) {
342372
343576
  return false;
342373
343577
  }
342374
- const resolvedMemoryRoot = resolveToRealPath(
342375
- this.storage.getProjectMemoryTempDir()
342376
- );
342377
343578
  return isSubpath(resolvedMemoryRoot, resolvedPath);
342378
343579
  }
342379
343580
  isScopedAutoMemoryExtractionWritePathAllowed(absolutePath, resolvedPath) {
@@ -342409,7 +343610,9 @@ ${sections.join("\n")}
342409
343610
  * the auto-memory extraction agent and the `/memory inbox` review flow. The
342410
343611
  * main agent is denied access to it even though it falls inside the project
342411
343612
  * temp dir; the extraction agent receives a narrow execution-scoped exception
342412
- * for `.inbox/{private,global}/extraction.patch`.
343613
+ * for *writes* to `.inbox/{private,global}/extraction.patch`. Scoped *read*
343614
+ * access to the wider `.inbox/{private,global}/` subtree is granted in
343615
+ * `validatePathAccess` so the extractor can enumerate prior patches.
342413
343616
  *
342414
343617
  * @param absolutePath The absolute path to check.
342415
343618
  * @returns true if the path is allowed, false otherwise.
@@ -342474,6 +343677,20 @@ ${sections.join("\n")}
342474
343677
  if (this.getWorkspaceContext().isPathReadable(absolutePath)) {
342475
343678
  return null;
342476
343679
  }
343680
+ if (hasScopedMemoryInboxAccess()) {
343681
+ const inboxRoot = path76.join(
343682
+ this.storage.getProjectMemoryTempDir(),
343683
+ ".inbox"
343684
+ );
343685
+ if (this.isScopedMemoryInboxPatchPathAllowed(
343686
+ absolutePath,
343687
+ resolveToRealPath(absolutePath),
343688
+ inboxRoot,
343689
+ "read"
343690
+ )) {
343691
+ return null;
343692
+ }
343693
+ }
342477
343694
  }
342478
343695
  if (this.isPathAllowed(absolutePath)) {
342479
343696
  return null;
@@ -342808,10 +344025,10 @@ ${sections.join("\n")}
342808
344025
  return this.gemmaModelRouter;
342809
344026
  }
342810
344027
  getAgentSessionNoninteractiveEnabled() {
342811
- return this.agentSessionNoninteractiveEnabled;
344028
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionNoninteractiveEnabled;
342812
344029
  }
342813
344030
  getAgentSessionInteractiveEnabled() {
342814
- return this.agentSessionInteractiveEnabled;
344031
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionInteractiveEnabled;
342815
344032
  }
342816
344033
  /**
342817
344034
  * Get override settings for a specific agent.
@@ -343931,11 +345148,271 @@ async function isProjectSkillPatchTarget(targetPath, config2) {
343931
345148
  function hasParsedPatchHunks(parsedPatches) {
343932
345149
  return parsedPatches.length > 0 && parsedPatches.every((patch) => patch.hunks.length > 0);
343933
345150
  }
345151
+ function getMemoryPatchRoot(memoryDir, kind) {
345152
+ return path80.join(memoryDir, ".inbox", kind);
345153
+ }
345154
+ function isSubpathOrSame(childPath, parentPath) {
345155
+ return isSubpath(parentPath, childPath);
345156
+ }
345157
+ function normalizeInboxMemoryPatchPath(relativePath) {
345158
+ if (relativePath.length === 0 || path80.isAbsolute(relativePath) || relativePath.includes("\\")) {
345159
+ return void 0;
345160
+ }
345161
+ const normalizedPath = path80.posix.normalize(relativePath);
345162
+ if (normalizedPath === "." || normalizedPath.startsWith("../") || normalizedPath === ".." || !normalizedPath.endsWith(".patch")) {
345163
+ return void 0;
345164
+ }
345165
+ return normalizedPath;
345166
+ }
345167
+ function getAllowedMemoryPatchRoots(config2, kind) {
345168
+ switch (kind) {
345169
+ case "private":
345170
+ return [path80.resolve(config2.storage.getProjectMemoryTempDir())];
345171
+ case "global":
345172
+ return [path80.resolve(getGlobalMemoryFilePath())];
345173
+ default:
345174
+ throw new Error(`Unknown memory patch kind: ${kind}`);
345175
+ }
345176
+ }
345177
+ function hasMarkdownExtension(fileName) {
345178
+ return fileName.toLowerCase().endsWith(".md");
345179
+ }
345180
+ function isAllowedPrivateMemoryFileName(fileName) {
345181
+ if (fileName === PROJECT_MEMORY_INDEX_FILENAME) {
345182
+ return true;
345183
+ }
345184
+ return !fileName.startsWith(".") && hasMarkdownExtension(fileName);
345185
+ }
345186
+ function uniqueResolvedPaths(paths) {
345187
+ return Array.from(new Set(paths.map((filePath) => path80.resolve(filePath))));
345188
+ }
345189
+ function isSamePath(leftPath, rightPath) {
345190
+ return isSubpath(leftPath, rightPath) && isSubpath(rightPath, leftPath);
345191
+ }
345192
+ function includesSamePath(paths, targetPath) {
345193
+ return paths.some((candidate) => isSamePath(candidate, targetPath));
345194
+ }
345195
+ function isAllowedPrivateMemoryDocumentPath(targetPath, memoryDirs) {
345196
+ const resolvedTargetPath = path80.resolve(targetPath);
345197
+ const targetDir = path80.dirname(resolvedTargetPath);
345198
+ if (!includesSamePath(memoryDirs, targetDir)) {
345199
+ return false;
345200
+ }
345201
+ return isAllowedPrivateMemoryFileName(path80.basename(resolvedTargetPath));
345202
+ }
345203
+ function isAllowedGlobalMemoryDocumentPath(targetPath, globalMemoryFiles) {
345204
+ const resolvedTargetPath = path80.resolve(targetPath);
345205
+ return includesSamePath(globalMemoryFiles, resolvedTargetPath);
345206
+ }
345207
+ async function getMemoryPatchTargetValidationContext(config2, kind) {
345208
+ const allowedRoots = await canonicalizeAllowedPatchRoots(
345209
+ getAllowedMemoryPatchRoots(config2, kind)
345210
+ );
345211
+ if (kind === "global") {
345212
+ const rawGlobalMemoryFile = path80.resolve(getGlobalMemoryFilePath());
345213
+ const canonicalGlobalMemoryFiles = await canonicalizeAllowedPatchRoots([
345214
+ rawGlobalMemoryFile
345215
+ ]);
345216
+ return {
345217
+ kind,
345218
+ allowedRoots,
345219
+ privateMemoryDirs: [],
345220
+ globalMemoryFiles: uniqueResolvedPaths([
345221
+ rawGlobalMemoryFile,
345222
+ ...canonicalGlobalMemoryFiles
345223
+ ])
345224
+ };
345225
+ }
345226
+ const rawPrivateMemoryDir = path80.resolve(
345227
+ config2.storage.getProjectMemoryTempDir()
345228
+ );
345229
+ const canonicalPrivateMemoryDirs = await canonicalizeAllowedPatchRoots([
345230
+ rawPrivateMemoryDir
345231
+ ]);
345232
+ const privateMemoryDirs = uniqueResolvedPaths([
345233
+ rawPrivateMemoryDir,
345234
+ ...canonicalPrivateMemoryDirs
345235
+ ]);
345236
+ return { kind, allowedRoots, privateMemoryDirs, globalMemoryFiles: [] };
345237
+ }
345238
+ function isResolvedMemoryPatchTargetAllowed(resolvedTargetPath, context2) {
345239
+ if (context2.kind === "global") {
345240
+ return isAllowedGlobalMemoryDocumentPath(
345241
+ resolvedTargetPath,
345242
+ context2.globalMemoryFiles
345243
+ );
345244
+ }
345245
+ if (context2.kind === "private") {
345246
+ return isAllowedPrivateMemoryDocumentPath(
345247
+ resolvedTargetPath,
345248
+ context2.privateMemoryDirs
345249
+ );
345250
+ }
345251
+ return true;
345252
+ }
345253
+ async function resolveMemoryPatchTargetWithinAllowedSet(targetPath, context2) {
345254
+ const resolvedTargetPath = await resolveTargetWithinAllowedRoots(
345255
+ targetPath,
345256
+ context2.allowedRoots
345257
+ );
345258
+ if (!resolvedTargetPath) {
345259
+ return void 0;
345260
+ }
345261
+ if (context2.kind === "private" && (!isAllowedPrivateMemoryDocumentPath(
345262
+ targetPath,
345263
+ context2.privateMemoryDirs
345264
+ ) || !isAllowedPrivateMemoryDocumentPath(
345265
+ resolvedTargetPath,
345266
+ context2.privateMemoryDirs
345267
+ ))) {
345268
+ return void 0;
345269
+ }
345270
+ if (context2.kind === "global" && (!isAllowedGlobalMemoryDocumentPath(
345271
+ targetPath,
345272
+ context2.globalMemoryFiles
345273
+ ) || !isAllowedGlobalMemoryDocumentPath(
345274
+ resolvedTargetPath,
345275
+ context2.globalMemoryFiles
345276
+ ))) {
345277
+ return void 0;
345278
+ }
345279
+ return resolvedTargetPath;
345280
+ }
345281
+ async function findDisallowedMemoryPatchTarget(parsedPatches, context2) {
345282
+ const validated = validateParsedSkillPatchHeaders(parsedPatches);
345283
+ if (!validated.success) {
345284
+ return void 0;
345285
+ }
345286
+ for (const header of validated.patches) {
345287
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(
345288
+ header.targetPath,
345289
+ context2
345290
+ )) {
345291
+ return header.targetPath;
345292
+ }
345293
+ }
345294
+ return void 0;
345295
+ }
345296
+ async function getInboxMemoryPatchSourcePath(config2, kind, relativePath) {
345297
+ const normalizedPath = normalizeInboxMemoryPatchPath(relativePath);
345298
+ if (!normalizedPath) {
345299
+ return void 0;
345300
+ }
345301
+ const patchRoot = path80.resolve(
345302
+ getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind)
345303
+ );
345304
+ const sourcePath = path80.resolve(patchRoot, ...normalizedPath.split("/"));
345305
+ if (!isSubpathOrSame(sourcePath, patchRoot)) {
345306
+ return void 0;
345307
+ }
345308
+ return sourcePath;
345309
+ }
345310
+ async function listInboxPatchFiles(config2, kind) {
345311
+ const patchRoot = getMemoryPatchRoot(
345312
+ config2.storage.getProjectMemoryTempDir(),
345313
+ kind
345314
+ );
345315
+ const found = [];
345316
+ async function walk(currentDir) {
345317
+ let dirEntries;
345318
+ try {
345319
+ dirEntries = await fs71.readdir(currentDir, { withFileTypes: true });
345320
+ } catch {
345321
+ return;
345322
+ }
345323
+ for (const entry of dirEntries) {
345324
+ const entryPath = path80.join(currentDir, entry.name);
345325
+ if (entry.isDirectory()) {
345326
+ await walk(entryPath);
345327
+ continue;
345328
+ }
345329
+ if (entry.isFile() && entry.name.endsWith(".patch")) {
345330
+ found.push(entryPath);
345331
+ }
345332
+ }
345333
+ }
345334
+ await walk(patchRoot);
345335
+ return found.sort();
345336
+ }
345337
+ async function validateInboxMemoryPatchFile(config2, kind, sourcePath) {
345338
+ let content;
345339
+ try {
345340
+ content = await fs71.readFile(sourcePath, "utf-8");
345341
+ } catch (error40) {
345342
+ return {
345343
+ valid: false,
345344
+ reason: `failed to read patch: ${error40 instanceof Error ? error40.message : String(error40)}`
345345
+ };
345346
+ }
345347
+ let parsed;
345348
+ try {
345349
+ parsed = parsePatch(content);
345350
+ } catch (error40) {
345351
+ return {
345352
+ valid: false,
345353
+ reason: `failed to parse patch: ${error40 instanceof Error ? error40.message : String(error40)}`
345354
+ };
345355
+ }
345356
+ if (!hasParsedPatchHunks(parsed)) {
345357
+ return { valid: false, reason: "no hunks found in patch" };
345358
+ }
345359
+ const validated = validateParsedSkillPatchHeaders(parsed);
345360
+ if (!validated.success) {
345361
+ switch (validated.reason) {
345362
+ case "missingTargetPath":
345363
+ return {
345364
+ valid: false,
345365
+ reason: "missing target file path in patch header"
345366
+ };
345367
+ case "invalidPatchHeaders":
345368
+ return {
345369
+ valid: false,
345370
+ reason: `invalid diff headers${validated.targetPath ? `: ${validated.targetPath}` : ""}`
345371
+ };
345372
+ default:
345373
+ return { valid: false, reason: "invalid patch headers" };
345374
+ }
345375
+ }
345376
+ const validationContext = await getMemoryPatchTargetValidationContext(
345377
+ config2,
345378
+ kind
345379
+ );
345380
+ for (const header of validated.patches) {
345381
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(
345382
+ header.targetPath,
345383
+ validationContext
345384
+ )) {
345385
+ return {
345386
+ valid: false,
345387
+ reason: `target file is outside ${kind} memory roots: ${header.targetPath}`
345388
+ };
345389
+ }
345390
+ }
345391
+ return { valid: true };
345392
+ }
345393
+ async function listValidInboxPatchFiles(config2, kind) {
345394
+ const patchFiles = await listInboxPatchFiles(config2, kind);
345395
+ if (patchFiles.length === 0) {
345396
+ return [];
345397
+ }
345398
+ const valid = [];
345399
+ for (const sourcePath of patchFiles) {
345400
+ const validation = await validateInboxMemoryPatchFile(
345401
+ config2,
345402
+ kind,
345403
+ sourcePath
345404
+ );
345405
+ if (validation.valid) {
345406
+ valid.push(sourcePath);
345407
+ }
345408
+ }
345409
+ return valid;
345410
+ }
343934
345411
  async function applyParsedSkillPatches(parsedPatches, config2) {
343935
345412
  const allowedRoots = await getCanonicalAllowedSkillPatchRoots(config2);
343936
345413
  return applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots);
343937
345414
  }
343938
- async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
345415
+ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots, options = {}) {
343939
345416
  const results = /* @__PURE__ */ new Map();
343940
345417
  const patchedContentByTarget = /* @__PURE__ */ new Map();
343941
345418
  const originalContentByTarget = /* @__PURE__ */ new Map();
@@ -343949,7 +345426,7 @@ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
343949
345426
  targetPath,
343950
345427
  allowedRoots
343951
345428
  );
343952
- if (!resolvedTargetPath) {
345429
+ if (!resolvedTargetPath || options.isResolvedTargetAllowed && !options.isResolvedTargetAllowed(resolvedTargetPath)) {
343953
345430
  return {
343954
345431
  success: false,
343955
345432
  reason: "outsideAllowedRoots",
@@ -344411,6 +345888,7 @@ var SkillExtractionAgent = (skillsDir, sessionIndex, existingSkillsSummary, memo
344411
345888
  },
344412
345889
  memoryInboxAccess: true,
344413
345890
  autoMemoryExtractionWriteAccess: true,
345891
+ includeExtensionContext: false,
344414
345892
  toolConfig: {
344415
345893
  tools: [
344416
345894
  ACTIVATE_SKILL_TOOL_NAME,
@@ -345169,6 +346647,36 @@ async function snapshotFiles(rootDir, shouldIncludeFile = () => true, shouldDesc
345169
346647
  async function snapshotInboxCandidates(memoryDir) {
345170
346648
  return snapshotFiles(path81.join(memoryDir, ".inbox"));
345171
346649
  }
346650
+ var MEMORY_INBOX_PATCH_KINDS = [
346651
+ "private",
346652
+ "global"
346653
+ ];
346654
+ async function validateMemoryInboxPatches(config2) {
346655
+ for (const kind of MEMORY_INBOX_PATCH_KINDS) {
346656
+ const patchFiles = await listInboxPatchFiles(config2, kind);
346657
+ for (const patchFile of patchFiles) {
346658
+ const validation = await validateInboxMemoryPatchFile(
346659
+ config2,
346660
+ kind,
346661
+ patchFile
346662
+ );
346663
+ if (validation.valid) {
346664
+ continue;
346665
+ }
346666
+ try {
346667
+ await fs72.unlink(patchFile);
346668
+ debugLogger.warn(
346669
+ `[MemoryService] Dropped invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}`
346670
+ );
346671
+ } catch (error40) {
346672
+ const message = error40 instanceof Error ? error40.message : String(error40);
346673
+ debugLogger.warn(
346674
+ `[MemoryService] Failed to drop invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}; unlink failed: ${message}`
346675
+ );
346676
+ }
346677
+ }
346678
+ }
346679
+ }
345172
346680
  async function buildPendingInboxSummary(memoryDir) {
345173
346681
  const sections = [];
345174
346682
  for (const kind of ["private", "global"]) {
@@ -345418,6 +346926,7 @@ ${pendingInboxSummary}`
345418
346926
  `[MemoryService] ${validPatches.length} valid patch(es) currently in inbox; ${patchesCreatedThisRun.length} created or updated this run`
345419
346927
  );
345420
346928
  }
346929
+ await validateMemoryInboxPatches(config2);
345421
346930
  const memoryFilesUpdated = [];
345422
346931
  const memoryCandidatesCreated = prefixRelativePaths(
345423
346932
  ".inbox",
@@ -345742,33 +347251,6 @@ function formatParsedDiff(parsed) {
345742
347251
  function getErrorMessage4(error40) {
345743
347252
  return error40 instanceof Error ? error40.message : String(error40);
345744
347253
  }
345745
- function getMemoryPatchRoot(memoryDir, kind) {
345746
- return path82.join(memoryDir, ".inbox", kind);
345747
- }
345748
- function isSubpathOrSame(childPath, parentPath) {
345749
- const relativePath = path82.relative(parentPath, childPath);
345750
- return relativePath === "" || !relativePath.startsWith("..") && !path82.isAbsolute(relativePath);
345751
- }
345752
- function normalizeInboxMemoryPatchPath(relativePath) {
345753
- if (relativePath.length === 0 || path82.isAbsolute(relativePath) || relativePath.includes("\\")) {
345754
- return void 0;
345755
- }
345756
- const normalizedPath = path82.posix.normalize(relativePath);
345757
- if (normalizedPath === "." || normalizedPath.startsWith("../") || normalizedPath === ".." || !normalizedPath.endsWith(".patch")) {
345758
- return void 0;
345759
- }
345760
- return normalizedPath;
345761
- }
345762
- function getAllowedMemoryPatchRoots(config2, kind) {
345763
- switch (kind) {
345764
- case "private":
345765
- return [path82.resolve(config2.storage.getProjectMemoryTempDir())];
345766
- case "global":
345767
- return [path82.resolve(getGlobalMemoryFilePath())];
345768
- default:
345769
- throw new Error(`Unknown memory patch kind: ${kind}`);
345770
- }
345771
- }
345772
347254
  async function getFileMtimeIso(filePath) {
345773
347255
  try {
345774
347256
  const stats = await fs73.stat(filePath);
@@ -345777,20 +347259,6 @@ async function getFileMtimeIso(filePath) {
345777
347259
  return void 0;
345778
347260
  }
345779
347261
  }
345780
- async function getInboxMemoryPatchSourcePath(config2, kind, relativePath) {
345781
- const normalizedPath = normalizeInboxMemoryPatchPath(relativePath);
345782
- if (!normalizedPath) {
345783
- return void 0;
345784
- }
345785
- const patchRoot = path82.resolve(
345786
- getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind)
345787
- );
345788
- const sourcePath = path82.resolve(patchRoot, ...normalizedPath.split("/"));
345789
- if (!isSubpathOrSame(sourcePath, patchRoot)) {
345790
- return void 0;
345791
- }
345792
- return sourcePath;
345793
- }
345794
347262
  async function patchTargetsProjectSkills(targetPaths, config2) {
345795
347263
  for (const targetPath of targetPaths) {
345796
347264
  if (await isProjectSkillPatchTarget(targetPath, config2)) {
@@ -345817,83 +347285,13 @@ function formatMemoryKindLabel(kind) {
345817
347285
  return kind;
345818
347286
  }
345819
347287
  }
345820
- async function listInboxPatchFiles(config2, kind) {
345821
- const patchRoot = getMemoryPatchRoot(
345822
- config2.storage.getProjectMemoryTempDir(),
345823
- kind
345824
- );
345825
- const found = [];
345826
- async function walk(currentDir) {
345827
- let dirEntries;
345828
- try {
345829
- dirEntries = await fs73.readdir(currentDir, { withFileTypes: true });
345830
- } catch {
345831
- return;
345832
- }
345833
- for (const entry of dirEntries) {
345834
- const entryPath = path82.join(currentDir, entry.name);
345835
- if (entry.isDirectory()) {
345836
- await walk(entryPath);
345837
- continue;
345838
- }
345839
- if (entry.isFile() && entry.name.endsWith(".patch")) {
345840
- found.push(entryPath);
345841
- }
345842
- }
345843
- }
345844
- await walk(patchRoot);
345845
- return found.sort();
345846
- }
345847
- async function listValidInboxPatchFiles(config2, kind) {
345848
- const patchFiles = await listInboxPatchFiles(config2, kind);
345849
- if (patchFiles.length === 0) {
345850
- return [];
345851
- }
345852
- const allowedRoots = await canonicalizeAllowedPatchRoots(
345853
- getAllowedMemoryPatchRoots(config2, kind)
345854
- );
345855
- const valid = [];
345856
- for (const sourcePath of patchFiles) {
345857
- let content;
345858
- try {
345859
- content = await fs73.readFile(sourcePath, "utf-8");
345860
- } catch {
345861
- continue;
345862
- }
345863
- let parsed;
345864
- try {
345865
- parsed = parsePatch(content);
345866
- } catch {
345867
- continue;
345868
- }
345869
- if (!hasParsedPatchHunks(parsed)) {
345870
- continue;
345871
- }
345872
- const validated = validateParsedSkillPatchHeaders(parsed);
345873
- if (!validated.success) {
345874
- continue;
345875
- }
345876
- const targetsAllAllowed = await Promise.all(
345877
- validated.patches.map(
345878
- async (header) => await resolveTargetWithinAllowedRoots(
345879
- header.targetPath,
345880
- allowedRoots
345881
- ) !== void 0
345882
- )
345883
- );
345884
- if (!targetsAllAllowed.every(Boolean)) {
345885
- continue;
345886
- }
345887
- valid.push(sourcePath);
345888
- }
345889
- return valid;
345890
- }
345891
347288
  async function listInboxMemoryPatches(config2) {
345892
347289
  const kinds = ["private", "global"];
345893
347290
  const aggregated = [];
345894
347291
  for (const kind of kinds) {
345895
- const allowedRoots = await canonicalizeAllowedPatchRoots(
345896
- getAllowedMemoryPatchRoots(config2, kind)
347292
+ const validationContext = await getMemoryPatchTargetValidationContext(
347293
+ config2,
347294
+ kind
345897
347295
  );
345898
347296
  const patchFiles = await listInboxPatchFiles(config2, kind);
345899
347297
  const aggregatedEntries = [];
@@ -345921,9 +347319,9 @@ async function listInboxMemoryPatches(config2) {
345921
347319
  }
345922
347320
  const targetsAllAllowed = await Promise.all(
345923
347321
  validated.patches.map(
345924
- async (header) => await resolveTargetWithinAllowedRoots(
347322
+ async (header) => await resolveMemoryPatchTargetWithinAllowedSet(
345925
347323
  header.targetPath,
345926
- allowedRoots
347324
+ validationContext
345927
347325
  ) !== void 0
345928
347326
  )
345929
347327
  );
@@ -346119,12 +347517,29 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
346119
347517
  message: `Memory patch "${displayName}" contains no valid hunks.`
346120
347518
  };
346121
347519
  }
346122
- const allowedRoots = await canonicalizeAllowedPatchRoots(
346123
- getAllowedMemoryPatchRoots(config2, kind)
347520
+ const validationContext = await getMemoryPatchTargetValidationContext(
347521
+ config2,
347522
+ kind
347523
+ );
347524
+ const disallowedTargetPath = await findDisallowedMemoryPatchTarget(
347525
+ parsed,
347526
+ validationContext
346124
347527
  );
347528
+ if (disallowedTargetPath) {
347529
+ return {
347530
+ success: false,
347531
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${disallowedTargetPath}`
347532
+ };
347533
+ }
346125
347534
  const applied = await applyParsedPatchesWithAllowedRoots(
346126
347535
  parsed,
346127
- allowedRoots
347536
+ validationContext.allowedRoots,
347537
+ {
347538
+ isResolvedTargetAllowed: (resolvedTargetPath) => isResolvedMemoryPatchTargetAllowed(
347539
+ resolvedTargetPath,
347540
+ validationContext
347541
+ )
347542
+ }
346128
347543
  );
346129
347544
  if (!applied.success) {
346130
347545
  switch (applied.reason) {
@@ -346141,7 +347556,7 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
346141
347556
  case "outsideAllowedRoots":
346142
347557
  return {
346143
347558
  success: false,
346144
- message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root: ${applied.targetPath}`
347559
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${applied.targetPath}`
346145
347560
  };
346146
347561
  case "newFileAlreadyExists":
346147
347562
  return {
@@ -347091,8 +348506,9 @@ function loadIgnoreRules(service, ignoreDirs = []) {
347091
348506
  const ignorer = new Ignore2();
347092
348507
  const ignoreFiles = service.getAllIgnoreFilePaths();
347093
348508
  for (const filePath of ignoreFiles) {
347094
- if (fs75.existsSync(filePath)) {
348509
+ try {
347095
348510
  ignorer.add(fs75.readFileSync(filePath, "utf8"));
348511
+ } catch {
347096
348512
  }
347097
348513
  }
347098
348514
  const allIgnoreDirs = [".git", ...ignoreDirs];
@@ -348261,11 +349677,11 @@ var AsyncFzf = class {
348261
349677
  // packages/core/node_modules/chokidar/index.js
348262
349678
  import { EventEmitter as EventEmitter8 } from "node:events";
348263
349679
  import { stat as statcb, Stats } from "node:fs";
348264
- import { readdir as readdir10, stat as stat7 } from "node:fs/promises";
349680
+ import { readdir as readdir11, stat as stat7 } from "node:fs/promises";
348265
349681
  import * as sp2 from "node:path";
348266
349682
 
348267
349683
  // packages/core/node_modules/readdirp/index.js
348268
- import { lstat as lstat3, readdir as readdir9, realpath as realpath4, stat as stat5 } from "node:fs/promises";
349684
+ import { lstat as lstat3, readdir as readdir10, realpath as realpath4, stat as stat5 } from "node:fs/promises";
348269
349685
  import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "node:path";
348270
349686
  import { Readable as Readable3 } from "node:stream";
348271
349687
  var EntryTypes = {
@@ -348417,7 +349833,7 @@ var ReaddirpStream = class extends Readable3 {
348417
349833
  async _exploreDir(path101, depth) {
348418
349834
  let files;
348419
349835
  try {
348420
- files = await readdir9(path101, this._rdOptions);
349836
+ files = await readdir10(path101, this._rdOptions);
348421
349837
  } catch (error40) {
348422
349838
  this._onError(error40);
348423
349839
  }
@@ -349282,11 +350698,11 @@ function createPattern(matcher) {
349282
350698
  if (matcher.path === string4)
349283
350699
  return true;
349284
350700
  if (matcher.recursive) {
349285
- const relative12 = sp2.relative(matcher.path, string4);
349286
- if (!relative12) {
350701
+ const relative11 = sp2.relative(matcher.path, string4);
350702
+ if (!relative11) {
349287
350703
  return false;
349288
350704
  }
349289
- return !relative12.startsWith("..") && !sp2.isAbsolute(relative12);
350705
+ return !relative11.startsWith("..") && !sp2.isAbsolute(relative11);
349290
350706
  }
349291
350707
  return false;
349292
350708
  };
@@ -349388,7 +350804,7 @@ var DirEntry = class {
349388
350804
  return;
349389
350805
  const dir = this.path;
349390
350806
  try {
349391
- await readdir10(dir);
350807
+ await readdir11(dir);
349392
350808
  } catch (err2) {
349393
350809
  if (this._removeWatcher) {
349394
350810
  this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
@@ -350855,8 +352271,8 @@ function normalizePathCandidate(candidate, projectRoot) {
350855
352271
  }
350856
352272
  let normalized2 = trimmed2.replace(/\\/g, "/");
350857
352273
  if (path88.isAbsolute(trimmed2)) {
350858
- const relative12 = path88.relative(projectRoot, trimmed2);
350859
- normalized2 = relative12 && !relative12.startsWith("..") && !path88.isAbsolute(relative12) ? relative12.replace(/\\/g, "/") : path88.basename(trimmed2);
352274
+ const relative11 = path88.relative(projectRoot, trimmed2);
352275
+ normalized2 = relative11 && !relative11.startsWith("..") && !path88.isAbsolute(relative11) ? relative11.replace(/\\/g, "/") : path88.basename(trimmed2);
350860
352276
  }
350861
352277
  if (normalized2.length > 120) {
350862
352278
  normalized2 = normalized2.split("/").slice(-3).join("/");
@@ -351661,6 +353077,9 @@ function contentPartsToGeminiParts(content) {
351661
353077
  result2.push({ text: part.text });
351662
353078
  break;
351663
353079
  default:
353080
+ debugLogger.warn(
353081
+ `Unhandled ContentPart type: ${JSON.stringify(part)} fallback to serialization`
353082
+ );
351664
353083
  result2.push({ text: JSON.stringify(part) });
351665
353084
  break;
351666
353085
  }
@@ -351677,62 +353096,6 @@ function buildToolResponseData(response) {
351677
353096
  return Object.keys(parts2).length > 0 ? parts2 : void 0;
351678
353097
  }
351679
353098
 
351680
- // packages/core/src/agent/tool-display-utils.ts
351681
- function populateToolDisplay({
351682
- name: name3,
351683
- invocation,
351684
- resultDisplay,
351685
- displayName
351686
- }) {
351687
- const display = {
351688
- name: displayName || name3,
351689
- description: invocation?.getDescription?.()
351690
- };
351691
- if (resultDisplay) {
351692
- display.result = toolResultDisplayToDisplayContent(resultDisplay);
351693
- }
351694
- return display;
351695
- }
351696
- function toolResultDisplayToDisplayContent(resultDisplay) {
351697
- if (typeof resultDisplay === "string") {
351698
- return { type: "text", text: resultDisplay };
351699
- }
351700
- if (typeof resultDisplay === "object" && resultDisplay !== null && "fileDiff" in resultDisplay && "newContent" in resultDisplay) {
351701
- return {
351702
- type: "diff",
351703
- path: resultDisplay.filePath || resultDisplay.fileName,
351704
- beforeText: resultDisplay.originalContent ?? "",
351705
- afterText: resultDisplay.newContent
351706
- };
351707
- }
351708
- return {
351709
- type: "text",
351710
- text: JSON.stringify(resultDisplay)
351711
- };
351712
- }
351713
- function renderDisplayDiff(diff) {
351714
- return createPatch(
351715
- diff.path || "file",
351716
- diff.beforeText,
351717
- diff.afterText,
351718
- "Original",
351719
- "Modified",
351720
- { context: 3 }
351721
- );
351722
- }
351723
- function displayContentToString(display) {
351724
- if (!display) {
351725
- return void 0;
351726
- }
351727
- if (display.type === "text") {
351728
- return display.text;
351729
- }
351730
- if (display.type === "diff") {
351731
- return renderDisplayDiff(display);
351732
- }
351733
- return JSON.stringify(display);
351734
- }
351735
-
351736
353099
  // packages/core/src/agent/event-translator.ts
351737
353100
  function createTranslationState(streamId) {
351738
353101
  return {
@@ -351881,18 +353244,19 @@ function translateEvent(event, state) {
351881
353244
  makeEvent("tool_request", state, {
351882
353245
  requestId: event.value.callId,
351883
353246
  name: event.value.name,
351884
- args: event.value.args
353247
+ args: event.value.args,
353248
+ display: event.value.display
351885
353249
  })
351886
353250
  );
351887
353251
  break;
351888
353252
  case "tool_call_response" /* ToolCallResponse */: {
351889
353253
  ensureStreamStart(state, out2);
351890
353254
  const data = buildToolResponseData(event.value);
351891
- const display = event.value.resultDisplay ? {
353255
+ const display = event.value.display ?? (event.value.resultDisplay ? {
351892
353256
  result: toolResultDisplayToDisplayContent(
351893
353257
  event.value.resultDisplay
351894
353258
  )
351895
- } : void 0;
353259
+ } : void 0);
351896
353260
  out2.push(
351897
353261
  makeEvent("tool_response", state, {
351898
353262
  requestId: event.value.callId,
@@ -351916,7 +353280,6 @@ function translateEvent(event, state) {
351916
353280
  ((x) => {
351917
353281
  throw new Error(`Unhandled event type: ${JSON.stringify(x)}`);
351918
353282
  })(event);
351919
- break;
351920
353283
  }
351921
353284
  return out2;
351922
353285
  }
@@ -352122,6 +353485,7 @@ var LegacyAgentProtocol = class {
352122
353485
  } else {
352123
353486
  this._emitErrorAndAgentEnd(err2);
352124
353487
  }
353488
+ } finally {
352125
353489
  this._clearActiveStream();
352126
353490
  }
352127
353491
  }
@@ -352204,7 +353568,8 @@ var LegacyAgentProtocol = class {
352204
353568
  name: request.name,
352205
353569
  invocation: "invocation" in tc ? tc.invocation : void 0,
352206
353570
  resultDisplay: response.resultDisplay,
352207
- displayName: "tool" in tc ? tc.tool?.displayName : void 0
353571
+ displayName: "tool" in tc ? tc.tool?.displayName : void 0,
353572
+ display: response.display
352208
353573
  });
352209
353574
  const data = buildToolResponseData(response);
352210
353575
  this._emit([
@@ -352304,6 +353669,7 @@ var LegacyAgentProtocol = class {
352304
353669
  const meta = {};
352305
353670
  if (err2 instanceof Error) {
352306
353671
  meta["errorName"] = err2.constructor.name;
353672
+ meta["stack"] = err2.stack;
352307
353673
  if ("exitCode" in err2 && typeof err2.exitCode === "number") {
352308
353674
  meta["exitCode"] = err2.exitCode;
352309
353675
  }
@@ -355040,7 +356406,7 @@ var ENCODING_ALIASES = {
355040
356406
  var serializeEncoding = (encoding) => typeof encoding === "string" ? `"${encoding}"` : String(encoding);
355041
356407
 
355042
356408
  // node_modules/execa/lib/arguments/cwd.js
355043
- import { statSync as statSync3 } from "node:fs";
356409
+ import { statSync as statSync4 } from "node:fs";
355044
356410
  import path94 from "node:path";
355045
356411
  import process20 from "node:process";
355046
356412
  var normalizeCwd = (cwd = getDefaultCwd()) => {
@@ -355062,7 +356428,7 @@ var fixCwdError = (originalMessage, cwd) => {
355062
356428
  }
355063
356429
  let cwdStat;
355064
356430
  try {
355065
- cwdStat = statSync3(cwd);
356431
+ cwdStat = statSync4(cwd);
355066
356432
  } catch (error40) {
355067
356433
  return `The "cwd" option is invalid: ${cwd}.
355068
356434
  ${error40.message}
@@ -359725,8 +361091,8 @@ function isGeminiWorktree(dirPath, projectRoot) {
359725
361091
  const realDirPath = realpathSync4(dirPath);
359726
361092
  const realProjectRoot = realpathSync4(projectRoot);
359727
361093
  const worktreesBaseDir = path96.join(realProjectRoot, ".gemini", "worktrees");
359728
- const relative12 = path96.relative(worktreesBaseDir, realDirPath);
359729
- return !relative12.startsWith("..") && !path96.isAbsolute(relative12);
361094
+ const relative11 = path96.relative(worktreesBaseDir, realDirPath);
361095
+ return !relative11.startsWith("..") && !path96.isAbsolute(relative11);
359730
361096
  } catch {
359731
361097
  return false;
359732
361098
  }
@@ -361122,6 +362488,7 @@ export {
361122
362488
  CacheService,
361123
362489
  createCache,
361124
362490
  ProjectIdRequiredError,
362491
+ InvalidNumericProjectIdError,
361125
362492
  ValidationCancelledError,
361126
362493
  IneligibleTierError,
361127
362494
  resetUserDataCacheForTesting,
@@ -361209,6 +362576,11 @@ export {
361209
362576
  GeminiChat,
361210
362577
  isSchemaDepthError,
361211
362578
  isInvalidArgumentError,
362579
+ stripToolCallIdPrefixes,
362580
+ populateToolDisplay,
362581
+ toolResultDisplayToDisplayContent,
362582
+ renderDisplayDiff,
362583
+ displayContentToString,
361212
362584
  GeminiEventType,
361213
362585
  CompressionStatus,
361214
362586
  Turn,
@@ -361246,6 +362618,7 @@ export {
361246
362618
  SubagentActivityErrorType,
361247
362619
  SUBAGENT_REJECTED_ERROR_PREFIX,
361248
362620
  SUBAGENT_CANCELLED_ERROR_MESSAGE,
362621
+ SubagentState,
361249
362622
  isSubagentProgress,
361250
362623
  isToolActivityError,
361251
362624
  getAgentCardLoadOptions,
@@ -361275,6 +362648,16 @@ export {
361275
362648
  getPolicyDenialError,
361276
362649
  checkPolicy,
361277
362650
  updatePolicy,
362651
+ NodeType,
362652
+ isAgentThought,
362653
+ isAgentYield,
362654
+ isToolExecution,
362655
+ isMaskedTool,
362656
+ isUserPrompt,
362657
+ isSystemEvent,
362658
+ isSnapshot,
362659
+ isRollingSummary,
362660
+ SnapshotGenerator,
361278
362661
  generalistProfile,
361279
362662
  stressTestProfile,
361280
362663
  GeminiClient,
@@ -361420,6 +362803,7 @@ export {
361420
362803
  performRestore,
361421
362804
  performInit,
361422
362805
  isProjectSkillPatchTarget,
362806
+ getAllowedMemoryPatchRoots,
361423
362807
  validatePatches,
361424
362808
  startMemoryService,
361425
362809
  showMemory,
@@ -361429,7 +362813,6 @@ export {
361429
362813
  listInboxSkills,
361430
362814
  moveInboxSkill,
361431
362815
  dismissInboxSkill,
361432
- getAllowedMemoryPatchRoots,
361433
362816
  listInboxMemoryPatches,
361434
362817
  applyInboxMemoryPatch,
361435
362818
  dismissInboxMemoryPatch,
@@ -361465,10 +362848,6 @@ export {
361465
362848
  geminiPartsToContentParts,
361466
362849
  contentPartsToGeminiParts,
361467
362850
  buildToolResponseData,
361468
- populateToolDisplay,
361469
- toolResultDisplayToDisplayContent,
361470
- renderDisplayDiff,
361471
- displayContentToString,
361472
362851
  createTranslationState,
361473
362852
  translateEvent,
361474
362853
  mapFinishReason,