@google/gemini-cli 0.42.0 → 0.44.0-nightly.20260513.g5ee05c775

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-COQP2M4D.js → chunk-27SPXGT2.js} +562 -437
  2. package/bundle/{chunk-EDKX67D6.js → chunk-2VH3SA6M.js} +43 -23
  3. package/bundle/{chunk-PUDLNWHE.js → chunk-3KOQHVJU.js} +3 -3
  4. package/bundle/{chunk-COKAF5GM.js → chunk-4QQ5AHZP.js} +2 -2
  5. package/bundle/{chunk-KVEAHIIV.js → chunk-5EEEHNEE.js} +3 -3
  6. package/bundle/{chunk-G2VTSEZ6.js → chunk-5SMSFUPB.js} +1 -1
  7. package/bundle/{chunk-7VVHSNDQ.js → chunk-AC2EWTF7.js} +1970 -731
  8. package/bundle/{chunk-GA527JB7.js → chunk-ATSNFRDF.js} +1 -1
  9. package/bundle/{chunk-3IS7GD6D.js → chunk-BA752AEU.js} +3 -3
  10. package/bundle/{chunk-CYEIWMZJ.js → chunk-FGYOOMPI.js} +1 -1
  11. package/bundle/{chunk-QOZSZYL7.js → chunk-FK45PHSI.js} +3 -3
  12. package/bundle/{chunk-I7AME6VC.js → chunk-FTY6BJEY.js} +9 -8
  13. package/bundle/{chunk-NTOPH4WG.js → chunk-GCWBZXBS.js} +2 -2
  14. package/bundle/chunk-I2JHD4D3.js +512 -0
  15. package/bundle/{chunk-7C6GGDK6.js → chunk-IZJOLGNO.js} +3 -3
  16. package/bundle/{chunk-4SLGT6YD.js → chunk-J4YAW3P3.js} +1 -1
  17. package/bundle/chunk-KADNKBXT.js +118 -0
  18. package/bundle/{chunk-DN4XSYRG.js → chunk-LF33N5QM.js} +8696 -13355
  19. package/bundle/{chunk-CHERUG6W.js → chunk-LO22NRY4.js} +502 -390
  20. package/bundle/{chunk-JEW7ZIWE.js → chunk-M7OUJJZ2.js} +5270 -5234
  21. package/bundle/{chunk-WIXUKOZA.js → chunk-MFNKZZOB.js} +1 -1
  22. package/bundle/chunk-MLPM54XD.js +357247 -0
  23. package/bundle/{chunk-ECNYAST2.js → chunk-N22WUHJE.js} +5419 -5378
  24. package/bundle/chunk-OC7XGTLV.js +81656 -0
  25. package/bundle/{chunk-ZNMQA242.js → chunk-QDEK3TQ6.js} +3 -3
  26. package/bundle/{chunk-BCYBA52D.js → chunk-QMXQUBC4.js} +43 -23
  27. package/bundle/chunk-TBHMNRI3.js +1571 -0
  28. package/bundle/{chunk-LATVEETM.js → chunk-TOOOS4HD.js} +2 -2
  29. package/bundle/{chunk-XUMRUXOT.js → chunk-UHSQLPNG.js} +50 -27
  30. package/bundle/chunk-USS2A6NQ.js +156 -0
  31. package/bundle/chunk-WMTLLWRC.js +391 -0
  32. package/bundle/chunk-XDWZDV7C.js +17250 -0
  33. package/bundle/{chunk-DMWX7UP6.js → chunk-YBYQH75I.js} +2252 -829
  34. package/bundle/{chunk-FCAODPNO.js → chunk-ZZN56QZ3.js} +502 -390
  35. package/bundle/{cleanup-3RILFNVM.js → cleanup-2H3SANYB.js} +3 -3
  36. package/bundle/{cleanup-SVRKYBR6.js → cleanup-7GY7BVC6.js} +3 -3
  37. package/bundle/{cleanup-XFVHHDVO.js → cleanup-FERREFU6.js} +3 -3
  38. package/bundle/cleanup-VIITMMDH.js +33 -0
  39. package/bundle/{core-FRVSDP2C.js → core-GS6NXK7Y.js} +30 -2
  40. package/bundle/{devtoolsService-VM2WTHBX.js → devtoolsService-FKC6Y4OE.js} +3 -3
  41. package/bundle/{devtoolsService-TRDGMQLJ.js → devtoolsService-K2DRCZEY.js} +5 -4
  42. package/bundle/{devtoolsService-RUEO5PGP.js → devtoolsService-PS6RYICL.js} +3 -3
  43. package/bundle/devtoolsService-ZDXC2NPD.js +857 -0
  44. package/bundle/{dist-6BN2CJPN.js → dist-S3YUNQKP.js} +30 -2
  45. package/bundle/{core-B5S6HZJT.js → dist-TBGNMYU2.js} +30 -2
  46. package/bundle/dist-ZEW43MLQ.js +2124 -0
  47. package/bundle/docs/changelogs/index.md +30 -0
  48. package/bundle/docs/changelogs/latest.md +261 -166
  49. package/bundle/docs/changelogs/preview.md +178 -103
  50. package/bundle/docs/cli/auto-memory.md +60 -38
  51. package/bundle/docs/cli/settings.md +1 -1
  52. package/bundle/docs/cli/tutorials/memory-management.md +1 -1
  53. package/bundle/docs/extensions/releasing.md +58 -24
  54. package/bundle/docs/reference/configuration.md +14 -1
  55. package/bundle/docs/reference/keyboard-shortcuts.md +23 -0
  56. package/bundle/{gemini-QSTQ2DBG.js → gemini-6YGVETF3.js} +165 -61
  57. package/bundle/{gemini-GHUELHBF.js → gemini-7FCGNXOV.js} +350 -232
  58. package/bundle/gemini-IXZUGRVP.js +16360 -0
  59. package/bundle/{gemini-NQPVX5JC.js → gemini-WYTY4CD5.js} +165 -61
  60. package/bundle/gemini.js +8 -8
  61. package/bundle/{interactiveCli-AG2YWL2O.js → interactiveCli-A2FV6NYD.js} +1721 -1472
  62. package/bundle/{interactiveCli-MZFG35NB.js → interactiveCli-DWNRHVIB.js} +2003 -1736
  63. package/bundle/{interactiveCli-453M2IVE.js → interactiveCli-H7N4UXVQ.js} +1720 -1472
  64. package/bundle/interactiveCli-XRZEELCX.js +34754 -0
  65. package/bundle/{liteRtServerManager-G4Q7OVBX.js → liteRtServerManager-5C5EONBK.js} +5 -5
  66. package/bundle/{liteRtServerManager-S7WL25VD.js → liteRtServerManager-NQKPNCLR.js} +5 -5
  67. package/bundle/{liteRtServerManager-BXQ6VVWP.js → liteRtServerManager-UJBPII3P.js} +5 -5
  68. package/bundle/liteRtServerManager-UZCAJJCS.js +66 -0
  69. package/bundle/{memoryDiscovery-KSYZVCWF.js → memoryDiscovery-ALKMYAPP.js} +1 -1
  70. package/bundle/{memoryDiscovery-FB7MMKTA.js → memoryDiscovery-XFCKEF3F.js} +1 -1
  71. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  72. package/bundle/{oauth2-provider-VR4DL6AL.js → oauth2-provider-JNOY6NUI.js} +2 -2
  73. package/bundle/{oauth2-provider-H7G6RSFW.js → oauth2-provider-O6OA5EMU.js} +2 -2
  74. package/bundle/{oauth2-provider-5UF5WEE2.js → oauth2-provider-QYCLASEA.js} +39 -73
  75. package/bundle/oauth2-provider-VWLTUFO7.js +237 -0
  76. package/bundle/{start-CQBSKFYB.js → start-6FV3VPPH.js} +7 -7
  77. package/bundle/{start-NIMXQJYB.js → start-IWAUTCYF.js} +7 -7
  78. package/bundle/{start-2SKRN43X.js → start-L4DAQUQM.js} +7 -7
  79. package/bundle/start-XTXUKP77.js +19 -0
  80. package/package.json +1 -1
@@ -92,6 +92,7 @@ import {
92
92
  PREVIEW_GEMINI_MODEL,
93
93
  PREVIEW_GEMINI_MODEL_AUTO,
94
94
  PRIORITY_SUBAGENT_TOOL,
95
+ PROJECT_MEMORY_INDEX_FILENAME,
95
96
  PolicyDecision,
96
97
  QuestionType,
97
98
  READ_FILE_DEFINITION,
@@ -223,7 +224,7 @@ import {
223
224
  toPathKey,
224
225
  unescapePath,
225
226
  zodToJsonSchema
226
- } from "./chunk-JEW7ZIWE.js";
227
+ } from "./chunk-M7OUJJZ2.js";
227
228
  import {
228
229
  wrapper_default
229
230
  } from "./chunk-664ZODQF.js";
@@ -2574,7 +2575,7 @@ var require_lib = __commonJS({
2574
2575
  return numMessages > 0;
2575
2576
  }
2576
2577
  async function isBinaryFile2(file2, size) {
2577
- if (isString(file2)) {
2578
+ if (isString2(file2)) {
2578
2579
  const stat9 = await statAsync(file2);
2579
2580
  isStatFile(stat9);
2580
2581
  const fileDescriptor = await openAsync(file2, "r");
@@ -2602,7 +2603,7 @@ var require_lib = __commonJS({
2602
2603
  }
2603
2604
  exports2.isBinaryFile = isBinaryFile2;
2604
2605
  function isBinaryFileSync(file2, size) {
2605
- if (isString(file2)) {
2606
+ if (isString2(file2)) {
2606
2607
  const stat9 = fs84.statSync(file2);
2607
2608
  isStatFile(stat9);
2608
2609
  const fileDescriptor = fs84.openSync(file2, "r");
@@ -2682,7 +2683,7 @@ var require_lib = __commonJS({
2682
2683
  }
2683
2684
  return false;
2684
2685
  }
2685
- function isString(x) {
2686
+ function isString2(x) {
2686
2687
  return typeof x === "string";
2687
2688
  }
2688
2689
  function isStatFile(stat9) {
@@ -24450,7 +24451,7 @@ var require_minimal = __commonJS({
24450
24451
  function isInteger3(value) {
24451
24452
  return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
24452
24453
  };
24453
- util2.isString = function isString(value) {
24454
+ util2.isString = function isString2(value) {
24454
24455
  return typeof value === "string" || value instanceof String;
24455
24456
  };
24456
24457
  util2.isObject = function isObject6(value) {
@@ -25319,13 +25320,13 @@ var require_path = __commonJS({
25319
25320
  "node_modules/@protobufjs/path/index.js"(exports2) {
25320
25321
  "use strict";
25321
25322
  var path101 = exports2;
25322
- var isAbsolute8 = (
25323
+ var isAbsolute7 = (
25323
25324
  /**
25324
25325
  * Tests if the specified path is absolute.
25325
25326
  * @param {string} path Path to test
25326
25327
  * @returns {boolean} `true` if path is absolute
25327
25328
  */
25328
- path101.isAbsolute = function isAbsolute9(path102) {
25329
+ path101.isAbsolute = function isAbsolute8(path102) {
25329
25330
  return /^(?:\/|\w+:)/.test(path102);
25330
25331
  }
25331
25332
  );
@@ -25337,7 +25338,7 @@ var require_path = __commonJS({
25337
25338
  */
25338
25339
  path101.normalize = function normalize6(path102) {
25339
25340
  path102 = path102.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
25340
- var parts2 = path102.split("/"), absolute = isAbsolute8(path102), prefix = "";
25341
+ var parts2 = path102.split("/"), absolute = isAbsolute7(path102), prefix = "";
25341
25342
  if (absolute)
25342
25343
  prefix = parts2.shift() + "/";
25343
25344
  for (var i3 = 0; i3 < parts2.length; ) {
@@ -25359,7 +25360,7 @@ var require_path = __commonJS({
25359
25360
  path101.resolve = function resolve25(originPath, includePath, alreadyNormalized) {
25360
25361
  if (!alreadyNormalized)
25361
25362
  includePath = normalize5(includePath);
25362
- if (isAbsolute8(includePath))
25363
+ if (isAbsolute7(includePath))
25363
25364
  return includePath;
25364
25365
  if (!alreadyNormalized)
25365
25366
  originPath = normalize5(originPath);
@@ -42951,7 +42952,7 @@ var require_minimal2 = __commonJS({
42951
42952
  function isInteger3(value) {
42952
42953
  return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
42953
42954
  };
42954
- util2.isString = function isString(value) {
42955
+ util2.isString = function isString2(value) {
42955
42956
  return typeof value === "string" || value instanceof String;
42956
42957
  };
42957
42958
  util2.isObject = function isObject6(value) {
@@ -96326,7 +96327,7 @@ var require_object_inspect = __commonJS({
96326
96327
  if (isBoolean2(obj)) {
96327
96328
  return markBoxed(booleanValueOf.call(obj));
96328
96329
  }
96329
- if (isString(obj)) {
96330
+ if (isString2(obj)) {
96330
96331
  return markBoxed(inspect4(String(obj)));
96331
96332
  }
96332
96333
  if (typeof window !== "undefined" && obj === window) {
@@ -96375,7 +96376,7 @@ var require_object_inspect = __commonJS({
96375
96376
  function isError(obj) {
96376
96377
  return toStr(obj) === "[object Error]" && canTrustToString(obj);
96377
96378
  }
96378
- function isString(obj) {
96379
+ function isString2(obj) {
96379
96380
  return toStr(obj) === "[object String]" && canTrustToString(obj);
96380
96381
  }
96381
96382
  function isNumber3(obj) {
@@ -204423,8 +204424,8 @@ var require_ignore = __commonJS({
204423
204424
  (prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern)),
204424
204425
  pattern
204425
204426
  );
204426
- var isString = (subject) => typeof subject === "string";
204427
- var checkPattern = (pattern) => pattern && isString(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
204427
+ var isString2 = (subject) => typeof subject === "string";
204428
+ var checkPattern = (pattern) => pattern && isString2(pattern) && !REGEX_TEST_BLANK_LINE.test(pattern) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern) && pattern.indexOf("#") !== 0;
204428
204429
  var splitPattern = (pattern) => pattern.split(REGEX_SPLITALL_CRLF).filter(Boolean);
204429
204430
  var IgnoreRule = class {
204430
204431
  constructor(pattern, mark, body2, ignoreCase, negative, prefix) {
@@ -204491,7 +204492,7 @@ var require_ignore = __commonJS({
204491
204492
  this._added = true;
204492
204493
  return;
204493
204494
  }
204494
- if (isString(pattern)) {
204495
+ if (isString2(pattern)) {
204495
204496
  pattern = {
204496
204497
  pattern
204497
204498
  };
@@ -204506,7 +204507,7 @@ var require_ignore = __commonJS({
204506
204507
  add(pattern) {
204507
204508
  this._added = false;
204508
204509
  makeArray(
204509
- isString(pattern) ? splitPattern(pattern) : pattern
204510
+ isString2(pattern) ? splitPattern(pattern) : pattern
204510
204511
  ).forEach(this._add, this);
204511
204512
  return this._added;
204512
204513
  }
@@ -204548,7 +204549,7 @@ var require_ignore = __commonJS({
204548
204549
  throw new Ctor(message);
204549
204550
  };
204550
204551
  var checkPath = (path101, originalPath, doThrow) => {
204551
- if (!isString(path101)) {
204552
+ if (!isString2(path101)) {
204552
204553
  return doThrow(
204553
204554
  `path must be a string, but got \`${originalPath}\``,
204554
204555
  TypeError
@@ -229145,13 +229146,13 @@ var require_implementation2 = __commonJS({
229145
229146
  var isObject6 = object3 !== null && typeof object3 === "object";
229146
229147
  var isFunction = toStr.call(object3) === "[object Function]";
229147
229148
  var isArguments = isArgs(object3);
229148
- var isString = isObject6 && toStr.call(object3) === "[object String]";
229149
+ var isString2 = isObject6 && toStr.call(object3) === "[object String]";
229149
229150
  var theKeys = [];
229150
229151
  if (!isObject6 && !isFunction && !isArguments) {
229151
229152
  throw new TypeError("Object.keys called on a non-object");
229152
229153
  }
229153
229154
  var skipProto = hasProtoEnumBug && isFunction;
229154
- if (isString && object3.length > 0 && !has.call(object3, 0)) {
229155
+ if (isString2 && object3.length > 0 && !has.call(object3, 0)) {
229155
229156
  for (var i3 = 0; i3 < object3.length; ++i3) {
229156
229157
  theKeys.push(String(i3));
229157
229158
  }
@@ -236749,6 +236750,8 @@ var BINARY_FILE_PATTERNS = [
236749
236750
  "**/*.bz2",
236750
236751
  "**/*.rar",
236751
236752
  "**/*.7z",
236753
+ "**/*.pak",
236754
+ "**/*.rpa",
236752
236755
  "**/*.doc",
236753
236756
  "**/*.docx",
236754
236757
  "**/*.xls",
@@ -237759,8 +237762,14 @@ function escapeShellArg(arg, shell) {
237759
237762
  }
237760
237763
  switch (shell) {
237761
237764
  case "powershell":
237765
+ if (/^[a-zA-Z0-9\-_.]+$/.test(arg)) {
237766
+ return arg;
237767
+ }
237762
237768
  return `'${arg.replace(/'/g, "''")}'`;
237763
237769
  case "cmd":
237770
+ if (/^[a-zA-Z0-9\-_.]+$/.test(arg)) {
237771
+ return arg;
237772
+ }
237764
237773
  return `"${arg.replace(/"/g, '""')}"`;
237765
237774
  case "bash":
237766
237775
  default:
@@ -242047,7 +242056,8 @@ function recordModelRoutingMetrics(config2, event) {
242047
242056
  "routing.approval_mode": event.approval_mode
242048
242057
  };
242049
242058
  if (event.reasoning) {
242050
- attributes["routing.reasoning"] = event.reasoning;
242059
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
242060
+ attributes["routing.reasoning"] = isStrictTelemetry && event.reasoning.length > 1e3 ? event.reasoning.substring(0, 1e3) + "..." : event.reasoning;
242051
242061
  }
242052
242062
  if (event.enable_numerical_routing !== void 0) {
242053
242063
  attributes["routing.enable_numerical_routing"] = event.enable_numerical_routing;
@@ -242057,9 +242067,10 @@ function recordModelRoutingMetrics(config2, event) {
242057
242067
  }
242058
242068
  modelRoutingLatencyHistogram.record(event.routing_latency_ms, attributes);
242059
242069
  if (event.failed) {
242070
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
242060
242071
  modelRoutingFailureCounter.add(1, {
242061
242072
  ...attributes,
242062
- "routing.error_message": event.error_message
242073
+ "routing.error_message": isStrictTelemetry && event.error_message && event.error_message.length > 1e3 ? event.error_message.substring(0, 1e3) + "..." : event.error_message
242063
242074
  });
242064
242075
  }
242065
242076
  }
@@ -244879,7 +244890,7 @@ var KeychainService = class {
244879
244890
  if (await this.isKeychainFunctional(keychainModule)) {
244880
244891
  return keychainModule;
244881
244892
  }
244882
- debugLogger.debug("Keychain functional verification failed");
244893
+ debugLogger.debug("Keychain functional verification failed or timed out");
244883
244894
  return null;
244884
244895
  } catch (error40) {
244885
244896
  const message = error40 instanceof Error ? error40.message : String(error40);
@@ -244900,13 +244911,22 @@ var KeychainService = class {
244900
244911
  return null;
244901
244912
  }
244902
244913
  // Performs a set-get-delete cycle to verify keychain functionality.
244914
+ // Capped with a 2s timeout so a non-responsive Secret Service (common on
244915
+ // headless Linux: WSL/SSH/Docker without gnome-keyring or D-Bus) falls back
244916
+ // to FileKeychain instead of hanging the CLI indefinitely.
244903
244917
  async isKeychainFunctional(keychain) {
244904
244918
  const testAccount = `${KEYCHAIN_TEST_PREFIX}${crypto7.randomBytes(8).toString("hex")}`;
244905
244919
  const testPassword = "test";
244906
- await keychain.setPassword(this.serviceName, testAccount, testPassword);
244907
- const retrieved = await keychain.getPassword(this.serviceName, testAccount);
244908
- const deleted = await keychain.deletePassword(this.serviceName, testAccount);
244909
- return deleted && retrieved === testPassword;
244920
+ const probe = async () => {
244921
+ await keychain.setPassword(this.serviceName, testAccount, testPassword);
244922
+ const retrieved = await keychain.getPassword(this.serviceName, testAccount);
244923
+ const deleted = await keychain.deletePassword(this.serviceName, testAccount);
244924
+ return deleted && retrieved === testPassword;
244925
+ };
244926
+ return Promise.race([
244927
+ probe(),
244928
+ new Promise((resolve25) => setTimeout(() => resolve25(false), 2e3).unref())
244929
+ ]);
244910
244930
  }
244911
244931
  /**
244912
244932
  * MacOS-specific check to detect if a default keychain is available.
@@ -245400,7 +245420,8 @@ async function triggerPostAuthCallbacks(tokens) {
245400
245420
  refresh_token: tokens.refresh_token ?? void 0,
245401
245421
  // Ensure null is not passed
245402
245422
  type: "authorized_user",
245403
- client_email: userAccountManager2.getCachedGoogleAccount() ?? void 0
245423
+ client_email: userAccountManager2.getCachedGoogleAccount() ?? void 0,
245424
+ quota_project_id: process.env["GOOGLE_CLOUD_QUOTA_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"]
245404
245425
  };
245405
245426
  authEvents.emit("post_auth", jwtInput);
245406
245427
  }
@@ -245799,7 +245820,12 @@ async function fetchCachedCredentials() {
245799
245820
  for (const keyFile of pathsToTry) {
245800
245821
  try {
245801
245822
  const keyFileString = await fs20.readFile(keyFile, "utf-8");
245802
- return JSON.parse(keyFileString);
245823
+ const parsed = JSON.parse(keyFileString);
245824
+ const isOAuthCreds = (val) => typeof val === "object" && val !== null;
245825
+ if (isOAuthCreds(parsed)) {
245826
+ return parsed;
245827
+ }
245828
+ throw new Error("Invalid credentials format");
245803
245829
  } catch (error40) {
245804
245830
  debugLogger.debug(`Failed to load credentials from ${keyFile}:`, getErrorMessage(error40));
245805
245831
  }
@@ -246273,8 +246299,8 @@ var EventMetadataKey;
246273
246299
  })(EventMetadataKey || (EventMetadataKey = {}));
246274
246300
 
246275
246301
  // packages/core/dist/src/generated/git-commit.js
246276
- var GIT_COMMIT_INFO = "8db727552";
246277
- var CLI_VERSION = "0.42.0";
246302
+ var GIT_COMMIT_INFO = "5ee05c775";
246303
+ var CLI_VERSION = "0.44.0-nightly.20260512.g022e8baef";
246278
246304
 
246279
246305
  // packages/core/dist/src/ide/detect-ide.js
246280
246306
  var IDE_DEFINITIONS = {
@@ -248124,7 +248150,35 @@ var GcpMetricExporter = class extends import_opentelemetry_cloud_monitoring_expo
248124
248150
  prefix: "custom.googleapis.com/gemini_cli"
248125
248151
  });
248126
248152
  }
248153
+ export(metrics2, resultCallback) {
248154
+ super.export(metrics2, (result2) => {
248155
+ if (result2.code === import_core5.ExportResultCode.FAILED && result2.error) {
248156
+ const errorMessage = result2.error.message || String(result2.error);
248157
+ if (process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true" && errorMessage.includes("written more frequently than the maximum sampling period")) {
248158
+ resultCallback({ code: import_core5.ExportResultCode.SUCCESS });
248159
+ return;
248160
+ }
248161
+ }
248162
+ resultCallback(result2);
248163
+ });
248164
+ }
248127
248165
  };
248166
+ function truncateLogPayload(payload, limit = 2e5) {
248167
+ if (typeof payload === "string") {
248168
+ return payload.length > limit ? payload.substring(0, limit) + "... (truncated due to size)" : payload;
248169
+ }
248170
+ if (Array.isArray(payload)) {
248171
+ return payload.map((item) => truncateLogPayload(item, limit));
248172
+ }
248173
+ if (payload !== null && typeof payload === "object") {
248174
+ const truncatedObj = {};
248175
+ for (const [key, value] of Object.entries(payload)) {
248176
+ truncatedObj[key] = truncateLogPayload(value, limit);
248177
+ }
248178
+ return truncatedObj;
248179
+ }
248180
+ return payload;
248181
+ }
248128
248182
  var GcpLogExporter = class {
248129
248183
  logging;
248130
248184
  log;
@@ -248136,20 +248190,46 @@ var GcpLogExporter = class {
248136
248190
  export(logs3, resultCallback) {
248137
248191
  try {
248138
248192
  const entries = logs3.map((log) => {
248139
- const entry = this.log.entry({
248140
- severity: this.mapSeverityToCloudLogging(log.severityNumber),
248141
- timestamp: new Date((0, import_core5.hrTimeToMilliseconds)(log.hrTime)),
248142
- resource: {
248143
- type: "global",
248144
- labels: {
248145
- project_id: this.logging.projectId
248146
- }
248147
- }
248148
- }, {
248193
+ const rawPayload = {
248149
248194
  ...log.attributes,
248150
248195
  ...log.resource?.attributes,
248151
248196
  message: log.body
248152
- });
248197
+ };
248198
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
248199
+ let finalPayload = rawPayload;
248200
+ if (isStrictTelemetry) {
248201
+ let safePayload = truncateLogPayload(rawPayload, 1e4);
248202
+ let payloadString = JSON.stringify(safePayload);
248203
+ if (payloadString && payloadString.length > 1e5) {
248204
+ safePayload = truncateLogPayload(rawPayload, 2e3);
248205
+ payloadString = JSON.stringify(safePayload);
248206
+ if (payloadString && payloadString.length > 1e5) {
248207
+ safePayload = truncateLogPayload(rawPayload, 5e3);
248208
+ payloadString = JSON.stringify(safePayload);
248209
+ if (payloadString && payloadString.length > 1e5) {
248210
+ safePayload = {
248211
+ _warning: "Payload heavily truncated due to strict limits",
248212
+ data: payloadString.substring(0, 5e4) + "... (truncated)"
248213
+ };
248214
+ }
248215
+ }
248216
+ }
248217
+ finalPayload = safePayload;
248218
+ }
248219
+ const entry = this.log.entry(
248220
+ {
248221
+ severity: this.mapSeverityToCloudLogging(log.severityNumber),
248222
+ timestamp: new Date((0, import_core5.hrTimeToMilliseconds)(log.hrTime)),
248223
+ resource: {
248224
+ type: "global",
248225
+ labels: {
248226
+ project_id: this.logging.projectId
248227
+ }
248228
+ }
248229
+ },
248230
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
248231
+ finalPayload
248232
+ );
248153
248233
  return entry;
248154
248234
  });
248155
248235
  const writePromise = this.log.write(entries).then(() => {
@@ -268951,7 +269031,12 @@ async function getConnectionConfigFromFile(pid) {
268951
269031
  try {
268952
269032
  const portFile = path26.join(os17.tmpdir(), "gemini", "ide", `gemini-ide-server-${pid}.json`);
268953
269033
  const portFileContents = await fs29.promises.readFile(portFile, "utf8");
268954
- return JSON.parse(portFileContents);
269034
+ const parsed = JSON.parse(portFileContents);
269035
+ const isConfig = (val) => typeof val === "object" && val !== null;
269036
+ if (isConfig(parsed)) {
269037
+ return parsed;
269038
+ }
269039
+ throw new Error("Invalid connection config format");
268955
269040
  } catch {
268956
269041
  }
268957
269042
  const portFileDir = path26.join(os17.tmpdir(), "gemini", "ide");
@@ -268979,7 +269064,12 @@ async function getConnectionConfigFromFile(pid) {
268979
269064
  }
268980
269065
  const parsedContents = fileContents.map((content) => {
268981
269066
  try {
268982
- return JSON.parse(content);
269067
+ const parsed = JSON.parse(content);
269068
+ const isConfig = (val) => typeof val === "object" && val !== null;
269069
+ if (isConfig(parsed)) {
269070
+ return parsed;
269071
+ }
269072
+ return void 0;
268983
269073
  } catch (e2) {
268984
269074
  logger.debug("Failed to parse JSON from config file: ", e2);
268985
269075
  return void 0;
@@ -269321,7 +269411,7 @@ function getVersion() {
269321
269411
  }
269322
269412
  versionPromise = (async () => {
269323
269413
  const pkgJson = await getPackageJson(__dirname4);
269324
- return "0.42.0";
269414
+ return "0.44.0-nightly.20260512.g022e8baef";
269325
269415
  })();
269326
269416
  return versionPromise;
269327
269417
  }
@@ -269537,8 +269627,11 @@ var IdeClient = class _IdeClient {
269537
269627
  if (textPart?.text) {
269538
269628
  try {
269539
269629
  const parsedJson = JSON.parse(textPart.text);
269540
- if (parsedJson && typeof parsedJson.content === "string") {
269541
- return parsedJson.content;
269630
+ if (parsedJson) {
269631
+ const content = parsedJson.content;
269632
+ if (typeof content === "string") {
269633
+ return content;
269634
+ }
269542
269635
  }
269543
269636
  if (parsedJson && parsedJson.content === null) {
269544
269637
  return void 0;
@@ -270213,18 +270306,25 @@ function cloneChain(chain2) {
270213
270306
  return chain2.map(clonePolicy);
270214
270307
  }
270215
270308
 
270309
+ // packages/core/dist/src/utils/modelUtils.js
270310
+ function normalizeModelId(modelId) {
270311
+ return modelId.startsWith("models/") ? modelId.slice(7) : modelId;
270312
+ }
270313
+
270216
270314
  // packages/core/dist/src/availability/policyHelpers.js
270217
270315
  function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270218
- const modelFromConfig = preferredModel ?? config2.getActiveModel?.() ?? config2.getModel();
270219
- const configuredModel = config2.getModel();
270316
+ const normalizedPreferredModel = preferredModel ? normalizeModelId(preferredModel) : void 0;
270317
+ const modelFromConfig = normalizeModelId(normalizedPreferredModel ?? config2.getActiveModel?.() ?? config2.getModel());
270318
+ const configuredModel = normalizeModelId(config2.getModel());
270220
270319
  let chain2;
270221
270320
  const useGemini31 = config2.getGemini31LaunchedSync?.() ?? false;
270222
270321
  const useGemini31FlashLite = config2.getGemini31FlashLiteLaunchedSync?.() ?? false;
270223
270322
  const useCustomToolModel = config2.getUseCustomToolModelSync?.() ?? false;
270224
270323
  const hasAccessToPreview = config2.getHasAccessToPreviewModel?.() ?? true;
270225
- const resolvedModel = resolveModel(modelFromConfig, useGemini31, useGemini31FlashLite, useCustomToolModel, hasAccessToPreview, config2);
270226
- const isAutoPreferred = preferredModel ? isAutoModel(preferredModel, config2) : false;
270324
+ const resolvedModel = normalizeModelId(resolveModel(modelFromConfig, useGemini31, useGemini31FlashLite, useCustomToolModel, hasAccessToPreview, config2));
270325
+ const isAutoPreferred = normalizedPreferredModel ? isAutoModel(normalizedPreferredModel, config2) : false;
270227
270326
  const isAutoConfigured = isAutoModel(configuredModel, config2);
270327
+ const effectiveWrapsAround = wrapsAround || isAutoPreferred || isAutoConfigured || isGemini3Model(resolvedModel, config2);
270228
270328
  if (config2.getExperimentalDynamicModelConfiguration?.() === true) {
270229
270329
  const context2 = {
270230
270330
  useGemini3_1: useGemini31,
@@ -270233,13 +270333,13 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270233
270333
  };
270234
270334
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270235
270335
  chain2 = config2.modelConfigService.resolveChain("lite", context2);
270236
- } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270336
+ } else if (isGemini3Model(normalizeModelId(resolvedModel), config2) || isAutoPreferred || isAutoConfigured) {
270237
270337
  if (isAutoConfigured && config2.modelConfigService.getModelChain(configuredModel)) {
270238
270338
  chain2 = config2.modelConfigService.resolveChain(configuredModel, context2);
270239
270339
  }
270240
270340
  if (!chain2) {
270241
270341
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270242
- const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270342
+ const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270243
270343
  const autoPrefix = isAutoSelection ? "auto-" : "";
270244
270344
  const chainKey = previewEnabled ? "preview" : "default";
270245
270345
  chain2 = config2.modelConfigService.resolveChain(`${autoPrefix}${chainKey}`, context2);
@@ -270248,14 +270348,14 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270248
270348
  if (!chain2) {
270249
270349
  chain2 = createSingleModelChain(modelFromConfig);
270250
270350
  }
270251
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270351
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270252
270352
  } else {
270253
270353
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270254
270354
  chain2 = getFlashLitePolicyChain();
270255
270355
  } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270256
270356
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270257
270357
  if (hasAccessToPreview) {
270258
- const previewEnabled = isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270358
+ const previewEnabled = isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270259
270359
  chain2 = getModelPolicyChain({
270260
270360
  previewEnabled,
270261
270361
  isAutoSelection,
@@ -270277,7 +270377,7 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270277
270377
  } else {
270278
270378
  chain2 = createSingleModelChain(modelFromConfig);
270279
270379
  }
270280
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270380
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270281
270381
  }
270282
270382
  if (config2?.getApprovalMode?.() === ApprovalMode.PLAN) {
270283
270383
  return chain2.map((policy) => ({
@@ -270288,14 +270388,16 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270288
270388
  return chain2;
270289
270389
  }
270290
270390
  function applyDynamicSlicing(chain2, resolvedModel, wrapsAround) {
270291
- const activeIndex = chain2.findIndex((policy) => policy.model === resolvedModel);
270391
+ const normalizedResolved = normalizeModelId(resolvedModel);
270392
+ const activeIndex = chain2.findIndex((policy) => normalizeModelId(policy.model) === normalizedResolved);
270292
270393
  if (activeIndex !== -1) {
270293
270394
  return wrapsAround ? [...chain2.slice(activeIndex), ...chain2.slice(0, activeIndex)] : [...chain2.slice(activeIndex)];
270294
270395
  }
270295
270396
  return [createDefaultPolicy(resolvedModel, { isLastResort: true })];
270296
270397
  }
270297
270398
  function buildFallbackPolicyContext(chain2, failedModel, wrapsAround = false) {
270298
- const index = chain2.findIndex((policy) => policy.model === failedModel);
270399
+ const normalizedFailed = normalizeModelId(failedModel);
270400
+ const index = chain2.findIndex((policy) => normalizeModelId(policy.model) === normalizedFailed);
270299
270401
  if (index === -1) {
270300
270402
  return { failedPolicy: void 0, candidates: chain2 };
270301
270403
  }
@@ -270857,7 +270959,12 @@ var BaseLlmClient = class {
270857
270959
  responseMimeType: "application/json"
270858
270960
  }
270859
270961
  }, shouldRetryOnContent, "generateJson", role);
270860
- return JSON.parse(this.cleanJsonResponse(getResponseText(result2).trim(), model));
270962
+ const parsed = JSON.parse(this.cleanJsonResponse(getResponseText(result2).trim(), model));
270963
+ const isRecord3 = (val) => typeof val === "object" && val !== null && !Array.isArray(val);
270964
+ if (isRecord3(parsed)) {
270965
+ return parsed;
270966
+ }
270967
+ throw new Error("Invalid JSON response format from LLM");
270861
270968
  }
270862
270969
  async generateEmbedding(texts) {
270863
270970
  if (!texts || texts.length === 0) {
@@ -270891,6 +270998,15 @@ var BaseLlmClient = class {
270891
270998
  }
270892
270999
  return text;
270893
271000
  }
271001
+ async countTokens(options) {
271002
+ const model = options.modelConfigKey ? this.config.modelConfigService.getResolvedConfig(options.modelConfigKey).model : this.config.getActiveModel();
271003
+ const result2 = await this.contentGenerator.countTokens({
271004
+ model,
271005
+ contents: options.contents,
271006
+ config: options.abortSignal ? { abortSignal: options.abortSignal } : void 0
271007
+ });
271008
+ return { totalTokens: result2.totalTokens || 0 };
271009
+ }
270894
271010
  async generateContent(options) {
270895
271011
  const { modelConfigKey, contents, systemInstruction, abortSignal, promptId, role, maxAttempts } = options;
270896
271012
  const shouldRetryOnContent = (response) => {
@@ -271470,6 +271586,9 @@ function isEditToolParams(args2) {
271470
271586
  }
271471
271587
  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";
271472
271588
  }
271589
+ function fileDiffToSummary(diff, editData) {
271590
+ return diff.diffStat ? `${diff.diffStat.model_added_lines} added, ${diff.diffStat.model_removed_lines} removed` : `${editData.occurrences} replacements`;
271591
+ }
271473
271592
  var EditToolInvocation = class extends BaseToolInvocation {
271474
271593
  config;
271475
271594
  resolvedPath;
@@ -271846,8 +271965,20 @@ ${snippet2}`);
271846
271965
  if (jitContext) {
271847
271966
  llmContent = appendJitContext(llmContent, jitContext);
271848
271967
  }
271968
+ const resultSummary = typeof displayResult === "string" ? displayResult : fileDiffToSummary(displayResult, editData);
271849
271969
  return {
271850
271970
  llmContent,
271971
+ display: {
271972
+ name: this._toolDisplayName,
271973
+ description: this.getDescription(),
271974
+ resultSummary,
271975
+ result: {
271976
+ type: "diff",
271977
+ path: this.resolvedPath,
271978
+ beforeText: editData.currentContent ?? "",
271979
+ afterText: editData.newContent
271980
+ }
271981
+ },
271851
271982
  returnDisplay: displayResult
271852
271983
  };
271853
271984
  } catch (error40) {
@@ -272377,6 +272508,17 @@ ${snippet2}`);
272377
272508
  }
272378
272509
  return {
272379
272510
  llmContent,
272511
+ display: {
272512
+ name: WRITE_FILE_DISPLAY_NAME,
272513
+ description: this.getDescription(),
272514
+ resultSummary: diffStat ? `${diffStat.model_added_lines} added, ${diffStat.model_removed_lines} removed` : "Written",
272515
+ result: {
272516
+ type: "diff",
272517
+ path: this.resolvedPath,
272518
+ beforeText: correctedContentResult.originalContent ?? "",
272519
+ afterText: correctedContentResult.correctedContent
272520
+ }
272521
+ },
272380
272522
  returnDisplay: displayResult
272381
272523
  };
272382
272524
  } catch (error40) {
@@ -273099,6 +273241,12 @@ var ProjectIdRequiredError = class extends Error {
273099
273241
  this.name = "ProjectIdRequiredError";
273100
273242
  }
273101
273243
  };
273244
+ var InvalidNumericProjectIdError = class extends Error {
273245
+ constructor(projectId) {
273246
+ super(`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.`);
273247
+ this.name = "InvalidNumericProjectIdError";
273248
+ }
273249
+ };
273102
273250
  var ValidationCancelledError = class extends Error {
273103
273251
  constructor() {
273104
273252
  super("User cancelled account validation");
@@ -273124,6 +273272,9 @@ function resetUserDataCacheForTesting() {
273124
273272
  }
273125
273273
  async function setupUser(client, config2, httpOptions = {}) {
273126
273274
  const projectId = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
273275
+ if (projectId && /^\d+$/.test(projectId)) {
273276
+ throw new InvalidNumericProjectIdError(projectId);
273277
+ }
273127
273278
  const projectCache = userDataCache.getOrCreate(client, () => createCache({
273128
273279
  storage: "map",
273129
273280
  defaultTtl: 3e4
@@ -273273,13 +273424,26 @@ function validateLoadCodeAssistResponse(res) {
273273
273424
 
273274
273425
  // packages/core/dist/src/utils/quotaErrorDetection.js
273275
273426
  function isApiError(error40) {
273276
- return typeof error40 === "object" && error40 !== null && "error" in error40 && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
273277
- typeof error40.error === "object" && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
273278
- "message" in error40.error;
273427
+ if (typeof error40 !== "object" || error40 === null || !("error" in error40)) {
273428
+ return false;
273429
+ }
273430
+ const errorProp = error40.error;
273431
+ if (typeof errorProp !== "object" || errorProp === null) {
273432
+ return false;
273433
+ }
273434
+ return "code" in errorProp && typeof errorProp.code === "number" && "message" in errorProp && typeof errorProp.message === "string" && "status" in errorProp && typeof errorProp.status === "string";
273279
273435
  }
273280
273436
  function isStructuredError(error40) {
273281
- return typeof error40 === "object" && error40 !== null && "message" in error40 && // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
273282
- typeof error40.message === "string";
273437
+ if (typeof error40 !== "object" || error40 === null || !("message" in error40)) {
273438
+ return false;
273439
+ }
273440
+ if (typeof error40.message !== "string") {
273441
+ return false;
273442
+ }
273443
+ if ("status" in error40 && typeof error40.status !== "number") {
273444
+ return false;
273445
+ }
273446
+ return true;
273283
273447
  }
273284
273448
 
273285
273449
  // packages/core/dist/src/utils/tokenCalculation.js
@@ -273296,9 +273460,10 @@ function estimateTextTokens(text, charsPerToken) {
273296
273460
  return text.length / charsPerToken;
273297
273461
  }
273298
273462
  let tokens = 0;
273463
+ const asciiTokensPerChar = 1 / charsPerToken;
273299
273464
  for (let i3 = 0; i3 < text.length; i3++) {
273300
273465
  if (text.charCodeAt(i3) <= 127) {
273301
- tokens += ASCII_TOKENS_PER_CHAR;
273466
+ tokens += asciiTokensPerChar;
273302
273467
  } else {
273303
273468
  tokens += NON_ASCII_TOKENS_PER_CHAR;
273304
273469
  }
@@ -273762,7 +273927,12 @@ var FakeContentGenerator = class _FakeContentGenerator {
273762
273927
  return response.response;
273763
273928
  }
273764
273929
  async generateContent(request, _userPromptId, role) {
273765
- return Object.setPrototypeOf(this.getNextResponse("generateContent", request), GenerateContentResponse.prototype);
273930
+ const response = this.getNextResponse("generateContent", request);
273931
+ Object.setPrototypeOf(response, GenerateContentResponse.prototype);
273932
+ if (response instanceof GenerateContentResponse) {
273933
+ return response;
273934
+ }
273935
+ throw new Error("Failed to create GenerateContentResponse");
273766
273936
  }
273767
273937
  async generateContentStream(request, _userPromptId, role) {
273768
273938
  const responses = this.getNextResponse("generateContentStream", request);
@@ -273777,7 +273947,12 @@ var FakeContentGenerator = class _FakeContentGenerator {
273777
273947
  return this.getNextResponse("countTokens", request);
273778
273948
  }
273779
273949
  async embedContent(request) {
273780
- return Object.setPrototypeOf(this.getNextResponse("embedContent", request), EmbedContentResponse.prototype);
273950
+ const response = this.getNextResponse("embedContent", request);
273951
+ Object.setPrototypeOf(response, EmbedContentResponse.prototype);
273952
+ if (response instanceof EmbedContentResponse) {
273953
+ return response;
273954
+ }
273955
+ throw new Error("Failed to create EmbedContentResponse");
273781
273956
  }
273782
273957
  };
273783
273958
 
@@ -273937,10 +274112,6 @@ function validateBaseUrl(baseUrl) {
273937
274112
  }
273938
274113
  }
273939
274114
  async function createContentGeneratorConfig(config2, authType, apiKey, baseUrl, customHeaders, vertexAiRouting) {
273940
- const geminiApiKey = apiKey || process.env["GEMINI_API_KEY"] || await loadApiKey() || void 0;
273941
- const googleApiKey = process.env["GOOGLE_API_KEY"] || void 0;
273942
- const googleCloudProject = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
273943
- const googleCloudLocation = process.env["GOOGLE_CLOUD_LOCATION"] || void 0;
273944
274115
  const contentGeneratorConfig = {
273945
274116
  authType,
273946
274117
  proxy: config2?.getProxy(),
@@ -273951,6 +274122,10 @@ async function createContentGeneratorConfig(config2, authType, apiKey, baseUrl,
273951
274122
  if (authType === AuthType.LOGIN_WITH_GOOGLE || authType === AuthType.COMPUTE_ADC) {
273952
274123
  return contentGeneratorConfig;
273953
274124
  }
274125
+ const geminiApiKey = apiKey || process.env["GEMINI_API_KEY"] || await loadApiKey() || void 0;
274126
+ const googleApiKey = process.env["GOOGLE_API_KEY"] || void 0;
274127
+ const googleCloudProject = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
274128
+ const googleCloudLocation = process.env["GOOGLE_CLOUD_LOCATION"] || void 0;
273954
274129
  if (authType === AuthType.USE_GEMINI && geminiApiKey) {
273955
274130
  contentGeneratorConfig.apiKey = geminiApiKey;
273956
274131
  contentGeneratorConfig.vertexai = false;
@@ -274898,6 +275073,11 @@ ${directoryContent}`;
274898
275073
  }
274899
275074
  return {
274900
275075
  llmContent: resultMessage,
275076
+ display: {
275077
+ name: LS_DISPLAY_NAME,
275078
+ description: this.getDescription(),
275079
+ resultSummary: displayMessage
275080
+ },
274901
275081
  returnDisplay: {
274902
275082
  summary: displayMessage,
274903
275083
  files: entries.map((entry) => `${entry.isDirectory ? "[DIR] " : ""}${entry.name}`)
@@ -275130,7 +275310,7 @@ var IgnoreFileParser = class {
275130
275310
  return this.patterns;
275131
275311
  }
275132
275312
  getIgnoreFilePaths() {
275133
- return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter((filePath) => fs34.existsSync(filePath));
275313
+ return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter((filePath) => fs34.statSync(filePath, { throwIfNoEntry: false })?.isFile() ?? false);
275134
275314
  }
275135
275315
  /**
275136
275316
  * Returns true if at least one ignore file exists and has patterns.
@@ -275353,7 +275533,8 @@ var FileDiscoveryService = class {
275353
275533
  const paths = [];
275354
275534
  if (this.gitIgnoreFilter && this.defaultFilterFileOptions.respectGitIgnore) {
275355
275535
  const gitIgnorePath = path41.join(this.projectRoot, ".gitignore");
275356
- if (fs36.existsSync(gitIgnorePath)) {
275536
+ const stat9 = fs36.statSync(gitIgnorePath, { throwIfNoEntry: false });
275537
+ if (stat9?.isFile()) {
275357
275538
  paths.push(gitIgnorePath);
275358
275539
  }
275359
275540
  }
@@ -275438,8 +275619,15 @@ ${result2.llmContent}`;
275438
275619
  llmContent = appendJitContextToParts(llmContent, jitContext);
275439
275620
  }
275440
275621
  }
275622
+ const displayResultSummary = result2.isTruncated ? `${result2.linesShown[0]}-${result2.linesShown[1]} of ${result2.originalLineCount}` : lines !== void 0 ? `${lines} lines` : void 0;
275441
275623
  return {
275442
275624
  llmContent,
275625
+ display: {
275626
+ name: READ_FILE_DISPLAY_NAME,
275627
+ description: this.getDescription(),
275628
+ resultSummary: displayResultSummary,
275629
+ result: { type: "text", text: result2.returnDisplay || "" }
275630
+ },
275443
275631
  returnDisplay: result2.returnDisplay || ""
275444
275632
  };
275445
275633
  }
@@ -275462,12 +275650,6 @@ var ReadFileTool = class _ReadFileTool extends BaseDeclarativeTool {
275462
275650
  if (validationError) {
275463
275651
  return validationError;
275464
275652
  }
275465
- if (params.start_line !== void 0 && params.start_line < 1) {
275466
- return "start_line must be at least 1";
275467
- }
275468
- if (params.end_line !== void 0 && params.end_line < 1) {
275469
- return "end_line must be at least 1";
275470
- }
275471
275653
  if (params.start_line !== void 0 && params.end_line !== void 0 && params.start_line > params.end_line) {
275472
275654
  return "start_line cannot be greater than end_line";
275473
275655
  }
@@ -281703,10 +281885,10 @@ var Ignore = class {
281703
281885
  ignored(p) {
281704
281886
  const fullpath = p.fullpath();
281705
281887
  const fullpaths = `${fullpath}/`;
281706
- const relative12 = p.relative() || ".";
281707
- const relatives = `${relative12}/`;
281888
+ const relative11 = p.relative() || ".";
281889
+ const relatives = `${relative11}/`;
281708
281890
  for (const m of this.relative) {
281709
- if (m.match(relative12) || m.match(relatives))
281891
+ if (m.match(relative11) || m.match(relatives))
281710
281892
  return true;
281711
281893
  }
281712
281894
  for (const m of this.absolute) {
@@ -281717,9 +281899,9 @@ var Ignore = class {
281717
281899
  }
281718
281900
  childrenIgnored(p) {
281719
281901
  const fullpath = p.fullpath() + "/";
281720
- const relative12 = (p.relative() || ".") + "/";
281902
+ const relative11 = (p.relative() || ".") + "/";
281721
281903
  for (const m of this.relativeChildren) {
281722
- if (m.match(relative12))
281904
+ if (m.match(relative11))
281723
281905
  return true;
281724
281906
  }
281725
281907
  for (const m of this.absoluteChildren) {
@@ -282824,7 +283006,19 @@ var GrepToolInvocation = class extends BaseToolInvocation {
282824
283006
  } else {
282825
283007
  searchLocationDescription = `in path "${searchDirDisplay}"`;
282826
283008
  }
282827
- return await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283009
+ const result2 = await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283010
+ return {
283011
+ ...result2,
283012
+ display: {
283013
+ name: this._toolDisplayName,
283014
+ description: this.getDescription(),
283015
+ resultSummary: result2.returnDisplay.summary,
283016
+ result: {
283017
+ type: "text",
283018
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
283019
+ }
283020
+ }
283021
+ };
282828
283022
  } catch (error40) {
282829
283023
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
282830
283024
  const errorMessage = getErrorMessage(error40);
@@ -283283,7 +283477,19 @@ var GrepToolInvocation2 = class extends BaseToolInvocation {
283283
283477
  const matchCount = allMatches.filter((m) => !m.isContext).length;
283284
283478
  allMatches = await this.enrichWithRipgrepAutoContext(allMatches, matchCount, totalMaxMatches, searchDirAbs, timeoutController.signal);
283285
283479
  const searchLocationDescription = `in path "${searchDirDisplay}"`;
283286
- return await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283480
+ const result2 = await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283481
+ return {
283482
+ ...result2,
283483
+ display: {
283484
+ name: this._toolDisplayName,
283485
+ description: this.getDescription(),
283486
+ resultSummary: result2.returnDisplay.summary,
283487
+ result: {
283488
+ type: "text",
283489
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
283490
+ }
283491
+ }
283492
+ };
283287
283493
  } catch (error40) {
283288
283494
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
283289
283495
  const errorMessage = getErrorMessage(error40);
@@ -286819,8 +287025,18 @@ ${result2.output}`;
286819
287025
  ...executionError
286820
287026
  };
286821
287027
  }
287028
+ const displayResultSummary = result2.backgrounded ? `PID: ${result2.pid}` : result2.exitCode !== null && result2.exitCode !== 0 ? `Exit Code: ${result2.exitCode}` : void 0;
286822
287029
  return {
286823
287030
  llmContent,
287031
+ display: {
287032
+ name: "Shell",
287033
+ description: this.getDescription(),
287034
+ resultSummary: displayResultSummary,
287035
+ result: typeof returnDisplay === "string" ? { type: "text", text: returnDisplay } : (
287036
+ // TODO: Add support for terminal display type (AnsiOutput)
287037
+ void 0
287038
+ )
287039
+ },
286824
287040
  returnDisplay,
286825
287041
  data,
286826
287042
  ...executionError
@@ -292906,6 +293122,11 @@ Strategic Intent: ${strategicIntent.trim()}`;
292906
293122
  }
292907
293123
  return {
292908
293124
  llmContent,
293125
+ display: {
293126
+ format: "notice",
293127
+ name: title || UPDATE_TOPIC_DISPLAY_NAME,
293128
+ description: this.getDescription()
293129
+ },
292909
293130
  returnDisplay
292910
293131
  };
292911
293132
  }
@@ -293357,6 +293578,9 @@ var GeminiChat = class {
293357
293578
  this.chatRecordingService = new ChatRecordingService(context2);
293358
293579
  this.lastPromptTokenCount = estimateTokenCountSync(this.agentHistory.flatMap((c4) => c4.parts || []));
293359
293580
  }
293581
+ get loopContext() {
293582
+ return this.context;
293583
+ }
293360
293584
  async initialize(resumedSessionData, kind = "main") {
293361
293585
  await this.chatRecordingService.initialize(resumedSessionData, kind);
293362
293586
  }
@@ -293614,9 +293838,10 @@ var GeminiChat = class {
293614
293838
  lastModelToUse = modelToUse;
293615
293839
  lastConfig = config2;
293616
293840
  lastContentsToUse = contentsToUse;
293841
+ const finalContents = stripToolCallIdPrefixes(contentsToUse);
293617
293842
  return this.context.config.getContentGenerator().generateContentStream({
293618
293843
  model: modelToUse,
293619
- contents: contentsToUse,
293844
+ contents: finalContents,
293620
293845
  config: config2
293621
293846
  }, prompt_id, role);
293622
293847
  };
@@ -293785,7 +294010,9 @@ This error was probably caused by cyclic schema references in one of the followi
293785
294010
  const finalFunctionCallsMap = /* @__PURE__ */ new Map();
293786
294011
  const legacyFunctionCalls = [];
293787
294012
  const callIndexToId = /* @__PURE__ */ new Map();
294013
+ let runningFunctionCallCounter = 0;
293788
294014
  for await (const chunk of streamResponse) {
294015
+ const currentChunkStartCounter = runningFunctionCallCounter;
293789
294016
  const candidateWithReason = chunk?.candidates?.find((candidate) => candidate.finishReason);
293790
294017
  if (candidateWithReason) {
293791
294018
  finishReason = candidateWithReason.finishReason;
@@ -293794,18 +294021,30 @@ This error was probably caused by cyclic schema references in one of the followi
293794
294021
  if (this.context.config.isContextManagementEnabled()) {
293795
294022
  for (let i3 = 0; i3 < chunk.functionCalls.length; i3++) {
293796
294023
  const fnCall = chunk.functionCalls[i3];
294024
+ const globalIndex = currentChunkStartCounter + i3;
293797
294025
  if (!fnCall.id) {
293798
- let id = callIndexToId.get(i3);
294026
+ let id = callIndexToId.get(globalIndex);
293799
294027
  if (!id) {
293800
294028
  id = `synth_${this.context.promptId}_${Date.now()}_${this.callCounter++}`;
293801
- callIndexToId.set(i3, id);
293802
- debugLogger.log(`[GeminiChat] Assigned synthetic ID: ${id} to tool at index ${i3}: ${fnCall.name}`);
294029
+ callIndexToId.set(globalIndex, id);
294030
+ debugLogger.log(`[GeminiChat] Assigned synthetic ID: ${id} to tool at index ${globalIndex}: ${fnCall.name}`);
293803
294031
  }
293804
294032
  fnCall.id = id;
293805
294033
  }
294034
+ const name3 = fnCall.name?.trim() || "generic_tool";
294035
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
294036
+ fnCall.id = `${name3}__${fnCall.id}`;
294037
+ }
293806
294038
  finalFunctionCallsMap.set(fnCall.id, fnCall);
293807
294039
  }
294040
+ runningFunctionCallCounter += chunk.functionCalls.length;
293808
294041
  } else {
294042
+ for (const fnCall of chunk.functionCalls) {
294043
+ const name3 = fnCall.name?.trim() || "generic_tool";
294044
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
294045
+ fnCall.id = `${name3}__${fnCall.id}`;
294046
+ }
294047
+ }
293809
294048
  legacyFunctionCalls.push(...chunk.functionCalls);
293810
294049
  }
293811
294050
  }
@@ -293819,13 +294058,18 @@ This error was probably caused by cyclic schema references in one of the followi
293819
294058
  if (content.parts.some((part) => part.functionCall)) {
293820
294059
  hasToolCall = true;
293821
294060
  }
294061
+ let localFunctionCallCounter = 0;
293822
294062
  modelResponseParts.push(...content.parts.filter((part) => !part.thought).map((part) => {
293823
294063
  if (!this.context.config.isContextManagementEnabled()) {
293824
294064
  return part;
293825
294065
  }
294066
+ let callIndex;
294067
+ if (part.functionCall) {
294068
+ callIndex = currentChunkStartCounter + localFunctionCallCounter++;
294069
+ }
293826
294070
  return {
293827
294071
  ...part,
293828
- callIndex: chunk.functionCalls?.findIndex((fc) => fc.name === part.functionCall?.name)
294072
+ callIndex
293829
294073
  };
293830
294074
  }));
293831
294075
  }
@@ -293972,6 +294216,82 @@ function isSchemaDepthError(errorMessage) {
293972
294216
  function isInvalidArgumentError(errorMessage) {
293973
294217
  return errorMessage.includes("Request contains an invalid argument");
293974
294218
  }
294219
+ function stripToolCallIdPrefixes(contents) {
294220
+ return contents.map((content) => ({
294221
+ ...content,
294222
+ parts: (content.parts || []).map((part) => {
294223
+ const newPart = { ...part };
294224
+ if (newPart.functionCall) {
294225
+ const fc = newPart.functionCall;
294226
+ const name3 = fc.name?.trim() || "generic_tool";
294227
+ if (fc.id && fc.id.startsWith(`${name3}__`)) {
294228
+ newPart.functionCall = {
294229
+ name: fc.name,
294230
+ args: fc.args,
294231
+ id: fc.id.substring(name3.length + 2)
294232
+ };
294233
+ }
294234
+ }
294235
+ if (newPart.functionResponse) {
294236
+ const fr = newPart.functionResponse;
294237
+ const name3 = fr.name?.trim() || "generic_tool";
294238
+ if (fr.id && fr.id.startsWith(`${name3}__`)) {
294239
+ newPart.functionResponse = {
294240
+ name: fr.name,
294241
+ response: fr.response,
294242
+ id: fr.id.substring(name3.length + 2)
294243
+ };
294244
+ }
294245
+ }
294246
+ return newPart;
294247
+ })
294248
+ }));
294249
+ }
294250
+
294251
+ // packages/core/dist/src/agent/tool-display-utils.js
294252
+ function populateToolDisplay({ name: name3, invocation, resultDisplay, displayName, display: prevDisplay }) {
294253
+ const display = {
294254
+ name: displayName || name3,
294255
+ description: invocation?.getDescription?.(),
294256
+ ...prevDisplay
294257
+ };
294258
+ if (resultDisplay !== void 0 && display.result === void 0) {
294259
+ display.result = toolResultDisplayToDisplayContent(resultDisplay);
294260
+ }
294261
+ return display;
294262
+ }
294263
+ function toolResultDisplayToDisplayContent(resultDisplay) {
294264
+ if (typeof resultDisplay === "string") {
294265
+ return { type: "text", text: resultDisplay };
294266
+ }
294267
+ if (typeof resultDisplay === "object" && resultDisplay !== null && "fileDiff" in resultDisplay && "newContent" in resultDisplay) {
294268
+ return {
294269
+ type: "diff",
294270
+ path: resultDisplay.filePath || resultDisplay.fileName,
294271
+ beforeText: resultDisplay.originalContent ?? "",
294272
+ afterText: resultDisplay.newContent
294273
+ };
294274
+ }
294275
+ return {
294276
+ type: "text",
294277
+ text: JSON.stringify(resultDisplay)
294278
+ };
294279
+ }
294280
+ function renderDisplayDiff(diff) {
294281
+ return createPatch(diff.path || "file", diff.beforeText, diff.afterText, "Original", "Modified", { context: 3 });
294282
+ }
294283
+ function displayContentToString(display) {
294284
+ if (!display) {
294285
+ return void 0;
294286
+ }
294287
+ if (display.type === "text") {
294288
+ return display.text;
294289
+ }
294290
+ if (display.type === "diff") {
294291
+ return renderDisplayDiff(display);
294292
+ }
294293
+ return JSON.stringify(display);
294294
+ }
293975
294295
 
293976
294296
  // packages/core/dist/src/core/turn.js
293977
294297
  var GeminiEventType;
@@ -294129,13 +294449,33 @@ ${[...this.pendingCitations].sort().join("\n")}`
294129
294449
  }
294130
294450
  }
294131
294451
  handlePendingFunctionCall(fnCall, traceId) {
294132
- const name3 = fnCall.name || "undefined_tool_name";
294452
+ const name3 = fnCall.name?.trim() || "generic_tool";
294133
294453
  const args2 = fnCall.args || {};
294134
- const callId = fnCall.id ?? (this.chat.context.config.isContextManagementEnabled() ? `synth_${this.prompt_id}_${Date.now()}_${this.callCounter++}` : `${name3}_${Date.now()}_${this.callCounter++}`);
294454
+ const rawCallId = fnCall.id ?? (this.chat.context.config.isContextManagementEnabled() ? `synth_${this.prompt_id}_${Date.now()}_${this.callCounter++}` : `${name3}_${Date.now()}_${this.callCounter++}`);
294455
+ const callId = rawCallId.startsWith(`${name3}__`) ? rawCallId : `${name3}__${rawCallId}`;
294456
+ fnCall.id = callId;
294457
+ const tool = this.chat.loopContext.toolRegistry.getTool(name3);
294458
+ let display;
294459
+ if (tool) {
294460
+ let invocation;
294461
+ try {
294462
+ invocation = tool.build(args2);
294463
+ } catch {
294464
+ }
294465
+ display = populateToolDisplay({
294466
+ name: name3,
294467
+ invocation,
294468
+ displayName: tool.displayName
294469
+ });
294470
+ if (!display.description) {
294471
+ display.description = tool.description;
294472
+ }
294473
+ }
294135
294474
  const toolCallRequest = {
294136
294475
  callId,
294137
294476
  name: name3,
294138
294477
  args: args2,
294478
+ display,
294139
294479
  isClientInitiated: false,
294140
294480
  prompt_id: this.prompt_id,
294141
294481
  traceId
@@ -294277,7 +294617,7 @@ Use the following guidelines to optimize your search and read patterns.
294277
294617
  - Prefer using tools like ${GREP_TOOL_NAME} to identify points of interest instead of reading lots of files individually.
294278
294618
  - If you need to read multiple ranges in a file, do so parallel, in as few turns as possible.
294279
294619
  - 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}.
294280
- - ${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.
294620
+ - ${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.
294281
294621
  - You can compensate for the risk of missing results with scoped or limited searches by doing multiple searches in parallel.
294282
294622
  - Your primary goal is still to do your best quality work. Efficiency is an important, but secondary concern.
294283
294623
  </guidelines>
@@ -296756,6 +297096,13 @@ var SubagentActivityErrorType;
296756
297096
  })(SubagentActivityErrorType || (SubagentActivityErrorType = {}));
296757
297097
  var SUBAGENT_REJECTED_ERROR_PREFIX = "User rejected this operation.";
296758
297098
  var SUBAGENT_CANCELLED_ERROR_MESSAGE = "Request cancelled.";
297099
+ var SubagentState;
297100
+ (function(SubagentState2) {
297101
+ SubagentState2["RUNNING"] = "running";
297102
+ SubagentState2["COMPLETED"] = "completed";
297103
+ SubagentState2["ERROR"] = "error";
297104
+ SubagentState2["CANCELLED"] = "cancelled";
297105
+ })(SubagentState || (SubagentState = {}));
296759
297106
  function isSubagentProgress(obj) {
296760
297107
  return typeof obj === "object" && obj !== null && "isSubagentProgress" in obj && obj.isSubagentProgress === true;
296761
297108
  }
@@ -300957,7 +301304,7 @@ var A2AAuthProviderFactory = class _A2AAuthProviderFactory {
300957
301304
  return provider;
300958
301305
  }
300959
301306
  case "oauth2": {
300960
- const { OAuth2AuthProvider } = await import("./oauth2-provider-H7G6RSFW.js");
301307
+ const { OAuth2AuthProvider } = await import("./oauth2-provider-O6OA5EMU.js");
300961
301308
  const provider = new OAuth2AuthProvider(authConfig, options.agentName ?? "unknown", agentCard, options.agentCardUrl);
300962
301309
  await provider.initialize();
300963
301310
  return provider;
@@ -302191,8 +302538,10 @@ var SchedulerStateManager = class {
302191
302538
  const call = this.activeCalls.get(callId);
302192
302539
  if (!call || call.status === CoreToolCallStatus.Error)
302193
302540
  return;
302541
+ const display = call.request.display ? { ...call.request.display } : { name: call.request.name };
302542
+ display.description = newInvocation.getDescription();
302194
302543
  this.activeCalls.set(callId, this.patchCall(call, {
302195
- request: { ...call.request, args: newArgs },
302544
+ request: { ...call.request, args: newArgs, display },
302196
302545
  invocation: newInvocation
302197
302546
  }));
302198
302547
  this.emitUpdate();
@@ -304384,9 +304733,30 @@ var NodeType;
304384
304733
  NodeType2["SNAPSHOT"] = "SNAPSHOT";
304385
304734
  NodeType2["ROLLING_SUMMARY"] = "ROLLING_SUMMARY";
304386
304735
  })(NodeType || (NodeType = {}));
304736
+ function isAgentThought(node) {
304737
+ return node.type === NodeType.AGENT_THOUGHT;
304738
+ }
304739
+ function isAgentYield(node) {
304740
+ return node.type === NodeType.AGENT_YIELD;
304741
+ }
304387
304742
  function isToolExecution(node) {
304388
304743
  return node.type === NodeType.TOOL_EXECUTION;
304389
304744
  }
304745
+ function isMaskedTool(node) {
304746
+ return node.type === NodeType.MASKED_TOOL;
304747
+ }
304748
+ function isUserPrompt(node) {
304749
+ return node.type === NodeType.USER_PROMPT;
304750
+ }
304751
+ function isSystemEvent(node) {
304752
+ return node.type === NodeType.SYSTEM_EVENT;
304753
+ }
304754
+ function isSnapshot(node) {
304755
+ return node.type === NodeType.SNAPSHOT;
304756
+ }
304757
+ function isRollingSummary(node) {
304758
+ return node.type === NodeType.ROLLING_SUMMARY;
304759
+ }
304390
304760
 
304391
304761
  // packages/core/dist/src/context/processors/nodeDistillationProcessor.js
304392
304762
  var NodeDistillationProcessorOptionsSchema = {
@@ -304519,44 +304889,279 @@ function createNodeDistillationProcessor(id, env2, options) {
304519
304889
  }
304520
304890
 
304521
304891
  // packages/core/dist/src/context/processors/stateSnapshotProcessor.js
304522
- import { randomUUID as randomUUID8 } from "node:crypto";
304892
+ import { randomUUID as randomUUID9 } from "node:crypto";
304893
+
304894
+ // packages/core/dist/src/context/utils/formatNodesForLlm.js
304895
+ function getSemanticToolWrapper(toolName) {
304896
+ if (toolName.includes("search") || toolName.includes("grep"))
304897
+ return `SEARCH RESULTS`;
304898
+ if (toolName.includes("list") || toolName.includes("dir"))
304899
+ return `WORKSPACE STRUCTURE`;
304900
+ if (toolName.includes("shell") || toolName.includes("cmd"))
304901
+ return `SHELL EXECUTION`;
304902
+ if (toolName.includes("read") || toolName.includes("fetch"))
304903
+ return `FILE/WEB CONTENT`;
304904
+ return `TOOL RESPONSE`;
304905
+ }
304906
+ function formatNodesForLlm(nodes, options = {}) {
304907
+ const maxToolChars = options.maxToolResponseChars ?? 2e3;
304908
+ let transcript = "";
304909
+ const uniqueTurns = Array.from(new Set(nodes.map((n3) => n3.turnId).filter(Boolean)));
304910
+ for (const node of nodes) {
304911
+ const payload = node.payload;
304912
+ let nodeContent = "";
304913
+ if (payload.text) {
304914
+ nodeContent = payload.text;
304915
+ } else if (payload.functionCall) {
304916
+ nodeContent = `CALL: ${payload.functionCall.name}(${JSON.stringify(payload.functionCall.args)})`;
304917
+ } else if (payload.functionResponse) {
304918
+ const toolName = payload.functionResponse.name || "unknown_tool";
304919
+ const rawResponse = JSON.stringify(payload.functionResponse.response);
304920
+ const semanticWrapper = getSemanticToolWrapper(toolName);
304921
+ let formattedResponse = rawResponse;
304922
+ if (rawResponse.length > maxToolChars) {
304923
+ const half = Math.floor(maxToolChars / 2);
304924
+ const truncatedCount = rawResponse.length - maxToolChars;
304925
+ formattedResponse = `${rawResponse.substring(0, half)}... [TRUNCATED ${truncatedCount} chars] ...${rawResponse.substring(rawResponse.length - half)}`;
304926
+ }
304927
+ nodeContent = `[${semanticWrapper} (${toolName})]: ${formattedResponse}`;
304928
+ } else {
304929
+ nodeContent = JSON.stringify(payload);
304930
+ }
304931
+ const role = (node.role || "system").toUpperCase();
304932
+ let turnMarker = "";
304933
+ if (node.turnId) {
304934
+ const idx = uniqueTurns.indexOf(node.turnId);
304935
+ if (idx !== -1) {
304936
+ const relativeIdx = idx - (uniqueTurns.length - 1);
304937
+ turnMarker = `[Turn ${relativeIdx}] `;
304938
+ }
304939
+ }
304940
+ transcript += `${turnMarker}[${role}] [${node.type}]: ${nodeContent}
304941
+ `;
304942
+ }
304943
+ return transcript;
304944
+ }
304523
304945
 
304524
304946
  // packages/core/dist/src/context/utils/snapshotGenerator.js
304947
+ import { randomUUID as randomUUID8 } from "node:crypto";
304948
+ function isStringArray(value) {
304949
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
304950
+ }
304951
+ function isNumberArray(value) {
304952
+ return Array.isArray(value) && value.every((item) => typeof item === "number");
304953
+ }
304954
+ function isTaskArray(value) {
304955
+ return Array.isArray(value) && value.every((item) => {
304956
+ if (!isRecord(item))
304957
+ return false;
304958
+ const id = item["id"];
304959
+ const desc = item["description"];
304960
+ return typeof id === "string" && typeof desc === "string";
304961
+ });
304962
+ }
304963
+ function isString(value) {
304964
+ return typeof value === "string";
304965
+ }
304966
+ function findLatestSnapshotBaseline(targets) {
304967
+ const lastSnapshotNode = [...targets].reverse().find((n3) => n3.type === NodeType.SNAPSHOT && n3.payload.text);
304968
+ if (lastSnapshotNode?.payload.text) {
304969
+ return {
304970
+ text: lastSnapshotNode.payload.text,
304971
+ abstractsIds: lastSnapshotNode.abstractsIds ? [...lastSnapshotNode.abstractsIds] : [],
304972
+ id: lastSnapshotNode.id
304973
+ };
304974
+ }
304975
+ return void 0;
304976
+ }
304525
304977
  var SnapshotGenerator = class {
304526
304978
  env;
304527
304979
  constructor(env2) {
304528
304980
  this.env = env2;
304529
304981
  }
304530
- async synthesizeSnapshot(nodes, systemInstruction) {
304531
- 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.
304532
- Your task is to synthesize these turns into a single, dense, factual snapshot that preserves all critical context, preferences, active tasks, and factual knowledge.
304982
+ async synthesizeSnapshot(nodes, previousStateJson, options = {}) {
304983
+ const emptyState = {
304984
+ active_tasks: [],
304985
+ discovered_facts: [],
304986
+ constraints_and_preferences: [],
304987
+ recent_arc: []
304988
+ };
304989
+ let previousState = emptyState;
304990
+ if (previousStateJson) {
304991
+ try {
304992
+ const parsed = JSON.parse(previousStateJson);
304993
+ if (isRecord(parsed)) {
304994
+ let loadedArc = [];
304995
+ if (isStringArray(parsed["recent_arc"])) {
304996
+ loadedArc = parsed["recent_arc"];
304997
+ } else if (isString(parsed["summary"]) && parsed["summary"]) {
304998
+ loadedArc = [parsed["summary"]];
304999
+ }
305000
+ previousState = {
305001
+ active_tasks: isTaskArray(parsed["active_tasks"]) ? parsed["active_tasks"] : [],
305002
+ discovered_facts: isStringArray(parsed["discovered_facts"]) ? parsed["discovered_facts"] : [],
305003
+ constraints_and_preferences: isStringArray(parsed["constraints_and_preferences"]) ? parsed["constraints_and_preferences"] : [],
305004
+ recent_arc: loadedArc
305005
+ };
305006
+ }
305007
+ } catch {
305008
+ }
305009
+ }
305010
+ let pressureWarning = "";
305011
+ const stateString = JSON.stringify(previousState);
305012
+ const estimatedTokens = this.env.tokenCalculator.estimateTokensForString(stateString);
305013
+ const maxTokens = options.maxStateTokens ?? 4e3;
305014
+ if (estimatedTokens > maxTokens * 0.8) {
305015
+ pressureWarning = `
304533
305016
 
304534
- 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.`;
304535
- let userPromptText = "TRANSCRIPT TO SNAPSHOT:\n\n";
304536
- for (const node of nodes) {
304537
- const payload = node.payload;
304538
- let nodeContent = "";
304539
- if (payload.text) {
304540
- nodeContent = payload.text;
304541
- } else if (payload.functionCall) {
304542
- nodeContent = `CALL: ${payload.functionCall.name}(${JSON.stringify(payload.functionCall.args)})`;
304543
- } else if (payload.functionResponse) {
304544
- nodeContent = `RESPONSE: ${JSON.stringify(payload.functionResponse.response)}`;
304545
- }
304546
- userPromptText += `[${node.type}]: ${nodeContent}
304547
- `;
305017
+ [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\`.`;
304548
305018
  }
304549
- const response = await this.env.llmClient.generateContent({
304550
- role: LlmRole.UTILITY_STATE_SNAPSHOT_PROCESSOR,
304551
- modelConfigKey: { model: "gemini-3-flash-base" },
304552
- contents: [{ role: "user", parts: [{ text: userPromptText }] }],
304553
- systemInstruction: { role: "system", parts: [{ text: systemPrompt }] },
304554
- promptId: this.env.promptId,
304555
- abortSignal: new AbortController().signal
304556
- });
304557
- const candidate = response.candidates?.[0];
304558
- const textPart = candidate?.content?.parts?.[0];
304559
- return textPart?.text || "";
305019
+ const systemPrompt = `You are an expert Context Memory Manager. You maintain the long-term "Master State" of the AI agent's memory.
305020
+ You will be provided with the CURRENT Master State and a raw transcript of new conversation turns.
305021
+ Your task is to generate a JSON Delta Patch representing what has changed in the transcript.${pressureWarning}
305022
+
305023
+ CRITICAL OPERATIONAL RULES:
305024
+ 1. FACTS: Extract explicit empirical facts (file paths, exact error codes, specific configs).
305025
+ 2. PRUNING: Keep facts dense. Use obsolete indices to aggressively delete facts that are no longer relevant to the current objective.
305026
+ 3. TASKS: Add any new active user requests to "new_tasks".
305027
+ 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.`;
305028
+ const userPromptText = `CURRENT MASTER STATE:
305029
+ ${JSON.stringify(previousState, null, 2)}
305030
+
305031
+ TRANSCRIPT OF NEW TURNS:
305032
+ ${formatNodesForLlm(nodes)}`;
305033
+ const patchSchema = {
305034
+ type: "object",
305035
+ properties: {
305036
+ new_facts: {
305037
+ type: "array",
305038
+ items: { type: "string" },
305039
+ description: "New specific, empirical facts discovered in this transcript chunk."
305040
+ },
305041
+ new_constraints: {
305042
+ type: "array",
305043
+ items: { type: "string" },
305044
+ description: "New specific rules or instructions provided by the user in this chunk."
305045
+ },
305046
+ new_tasks: {
305047
+ type: "array",
305048
+ items: {
305049
+ type: "object",
305050
+ properties: {
305051
+ description: {
305052
+ type: "string",
305053
+ description: "The task goal/description."
305054
+ }
305055
+ }
305056
+ }
305057
+ },
305058
+ resolved_task_ids: {
305059
+ type: "array",
305060
+ items: { type: "string" },
305061
+ description: "IDs of tasks from the CURRENT MASTER STATE that were explicitly completed or abandoned in this transcript chunk."
305062
+ },
305063
+ obsolete_fact_indices: {
305064
+ type: "array",
305065
+ items: { type: "number" },
305066
+ description: "Array indices of facts from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
305067
+ },
305068
+ obsolete_constraint_indices: {
305069
+ type: "array",
305070
+ items: { type: "number" },
305071
+ description: "Array indices of constraints from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
305072
+ },
305073
+ chronological_summary: {
305074
+ type: "string",
305075
+ description: "A 1-2 sentence summary of the mechanical actions taken in this transcript chunk."
305076
+ }
305077
+ }
305078
+ };
305079
+ let patch = {};
305080
+ try {
305081
+ const result2 = await this.env.llmClient.generateJson({
305082
+ role: LlmRole.UTILITY_STATE_SNAPSHOT_PROCESSOR,
305083
+ modelConfigKey: { model: "context-snapshotter" },
305084
+ contents: [{ role: "user", parts: [{ text: userPromptText }] }],
305085
+ systemInstruction: { role: "system", parts: [{ text: systemPrompt }] },
305086
+ schema: patchSchema,
305087
+ promptId: this.env.promptId,
305088
+ abortSignal: new AbortController().signal
305089
+ });
305090
+ if (isRecord(result2)) {
305091
+ patch = result2;
305092
+ }
305093
+ } catch {
305094
+ return JSON.stringify(previousState);
305095
+ }
305096
+ const newState = {
305097
+ active_tasks: [...previousState.active_tasks],
305098
+ discovered_facts: [...previousState.discovered_facts],
305099
+ constraints_and_preferences: [
305100
+ ...previousState.constraints_and_preferences
305101
+ ],
305102
+ recent_arc: [...previousState.recent_arc]
305103
+ };
305104
+ const resolvedIds = patch["resolved_task_ids"];
305105
+ if (isStringArray(resolvedIds)) {
305106
+ const resolvedSet = new Set(resolvedIds);
305107
+ newState.active_tasks = newState.active_tasks.filter((t2) => !resolvedSet.has(t2.id));
305108
+ }
305109
+ const obsFacts = patch["obsolete_fact_indices"];
305110
+ if (isNumberArray(obsFacts)) {
305111
+ const dropSet = new Set(obsFacts);
305112
+ newState.discovered_facts = newState.discovered_facts.filter((_, i3) => !dropSet.has(i3));
305113
+ }
305114
+ const obsConstraints = patch["obsolete_constraint_indices"];
305115
+ if (isNumberArray(obsConstraints)) {
305116
+ const dropSet = new Set(obsConstraints);
305117
+ newState.constraints_and_preferences = newState.constraints_and_preferences.filter((_, i3) => !dropSet.has(i3));
305118
+ }
305119
+ const newTasks = patch["new_tasks"];
305120
+ if (Array.isArray(newTasks)) {
305121
+ for (const t2 of newTasks) {
305122
+ if (isRecord(t2)) {
305123
+ const desc = t2["description"];
305124
+ if (typeof desc === "string" && desc) {
305125
+ newState.active_tasks.push({
305126
+ id: `task_${randomUUID8().slice(0, 8)}`,
305127
+ description: desc
305128
+ });
305129
+ }
305130
+ }
305131
+ }
305132
+ }
305133
+ const newFacts = patch["new_facts"];
305134
+ if (isStringArray(newFacts)) {
305135
+ newState.discovered_facts.push(...newFacts);
305136
+ }
305137
+ const newConstraints = patch["new_constraints"];
305138
+ if (isStringArray(newConstraints)) {
305139
+ newState.constraints_and_preferences.push(...newConstraints);
305140
+ }
305141
+ const chronoSummary = patch["chronological_summary"];
305142
+ if (typeof chronoSummary === "string" && chronoSummary) {
305143
+ newState.recent_arc.push(chronoSummary);
305144
+ const maxTurns = options.maxSummaryTurns ?? 5;
305145
+ if (newState.recent_arc.length > maxTurns) {
305146
+ newState.recent_arc = newState.recent_arc.slice(-maxTurns);
305147
+ }
305148
+ }
305149
+ let currentTokens = this.env.tokenCalculator.estimateTokensForString(JSON.stringify(newState));
305150
+ while (currentTokens > maxTokens) {
305151
+ if (newState.discovered_facts.length > 0) {
305152
+ newState.discovered_facts.shift();
305153
+ } else if (newState.constraints_and_preferences.length > 0) {
305154
+ newState.constraints_and_preferences.shift();
305155
+ } else if (newState.recent_arc.length > 0) {
305156
+ newState.recent_arc.shift();
305157
+ } else if (newState.active_tasks.length > 0) {
305158
+ newState.active_tasks.shift();
305159
+ } else {
305160
+ break;
305161
+ }
305162
+ currentTokens = this.env.tokenCalculator.estimateTokensForString(JSON.stringify(newState));
305163
+ }
305164
+ return JSON.stringify(newState);
304560
305165
  }
304561
305166
  };
304562
305167
 
@@ -304571,7 +305176,9 @@ var StateSnapshotProcessorOptionsSchema = {
304571
305176
  },
304572
305177
  freeTokensTarget: { type: "number", nullable: true },
304573
305178
  model: { type: "string", nullable: true },
304574
- systemInstruction: { type: "string", nullable: true }
305179
+ systemInstruction: { type: "string", nullable: true },
305180
+ maxSummaryTurns: { type: "number", nullable: true },
305181
+ maxStateTokens: { type: "number", nullable: true }
304575
305182
  },
304576
305183
  required: []
304577
305184
  };
@@ -304595,7 +305202,7 @@ function createStateSnapshotProcessor(id, env2, options) {
304595
305202
  const targetIds = new Set(targets.map((t2) => t2.id));
304596
305203
  const isValid = consumedIds.every((id2) => targetIds.has(id2));
304597
305204
  if (isValid) {
304598
- const newId = randomUUID8();
305205
+ const newId = randomUUID9();
304599
305206
  const snapshotNode = {
304600
305207
  id: newId,
304601
305208
  turnId: newId,
@@ -304636,9 +305243,29 @@ function createStateSnapshotProcessor(id, env2, options) {
304636
305243
  }
304637
305244
  if (nodesToSummarize.length < 2)
304638
305245
  return targets;
305246
+ let previousStateJson = void 0;
305247
+ let baselineIdToConsume = void 0;
305248
+ const baseline = findLatestSnapshotBaseline(targets);
305249
+ if (baseline) {
305250
+ previousStateJson = baseline.text;
305251
+ const summaryIdx = nodesToSummarize.findIndex((n3) => n3.id === baseline.id);
305252
+ if (summaryIdx !== -1) {
305253
+ baselineIdToConsume = baseline.id;
305254
+ nodesToSummarize.splice(summaryIdx, 1);
305255
+ }
305256
+ } else {
305257
+ debugLogger.log("[StateSnapshotProcessor] No previous snapshot found in context graph. Initializing new Master State baseline.");
305258
+ }
304639
305259
  try {
304640
- const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, options.systemInstruction);
304641
- const newId = randomUUID8();
305260
+ const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, previousStateJson, {
305261
+ maxSummaryTurns: options.maxSummaryTurns,
305262
+ maxStateTokens: options.maxStateTokens
305263
+ });
305264
+ const newId = randomUUID9();
305265
+ const consumedIds = nodesToSummarize.map((n3) => n3.id);
305266
+ if (baselineIdToConsume && !consumedIds.includes(baselineIdToConsume)) {
305267
+ consumedIds.push(baselineIdToConsume);
305268
+ }
304642
305269
  const snapshotNode = {
304643
305270
  id: newId,
304644
305271
  turnId: newId,
@@ -304646,9 +305273,8 @@ function createStateSnapshotProcessor(id, env2, options) {
304646
305273
  timestamp: nodesToSummarize[nodesToSummarize.length - 1].timestamp,
304647
305274
  role: "user",
304648
305275
  payload: { text: snapshotText },
304649
- abstractsIds: nodesToSummarize.map((n3) => n3.id)
305276
+ abstractsIds: [...consumedIds]
304650
305277
  };
304651
- const consumedIds = nodesToSummarize.map((n3) => n3.id);
304652
305278
  const returnedNodes = targets.filter((t2) => !consumedIds.includes(t2.id));
304653
305279
  const firstRemovedIdx = targets.findIndex((t2) => consumedIds.includes(t2.id));
304654
305280
  if (firstRemovedIdx !== -1) {
@@ -304667,7 +305293,6 @@ function createStateSnapshotProcessor(id, env2, options) {
304667
305293
  }
304668
305294
 
304669
305295
  // packages/core/dist/src/context/processors/stateSnapshotAsyncProcessor.js
304670
- import { randomUUID as randomUUID9 } from "node:crypto";
304671
305296
  var StateSnapshotAsyncProcessorOptionsSchema = {
304672
305297
  type: "object",
304673
305298
  properties: {
@@ -304676,7 +305301,9 @@ var StateSnapshotAsyncProcessorOptionsSchema = {
304676
305301
  enum: ["accumulate", "point-in-time"],
304677
305302
  nullable: true
304678
305303
  },
304679
- systemInstruction: { type: "string", nullable: true }
305304
+ systemInstruction: { type: "string", nullable: true },
305305
+ maxSummaryTurns: { type: "number", nullable: true },
305306
+ maxStateTokens: { type: "number", nullable: true }
304680
305307
  },
304681
305308
  required: []
304682
305309
  };
@@ -304689,9 +305316,10 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
304689
305316
  if (targets.length === 0)
304690
305317
  return;
304691
305318
  try {
304692
- let nodesToSummarize = [...targets];
304693
305319
  let previousConsumedIds = [];
304694
305320
  const processorType = options.type ?? "point-in-time";
305321
+ const nodesToSummarize = [...targets];
305322
+ let previousStateJson = void 0;
304695
305323
  if (processorType === "accumulate") {
304696
305324
  const proposedSnapshots = inbox.getMessages("PROPOSED_SNAPSHOT");
304697
305325
  const accumulateSnapshots = proposedSnapshots.filter((s2) => s2.payload.type === "accumulate");
@@ -304700,19 +305328,29 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
304700
305328
  inbox.consume(latest.id);
304701
305329
  env2.inbox.drainConsumed(/* @__PURE__ */ new Set([latest.id]));
304702
305330
  previousConsumedIds = latest.payload.consumedIds;
304703
- const snapshotId = randomUUID9();
304704
- const previousStateNode = {
304705
- id: snapshotId,
304706
- turnId: snapshotId,
304707
- type: NodeType.SNAPSHOT,
304708
- timestamp: latest.timestamp,
304709
- role: "user",
304710
- payload: { text: latest.payload.newText }
304711
- };
304712
- nodesToSummarize = [previousStateNode, ...targets];
305331
+ previousStateJson = latest.payload.newText;
305332
+ } else {
305333
+ const baseline = findLatestSnapshotBaseline(targets);
305334
+ if (baseline) {
305335
+ previousStateJson = baseline.text;
305336
+ previousConsumedIds = [...baseline.abstractsIds];
305337
+ } else {
305338
+ debugLogger.log("[StateSnapshotAsyncProcessor] No previous snapshot found in Inbox or Graph. Initializing new Master State baseline in background.");
305339
+ }
305340
+ }
305341
+ }
305342
+ if (previousStateJson) {
305343
+ const summaryIdx = nodesToSummarize.findIndex((n3) => n3.type === NodeType.SNAPSHOT && n3.payload.text === previousStateJson);
305344
+ if (summaryIdx !== -1) {
305345
+ nodesToSummarize.splice(summaryIdx, 1);
304713
305346
  }
304714
305347
  }
304715
- const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, options.systemInstruction);
305348
+ if (nodesToSummarize.length === 0)
305349
+ return;
305350
+ const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, previousStateJson, {
305351
+ maxSummaryTurns: options.maxSummaryTurns,
305352
+ maxStateTokens: options.maxStateTokens
305353
+ });
304716
305354
  const newConsumedIds = [
304717
305355
  ...previousConsumedIds,
304718
305356
  ...targets.map((t2) => t2.id)
@@ -304789,7 +305427,9 @@ var generalistProfile = {
304789
305427
  triggers: ["gc_backstop"],
304790
305428
  processors: [
304791
305429
  createStateSnapshotProcessor("StateSnapshotSync", env2, resolveProcessorOptions(config2, "StateSnapshotSync", {
304792
- target: "max"
305430
+ target: "max",
305431
+ maxStateTokens: 4e3,
305432
+ maxSummaryTurns: 5
304793
305433
  }))
304794
305434
  ]
304795
305435
  }
@@ -304801,7 +305441,9 @@ var generalistProfile = {
304801
305441
  triggers: ["nodes_aged_out"],
304802
305442
  processors: [
304803
305443
  createStateSnapshotAsyncProcessor("StateSnapshotAsync", env2, resolveProcessorOptions(config2, "StateSnapshotAsync", {
304804
- type: "accumulate"
305444
+ type: "accumulate",
305445
+ maxStateTokens: 4e3,
305446
+ maxSummaryTurns: 5
304805
305447
  }))
304806
305448
  ]
304807
305449
  }
@@ -304997,6 +305639,12 @@ var ContextTracer = class {
304997
305639
  // packages/core/dist/src/context/eventBus.js
304998
305640
  import { EventEmitter as EventEmitter4 } from "node:events";
304999
305641
  var ContextEventBus = class extends EventEmitter4 {
305642
+ emitTokenGroundTruth(event) {
305643
+ this.emit("TOKEN_GROUND_TRUTH", event);
305644
+ }
305645
+ onTokenGroundTruth(listener) {
305646
+ this.on("TOKEN_GROUND_TRUTH", listener);
305647
+ }
305000
305648
  emitPristineHistoryUpdated(event) {
305001
305649
  this.emit("PRISTINE_HISTORY_UPDATED", event);
305002
305650
  }
@@ -305023,149 +305671,6 @@ var ContextEventBus = class extends EventEmitter4 {
305023
305671
  }
305024
305672
  };
305025
305673
 
305026
- // packages/core/dist/src/context/utils/contextTokenCalculator.js
305027
- var ContextTokenCalculator = class {
305028
- charsPerToken;
305029
- registry;
305030
- tokenCache = /* @__PURE__ */ new Map();
305031
- constructor(charsPerToken, registry2) {
305032
- this.charsPerToken = charsPerToken;
305033
- this.registry = registry2;
305034
- }
305035
- /**
305036
- * Estimates tokens for a simple string based on character count.
305037
- * Fast, but inherently inaccurate compared to real model tokenization.
305038
- */
305039
- estimateTokensForString(text) {
305040
- return Math.ceil(text.length / this.charsPerToken);
305041
- }
305042
- /**
305043
- * Fast, simple heuristic conversion from tokens to expected character length.
305044
- * Useful for calculating truncation thresholds.
305045
- */
305046
- tokensToChars(tokens) {
305047
- return tokens * this.charsPerToken;
305048
- }
305049
- /**
305050
- * Pre-calculates and caches the token cost of a newly minted node.
305051
- * Because nodes are immutable, this cost never changes for this node ID.
305052
- */
305053
- /**
305054
- * Removes cached token counts for any nodes that are no longer in the given live set.
305055
- * This prevents unbounded memory growth during long sessions.
305056
- */
305057
- garbageCollectCache(liveNodeIds) {
305058
- for (const [id] of this.tokenCache) {
305059
- if (!liveNodeIds.has(id)) {
305060
- this.tokenCache.delete(id);
305061
- }
305062
- }
305063
- }
305064
- cacheNodeTokens(node) {
305065
- const behavior = this.registry.get(node.type);
305066
- const parts2 = behavior.getEstimatableParts(node);
305067
- const tokens = this.estimateTokensForParts(parts2);
305068
- this.tokenCache.set(node.id, tokens);
305069
- return tokens;
305070
- }
305071
- /**
305072
- * Retrieves the token cost of a single node from the cache.
305073
- * If it misses the cache, it computes it and caches it.
305074
- */
305075
- getTokenCost(node) {
305076
- const cached2 = this.tokenCache.get(node.id);
305077
- if (cached2 !== void 0)
305078
- return cached2;
305079
- return this.cacheNodeTokens(node);
305080
- }
305081
- /**
305082
- * Calculates a detailed breakdown of tokens by category for a list of nodes.
305083
- * Useful for calibration tracing and debugging overestimation.
305084
- */
305085
- calculateTokenBreakdown(nodes) {
305086
- const breakdown = { total: 0, text: 0, media: 0, tool: 0, overhead: 0 };
305087
- const seenIds = /* @__PURE__ */ new Set();
305088
- const seenTurnIds = /* @__PURE__ */ new Set();
305089
- for (const node of nodes) {
305090
- if (seenIds.has(node.id))
305091
- continue;
305092
- seenIds.add(node.id);
305093
- if (node.turnId) {
305094
- if (!seenTurnIds.has(node.turnId)) {
305095
- seenTurnIds.add(node.turnId);
305096
- breakdown.overhead += MSG_OVERHEAD_TOKENS;
305097
- breakdown.total += MSG_OVERHEAD_TOKENS;
305098
- }
305099
- }
305100
- const cost = this.getTokenCost(node);
305101
- breakdown.total += cost;
305102
- const behavior = this.registry.get(node.type);
305103
- const parts2 = behavior.getEstimatableParts(node);
305104
- for (const part of parts2) {
305105
- if (typeof part.text === "string") {
305106
- breakdown.text += estimateTokenCountSync([part], 0, this.charsPerToken);
305107
- } else if (part.inlineData?.mimeType?.startsWith("image/") || part.fileData?.mimeType?.startsWith("image/")) {
305108
- breakdown.media += estimateTokenCountSync([part], 0, this.charsPerToken);
305109
- } else if (part.functionCall || part.functionResponse) {
305110
- breakdown.tool += estimateTokenCountSync([part], 0, this.charsPerToken);
305111
- } else {
305112
- breakdown.overhead += estimateTokenCountSync([part], 0, this.charsPerToken);
305113
- }
305114
- }
305115
- }
305116
- return breakdown;
305117
- }
305118
- /**
305119
- * Fast calculation for a flat array of ConcreteNodes (The Nodes).
305120
- * It relies entirely on the O(1) sidecar token cache.
305121
- */
305122
- calculateConcreteListTokens(nodes) {
305123
- let tokens = 0;
305124
- const seenIds = /* @__PURE__ */ new Set();
305125
- const seenTurnIds = /* @__PURE__ */ new Set();
305126
- for (const node of nodes) {
305127
- if (!seenIds.has(node.id)) {
305128
- seenIds.add(node.id);
305129
- tokens += this.getTokenCost(node);
305130
- if (node.turnId) {
305131
- if (!seenTurnIds.has(node.turnId)) {
305132
- seenTurnIds.add(node.turnId);
305133
- tokens += MSG_OVERHEAD_TOKENS;
305134
- }
305135
- }
305136
- }
305137
- }
305138
- return tokens;
305139
- }
305140
- /**
305141
- * Calculates the token cost for a single Gemini Content object.
305142
- */
305143
- calculateContentTokens(content) {
305144
- return this.estimateTokensForParts(content.parts || []) + MSG_OVERHEAD_TOKENS;
305145
- }
305146
- /**
305147
- * Slower, precise estimation for a Gemini Content/Part graph.
305148
- * Deeply inspects the nested structure and uses the base tokenization math.
305149
- */
305150
- partTokenCache = /* @__PURE__ */ new WeakMap();
305151
- estimateTokensForParts(parts2) {
305152
- let total = 0;
305153
- for (const part of parts2) {
305154
- if (part !== null && typeof part === "object") {
305155
- let cost = this.partTokenCache.get(part);
305156
- if (cost === void 0) {
305157
- cost = estimateTokenCountSync([part], 0, this.charsPerToken);
305158
- this.partTokenCache.set(part, cost);
305159
- }
305160
- total += cost;
305161
- } else {
305162
- total += estimateTokenCountSync([part], 0, this.charsPerToken);
305163
- }
305164
- }
305165
- return total;
305166
- }
305167
- };
305168
-
305169
305674
  // packages/core/dist/src/context/pipeline/inbox.js
305170
305675
  import { randomUUID as randomUUID11 } from "node:crypto";
305171
305676
  var LiveInbox = class {
@@ -305203,81 +305708,6 @@ var InboxSnapshotImpl = class {
305203
305708
  }
305204
305709
  };
305205
305710
 
305206
- // packages/core/dist/src/context/graph/behaviorRegistry.js
305207
- var NodeBehaviorRegistry = class {
305208
- behaviors = /* @__PURE__ */ new Map();
305209
- register(behavior) {
305210
- this.behaviors.set(behavior.type, behavior);
305211
- }
305212
- get(type2) {
305213
- const behavior = this.behaviors.get(type2);
305214
- if (!behavior) {
305215
- throw new Error(`Unregistered Node type: ${type2}`);
305216
- }
305217
- return behavior;
305218
- }
305219
- };
305220
-
305221
- // packages/core/dist/src/context/graph/builtinBehaviors.js
305222
- var UserPromptBehavior = {
305223
- type: NodeType.USER_PROMPT,
305224
- getEstimatableParts(node) {
305225
- return [node.payload];
305226
- }
305227
- };
305228
- var AgentThoughtBehavior = {
305229
- type: NodeType.AGENT_THOUGHT,
305230
- getEstimatableParts(node) {
305231
- return [node.payload];
305232
- }
305233
- };
305234
- var ToolExecutionBehavior = {
305235
- type: NodeType.TOOL_EXECUTION,
305236
- getEstimatableParts(node) {
305237
- return [node.payload];
305238
- }
305239
- };
305240
- var MaskedToolBehavior = {
305241
- type: NodeType.MASKED_TOOL,
305242
- getEstimatableParts(node) {
305243
- return [node.payload];
305244
- }
305245
- };
305246
- var AgentYieldBehavior = {
305247
- type: NodeType.AGENT_YIELD,
305248
- getEstimatableParts() {
305249
- return [];
305250
- }
305251
- };
305252
- var SystemEventBehavior = {
305253
- type: NodeType.SYSTEM_EVENT,
305254
- getEstimatableParts(node) {
305255
- return [node.payload];
305256
- }
305257
- };
305258
- var SnapshotBehavior = {
305259
- type: NodeType.SNAPSHOT,
305260
- getEstimatableParts(node) {
305261
- return [node.payload];
305262
- }
305263
- };
305264
- var RollingSummaryBehavior = {
305265
- type: NodeType.ROLLING_SUMMARY,
305266
- getEstimatableParts(node) {
305267
- return [node.payload];
305268
- }
305269
- };
305270
- function registerBuiltInBehaviors(registry2) {
305271
- registry2.register(UserPromptBehavior);
305272
- registry2.register(AgentThoughtBehavior);
305273
- registry2.register(ToolExecutionBehavior);
305274
- registry2.register(MaskedToolBehavior);
305275
- registry2.register(AgentYieldBehavior);
305276
- registry2.register(SystemEventBehavior);
305277
- registry2.register(SnapshotBehavior);
305278
- registry2.register(RollingSummaryBehavior);
305279
- }
305280
-
305281
305711
  // packages/core/dist/src/context/graph/toGraph.js
305282
305712
  import { randomUUID as randomUUID12, createHash as createHash7 } from "node:crypto";
305283
305713
  var PART_HASH_CACHE = /* @__PURE__ */ new WeakMap();
@@ -305347,9 +305777,9 @@ var ContextGraphBuilder = class {
305347
305777
  const msg = history[turnIdx];
305348
305778
  if (!msg.parts)
305349
305779
  continue;
305350
- if (turnIdx === 0 && msg.role === "user" && msg.parts.length === 1) {
305780
+ if (msg.role === "user" && msg.parts.length === 1) {
305351
305781
  const text = msg.parts[0].text;
305352
- if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI.")) {
305782
+ if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI")) {
305353
305783
  debugLogger.log("[ContextGraphBuilder] Skipping legacy environment header turn from graph.");
305354
305784
  continue;
305355
305785
  }
@@ -305449,10 +305879,11 @@ var ContextEnvironmentImpl = class {
305449
305879
  charsPerToken;
305450
305880
  eventBus;
305451
305881
  tokenCalculator;
305452
- inbox;
305453
305882
  behaviorRegistry;
305883
+ renderOptions;
305884
+ inbox;
305454
305885
  graphMapper;
305455
- constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus) {
305886
+ constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus, tokenCalculator, behaviorRegistry, renderOptions) {
305456
305887
  this.llmClientProvider = llmClientProvider;
305457
305888
  this.sessionId = sessionId;
305458
305889
  this.promptId = promptId;
@@ -305461,9 +305892,9 @@ var ContextEnvironmentImpl = class {
305461
305892
  this.tracer = tracer;
305462
305893
  this.charsPerToken = charsPerToken;
305463
305894
  this.eventBus = eventBus;
305464
- this.behaviorRegistry = new NodeBehaviorRegistry();
305465
- registerBuiltInBehaviors(this.behaviorRegistry);
305466
- this.tokenCalculator = new ContextTokenCalculator(this.charsPerToken, this.behaviorRegistry);
305895
+ this.tokenCalculator = tokenCalculator;
305896
+ this.behaviorRegistry = behaviorRegistry;
305897
+ this.renderOptions = renderOptions;
305467
305898
  this.inbox = new LiveInbox();
305468
305899
  this.graphMapper = new ContextGraphMapper();
305469
305900
  }
@@ -305501,30 +305932,6 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305501
305932
  }
305502
305933
  return new _ContextWorkingBufferImpl(pristineNodes, pristineMap, initialProvenance, []);
305503
305934
  }
305504
- /**
305505
- * Appends newly observed pristine nodes (e.g. from a user message) to the working buffer.
305506
- * Ensures they are tracked in the pristine map and point to themselves in provenance.
305507
- */
305508
- appendPristineNodes(newNodes) {
305509
- if (newNodes.length === 0)
305510
- return this;
305511
- const newPristineMap = new Map(this.pristineNodesMap);
305512
- const newProvenanceMap = new Map(this.provenanceMap);
305513
- const existingIds = new Set(this.nodes.map((n3) => n3.id));
305514
- const nodesToAdd = [];
305515
- const batchIds = /* @__PURE__ */ new Set();
305516
- for (const node of newNodes) {
305517
- if (!existingIds.has(node.id) && !batchIds.has(node.id)) {
305518
- newPristineMap.set(node.id, node);
305519
- newProvenanceMap.set(node.id, /* @__PURE__ */ new Set([node.id]));
305520
- nodesToAdd.push(node);
305521
- batchIds.add(node.id);
305522
- }
305523
- }
305524
- if (nodesToAdd.length === 0)
305525
- return this;
305526
- return new _ContextWorkingBufferImpl([...this.nodes, ...nodesToAdd], newPristineMap, newProvenanceMap, [...this.history]);
305527
- }
305528
305935
  /**
305529
305936
  * Generates an entirely new buffer instance by calculating the delta between the processor's input and output.
305530
305937
  */
@@ -305602,10 +306009,90 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305602
306009
  finalPristineMap = prunedPristineMap;
305603
306010
  return new _ContextWorkingBufferImpl(newGraph, finalPristineMap, newProvenanceMap, [...this.history, mutation]);
305604
306011
  }
305605
- /** Removes nodes from the working buffer that were completely dropped from the upstream pristine history */
305606
- prunePristineNodes(retainedIds) {
305607
- const newGraph = this.nodes.filter((n3) => retainedIds.has(n3.id) || !this.pristineNodesMap.has(n3.id));
306012
+ /**
306013
+ * Rebuilds the working buffer in the exact chronological order of the authoritative pristine history,
306014
+ * while preserving injected/summarized nodes at their relative positions.
306015
+ */
306016
+ syncPristineHistory(authoritativePristineNodes) {
306017
+ const newPristineMap = new Map(this.pristineNodesMap);
305608
306018
  const newProvenanceMap = new Map(this.provenanceMap);
306019
+ const authoritativeIds = new Set(authoritativePristineNodes.map((n3) => n3.id));
306020
+ for (const node of authoritativePristineNodes) {
306021
+ if (!newPristineMap.has(node.id)) {
306022
+ newPristineMap.set(node.id, node);
306023
+ newProvenanceMap.set(node.id, /* @__PURE__ */ new Set([node.id]));
306024
+ }
306025
+ }
306026
+ const survivingCurrentNodes = this.nodes.filter((n3) => {
306027
+ if (authoritativeIds.has(n3.id))
306028
+ return true;
306029
+ if (!this.pristineNodesMap.has(n3.id))
306030
+ return true;
306031
+ const roots = newProvenanceMap.get(n3.id);
306032
+ return !roots || roots.size === 0;
306033
+ }).filter((n3) => {
306034
+ if (!authoritativeIds.has(n3.id) && !this.pristineNodesMap.has(n3.id)) {
306035
+ const roots = newProvenanceMap.get(n3.id);
306036
+ if (roots && roots.size > 0) {
306037
+ for (const root of roots) {
306038
+ if (!authoritativeIds.has(root)) {
306039
+ return false;
306040
+ }
306041
+ }
306042
+ }
306043
+ }
306044
+ return true;
306045
+ });
306046
+ const coveredPristineIds = /* @__PURE__ */ new Set();
306047
+ for (const node of survivingCurrentNodes) {
306048
+ if (!authoritativeIds.has(node.id)) {
306049
+ const roots = newProvenanceMap.get(node.id);
306050
+ if (roots) {
306051
+ for (const root of roots) {
306052
+ coveredPristineIds.add(root);
306053
+ }
306054
+ }
306055
+ }
306056
+ }
306057
+ const pristineIndexMap = new Map(authoritativePristineNodes.map((n3, idx) => [n3.id, idx]));
306058
+ const getPristineIndex = (nodeId) => {
306059
+ const roots = newProvenanceMap.get(nodeId);
306060
+ if (!roots || roots.size === 0)
306061
+ return -1;
306062
+ let maxIndex = -1;
306063
+ for (const root of roots) {
306064
+ const idx = pristineIndexMap.get(root);
306065
+ if (idx !== void 0 && idx > maxIndex) {
306066
+ maxIndex = idx;
306067
+ }
306068
+ }
306069
+ return maxIndex;
306070
+ };
306071
+ const nodeOrder = new Array();
306072
+ for (let i3 = 0; i3 < authoritativePristineNodes.length; i3++) {
306073
+ const node = authoritativePristineNodes[i3];
306074
+ if (!coveredPristineIds.has(node.id)) {
306075
+ nodeOrder.push({ node, sortKey: i3, originalIndex: -1 });
306076
+ }
306077
+ }
306078
+ for (let i3 = 0; i3 < survivingCurrentNodes.length; i3++) {
306079
+ const node = survivingCurrentNodes[i3];
306080
+ if (!authoritativeIds.has(node.id)) {
306081
+ const baseSortKey = getPristineIndex(node.id);
306082
+ nodeOrder.push({
306083
+ node,
306084
+ sortKey: baseSortKey === -1 ? -1 : baseSortKey + 0.5,
306085
+ // Interleave after pristine roots, or at start if injected
306086
+ originalIndex: i3
306087
+ });
306088
+ }
306089
+ }
306090
+ nodeOrder.sort((a2, b) => {
306091
+ if (a2.sortKey !== b.sortKey)
306092
+ return a2.sortKey - b.sortKey;
306093
+ return a2.originalIndex - b.originalIndex;
306094
+ });
306095
+ const newGraph = nodeOrder.map((item) => item.node);
305609
306096
  const reachablePristineIds = /* @__PURE__ */ new Set();
305610
306097
  const reachableCurrentIds = /* @__PURE__ */ new Set();
305611
306098
  for (const node of newGraph) {
@@ -305613,7 +306100,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305613
306100
  const roots = newProvenanceMap.get(node.id);
305614
306101
  if (roots) {
305615
306102
  for (const root of roots) {
305616
- if (retainedIds.has(root) || !this.pristineNodesMap.has(root)) {
306103
+ if (authoritativeIds.has(root) || !this.pristineNodesMap.has(root)) {
305617
306104
  reachablePristineIds.add(root);
305618
306105
  }
305619
306106
  }
@@ -305626,7 +306113,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305626
306113
  }
305627
306114
  const prunedPristineMap = /* @__PURE__ */ new Map();
305628
306115
  for (const id of reachablePristineIds) {
305629
- const node = this.pristineNodesMap.get(id);
306116
+ const node = newPristineMap.get(id);
305630
306117
  if (node)
305631
306118
  prunedPristineMap.set(id, node);
305632
306119
  }
@@ -305653,6 +306140,7 @@ var PipelineOrchestrator = class {
305653
306140
  activeTimers = [];
305654
306141
  pendingPipelines = /* @__PURE__ */ new Map();
305655
306142
  pipelineMutex = /* @__PURE__ */ new Map();
306143
+ pipelineScheduled = /* @__PURE__ */ new Set();
305656
306144
  nodeProvider;
305657
306145
  constructor(pipelines, asyncPipelines, env2, eventBus, tracer) {
305658
306146
  this.pipelines = pipelines;
@@ -305693,25 +306181,37 @@ var PipelineOrchestrator = class {
305693
306181
  this.activeTimers.push(timer);
305694
306182
  } else if (trigger === "retained_exceeded" || trigger === "nodes_aged_out") {
305695
306183
  this.eventBus.onConsolidationNeeded((event) => {
305696
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
306184
+ void executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
305697
306185
  });
305698
306186
  } else if (trigger === "new_message" || trigger === "nodes_added") {
305699
306187
  this.eventBus.onChunkReceived((event) => {
305700
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
306188
+ void executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
305701
306189
  });
305702
306190
  }
305703
306191
  }
305704
306192
  }
305705
306193
  };
305706
- bindTriggers(this.pipelines, (pipeline, nodes, targets, protectedIds) => {
306194
+ const handleSyncExecution = async (pipeline, nodes, targets, protectedIds) => {
306195
+ if (this.pipelineScheduled.has(pipeline.name)) {
306196
+ debugLogger.log(`[Orchestrator] Pipeline ${pipeline.name} already scheduled (sync), dropping.`);
306197
+ return;
306198
+ }
306199
+ this.pipelineScheduled.add(pipeline.name);
305707
306200
  const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
305708
306201
  const nextPromise = (async () => {
305709
306202
  try {
305710
306203
  await existing;
305711
- const latestNodes = this.nodeProvider();
306204
+ this.pipelineScheduled.delete(pipeline.name);
306205
+ const latestNodes = this.nodeProvider ? this.nodeProvider() : nodes;
306206
+ const latestTargets = latestNodes.filter((n3) => targets.has(n3.id));
306207
+ debugLogger.log(`[Orchestrator] Executing sync pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`);
306208
+ if (latestTargets.length === 0) {
306209
+ debugLogger.log(`[Orchestrator] No latest targets for sync pipeline ${pipeline.name}, returning.`);
306210
+ return;
306211
+ }
305712
306212
  await this.executePipelineAsync(pipeline, latestNodes, new Set(targets), new Set(protectedIds));
305713
306213
  } catch (e2) {
305714
- debugLogger.error(`Pipeline chain ${pipeline.name} failed:`, e2);
306214
+ debugLogger.error(`Sync pipeline chain ${pipeline.name} failed:`, e2);
305715
306215
  }
305716
306216
  })();
305717
306217
  this.pipelineMutex.set(pipeline.name, nextPromise);
@@ -305723,18 +306223,47 @@ var PipelineOrchestrator = class {
305723
306223
  this.pipelineMutex.delete(pipeline.name);
305724
306224
  }
305725
306225
  });
305726
- });
305727
- bindTriggers(this.asyncPipelines, (pipeline, nodes, targetIds) => {
305728
- const inboxSnapshot = new InboxSnapshotImpl(this.env.inbox.getMessages() || []);
305729
- const targets = nodes.filter((n3) => targetIds.has(n3.id));
305730
- for (const processor of pipeline.processors) {
305731
- processor.process({
305732
- targets,
305733
- inbox: inboxSnapshot,
305734
- buffer: ContextWorkingBufferImpl.initialize(nodes)
305735
- }).catch((e2) => debugLogger.error(`AsyncProcessor ${processor.name} failed:`, e2));
306226
+ };
306227
+ const handleAsyncExecution = async (pipeline, nodes, targets) => {
306228
+ if (this.pipelineScheduled.has(pipeline.name)) {
306229
+ debugLogger.log(`[Orchestrator] Pipeline ${pipeline.name} already scheduled (async), dropping.`);
306230
+ return;
305736
306231
  }
305737
- });
306232
+ this.pipelineScheduled.add(pipeline.name);
306233
+ const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
306234
+ const nextPromise = (async () => {
306235
+ try {
306236
+ await existing;
306237
+ this.pipelineScheduled.delete(pipeline.name);
306238
+ const latestNodes = this.nodeProvider ? this.nodeProvider() : nodes;
306239
+ const latestTargets = latestNodes.filter((n3) => targets.has(n3.id));
306240
+ debugLogger.log(`[Orchestrator] Executing async pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`);
306241
+ const inboxSnapshot = new InboxSnapshotImpl(this.env.inbox.getMessages() || []);
306242
+ for (const processor of pipeline.processors) {
306243
+ debugLogger.log(`[Orchestrator] Running async processor ${processor.id}`);
306244
+ await processor.process({
306245
+ targets: latestTargets,
306246
+ inbox: inboxSnapshot,
306247
+ buffer: ContextWorkingBufferImpl.initialize(latestNodes)
306248
+ });
306249
+ }
306250
+ this.env.inbox.drainConsumed(inboxSnapshot.getConsumedIds());
306251
+ } catch (e2) {
306252
+ debugLogger.error(`Async pipeline chain ${pipeline.name} failed:`, e2);
306253
+ }
306254
+ })();
306255
+ this.pipelineMutex.set(pipeline.name, nextPromise);
306256
+ const pipelineId = `${pipeline.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
306257
+ this.pendingPipelines.set(pipelineId, nextPromise);
306258
+ void nextPromise.finally(() => {
306259
+ this.pendingPipelines.delete(pipelineId);
306260
+ if (this.pipelineMutex.get(pipeline.name) === nextPromise) {
306261
+ this.pipelineMutex.delete(pipeline.name);
306262
+ }
306263
+ });
306264
+ };
306265
+ bindTriggers(this.pipelines, (pipeline, nodes, targets, protectedIds) => handleSyncExecution(pipeline, nodes, targets, protectedIds));
306266
+ bindTriggers(this.asyncPipelines, (pipeline, nodes, targets) => handleAsyncExecution(pipeline, nodes, targets));
305738
306267
  }
305739
306268
  shutdown() {
305740
306269
  for (const timer of this.activeTimers) {
@@ -305889,17 +306418,54 @@ var HistoryObserver = class {
305889
306418
  }
305890
306419
  };
305891
306420
 
306421
+ // packages/core/dist/src/context/utils/tokenCalibration.js
306422
+ function performCalibration(env2, finalNodes, finalContents) {
306423
+ if (!env2.renderOptions?.calibrateTokenCalculation) {
306424
+ return;
306425
+ }
306426
+ void (async () => {
306427
+ try {
306428
+ const exactResp = await env2.llmClient.countTokens({
306429
+ contents: finalContents
306430
+ });
306431
+ const exactTokens = typeof exactResp.totalTokens === "number" ? exactResp.totalTokens : 0;
306432
+ const estimatedTokens = env2.tokenCalculator.calculateConcreteListTokens(finalNodes);
306433
+ const delta = Math.abs(exactTokens - estimatedTokens);
306434
+ const tolerance = Math.max(exactTokens, estimatedTokens) * 0.2;
306435
+ env2.tracer.logEvent("Render", "Token Calibration Measurement", {
306436
+ exactTokens,
306437
+ estimatedTokens,
306438
+ delta,
306439
+ isWithinTolerance: delta <= tolerance
306440
+ });
306441
+ if (delta > tolerance) {
306442
+ debugLogger.error(`[Token Calibration] Large deviation detected: exact ${exactTokens} vs estimated ${estimatedTokens} (delta: ${delta})`);
306443
+ }
306444
+ } catch {
306445
+ }
306446
+ })();
306447
+ }
306448
+
305892
306449
  // packages/core/dist/src/context/graph/render.js
305893
- async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionReasons = /* @__PURE__ */ new Map(), headerTokens = 0) {
306450
+ async function render2(nodes, orchestrator, sidecar, tracer, env2, advancedTokenCalculator, protectionReasons = /* @__PURE__ */ new Map(), header, previewNodeIds = /* @__PURE__ */ new Set()) {
306451
+ let headerTokens = 0;
306452
+ let headerBaseUnits = 0;
306453
+ if (header) {
306454
+ const costs = advancedTokenCalculator.calculateContentTokensAndBaseUnits(header);
306455
+ headerTokens = costs.tokens;
306456
+ headerBaseUnits = costs.baseUnits;
306457
+ }
305894
306458
  if (!sidecar.config.budget) {
305895
- const contents2 = env2.graphMapper.fromGraph(nodes);
306459
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
306460
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
305896
306461
  tracer.logEvent("Render", "Render Context to LLM (No Budget)", {
305897
306462
  renderedContext: contents2
305898
306463
  });
305899
- return { history: contents2, didApplyManagement: false };
306464
+ const baseUnits = advancedTokenCalculator.getRawBaseUnits(nodes) + headerBaseUnits;
306465
+ return { history: contents2, didApplyManagement: false, baseUnits };
305900
306466
  }
305901
306467
  const maxTokens = sidecar.config.budget.maxTokens;
305902
- const graphTokens = env2.tokenCalculator.calculateConcreteListTokens(nodes);
306468
+ const { tokens: graphTokens, baseUnits: graphBaseUnits } = advancedTokenCalculator.calculateTokensAndBaseUnits(nodes);
305903
306469
  const currentTokens = graphTokens + headerTokens;
305904
306470
  const protectedIds = new Set(protectionReasons.keys());
305905
306471
  tracer.logEvent("Render", "Budget Audit", {
@@ -305919,11 +306485,17 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305919
306485
  });
305920
306486
  if (currentTokens <= maxTokens) {
305921
306487
  tracer.logEvent("Render", `View is within maxTokens (${currentTokens} <= ${maxTokens}). Returning view.`);
305922
- const contents2 = env2.graphMapper.fromGraph(nodes);
306488
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
306489
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
305923
306490
  tracer.logEvent("Render", "Render Context for LLM", {
305924
306491
  renderedContext: contents2
305925
306492
  });
305926
- return { history: contents2, didApplyManagement: false };
306493
+ performCalibration(env2, visibleNodes2, contents2);
306494
+ return {
306495
+ history: contents2,
306496
+ didApplyManagement: false,
306497
+ baseUnits: graphBaseUnits + headerBaseUnits
306498
+ };
305927
306499
  }
305928
306500
  const targetDelta = currentTokens - sidecar.config.budget.retainedTokens;
305929
306501
  tracer.logEvent("Render", `View exceeds maxTokens (${currentTokens} > ${maxTokens}). Hitting Synchronous Pressure Barrier.`, { targetDelta });
@@ -305931,9 +306503,10 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305931
306503
  let rollingTokens = 0;
305932
306504
  for (let i3 = nodes.length - 1; i3 >= 0; i3--) {
305933
306505
  const node = nodes[i3];
306506
+ const priorTokens = rollingTokens;
305934
306507
  const nodeTokens = env2.tokenCalculator.calculateConcreteListTokens([node]);
305935
306508
  rollingTokens += nodeTokens;
305936
- if (rollingTokens > sidecar.config.budget.retainedTokens) {
306509
+ if (priorTokens > sidecar.config.budget.retainedTokens) {
305937
306510
  agedOutNodes.add(node.id);
305938
306511
  }
305939
306512
  }
@@ -305945,12 +306518,17 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305945
306518
  skipList.add(id);
305946
306519
  }
305947
306520
  }
305948
- const visibleNodes = processedNodes.filter((n3) => !skipList.has(n3.id));
306521
+ const visibleNodes = processedNodes.filter((n3) => !skipList.has(n3.id) && !previewNodeIds.has(n3.id));
305949
306522
  const contents = env2.graphMapper.fromGraph(visibleNodes);
305950
306523
  tracer.logEvent("Render", "Render Sanitized Context for LLM", {
305951
306524
  renderedContextSanitized: contents
305952
306525
  });
305953
- return { history: contents, didApplyManagement: true };
306526
+ performCalibration(env2, visibleNodes, contents);
306527
+ return {
306528
+ history: contents,
306529
+ didApplyManagement: true,
306530
+ baseUnits: advancedTokenCalculator.getRawBaseUnits(visibleNodes) + headerBaseUnits
306531
+ };
305954
306532
  }
305955
306533
 
305956
306534
  // packages/core/dist/src/context/utils/invariantChecker.js
@@ -305983,6 +306561,7 @@ var ContextManager = class {
305983
306561
  sidecar;
305984
306562
  env;
305985
306563
  tracer;
306564
+ advancedTokenCalculator;
305986
306565
  headerProvider;
305987
306566
  // The master state containing the pristine graph and current active graph.
305988
306567
  buffer = ContextWorkingBufferImpl.initialize([]);
@@ -305990,24 +306569,23 @@ var ContextManager = class {
305990
306569
  // Internal sub-components
305991
306570
  orchestrator;
305992
306571
  historyObserver;
306572
+ // Hysteresis tracking to prevent utility call churn
306573
+ lastTriggeredDeficit = 0;
305993
306574
  // Cache for Anomaly 3 (Redundant Renders)
305994
306575
  lastRenderCache;
305995
- constructor(sidecar, env2, tracer, orchestrator, chatHistory, headerProvider) {
306576
+ hasPerformedHotStart = false;
306577
+ constructor(sidecar, env2, tracer, orchestrator, chatHistory, advancedTokenCalculator, headerProvider) {
305996
306578
  this.sidecar = sidecar;
305997
306579
  this.env = env2;
305998
306580
  this.tracer = tracer;
306581
+ this.advancedTokenCalculator = advancedTokenCalculator;
305999
306582
  this.headerProvider = headerProvider;
306000
306583
  this.eventBus = env2.eventBus;
306001
306584
  this.orchestrator = orchestrator;
306002
306585
  this.orchestrator.setNodeProvider(() => this.buffer.nodes);
306003
306586
  this.historyObserver = new HistoryObserver(chatHistory, this.env.eventBus, this.tracer, this.env.graphMapper);
306004
306587
  this.eventBus.onPristineHistoryUpdated((event) => {
306005
- const newIds = new Set(event.nodes.map((n3) => n3.id));
306006
- const addedNodes = event.nodes.filter((n3) => event.newNodes.has(n3.id));
306007
- this.buffer = this.buffer.prunePristineNodes(newIds);
306008
- if (addedNodes.length > 0) {
306009
- this.buffer = this.buffer.appendPristineNodes(addedNodes);
306010
- }
306588
+ this.buffer = this.buffer.syncPristineHistory(event.nodes);
306011
306589
  this.evaluateTriggers(event.newNodes);
306012
306590
  });
306013
306591
  this.eventBus.onProcessorResult((event) => {
@@ -306051,10 +306629,11 @@ var ContextManager = class {
306051
306629
  }
306052
306630
  for (let i3 = this.buffer.nodes.length - 1; i3 >= 0; i3--) {
306053
306631
  const node = this.buffer.nodes[i3];
306632
+ const priorTokens = rollingTokens;
306054
306633
  rollingTokens += this.env.tokenCalculator.calculateConcreteListTokens([
306055
306634
  node
306056
306635
  ]);
306057
- if (rollingTokens > this.sidecar.config.budget.retainedTokens) {
306636
+ if (priorTokens > this.sidecar.config.budget.retainedTokens) {
306058
306637
  if (!protectedIds.has(node.id)) {
306059
306638
  agedOutNodes.add(node.id);
306060
306639
  }
@@ -306062,8 +306641,13 @@ var ContextManager = class {
306062
306641
  }
306063
306642
  if (agedOutNodes.size > 0) {
306064
306643
  const targetDeficit = currentTokens - this.sidecar.config.budget.retainedTokens;
306644
+ if (targetDeficit < this.lastTriggeredDeficit) {
306645
+ this.lastTriggeredDeficit = targetDeficit;
306646
+ }
306065
306647
  const threshold = this.sidecar.config.budget.coalescingThresholdTokens || 0;
306066
- if (targetDeficit >= threshold) {
306648
+ const growthSinceLast = targetDeficit - this.lastTriggeredDeficit;
306649
+ if (targetDeficit >= threshold && (growthSinceLast >= threshold || this.lastTriggeredDeficit === 0)) {
306650
+ this.lastTriggeredDeficit = targetDeficit;
306067
306651
  this.env.tokenCalculator.garbageCollectCache(new Set(this.buffer.nodes.map((n3) => n3.id)));
306068
306652
  this.eventBus.emitConsolidationNeeded({
306069
306653
  nodes: this.buffer.nodes,
@@ -306071,6 +306655,8 @@ var ContextManager = class {
306071
306655
  targetNodeIds: agedOutNodes
306072
306656
  });
306073
306657
  }
306658
+ } else {
306659
+ this.lastTriggeredDeficit = 0;
306074
306660
  }
306075
306661
  }
306076
306662
  }
@@ -306127,24 +306713,42 @@ var ContextManager = class {
306127
306713
  getNodes() {
306128
306714
  return [...this.buffer.nodes];
306129
306715
  }
306716
+ getEnvironment() {
306717
+ return this.env;
306718
+ }
306130
306719
  /**
306131
306720
  * Executes the final 'gc_backstop' pipeline if necessary, enforcing the token budget,
306132
306721
  * and maps the Episodic Context Graph back into a raw Gemini Content[] array for transmission.
306133
306722
  * This is the primary method called by the agent framework before sending a request.
306134
306723
  */
306135
- async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set()) {
306724
+ async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set(), abortSignal) {
306136
306725
  this.tracer.logEvent("ContextManager", "Starting rendering of LLM context");
306137
- await this.orchestrator.waitForPipelines();
306138
- let nodes = this.buffer.nodes;
306726
+ let previewNodes = [];
306139
306727
  if (pendingRequest) {
306140
- const previewNodes = this.env.graphMapper.applyEvent({
306728
+ previewNodes = this.env.graphMapper.applyEvent({
306141
306729
  type: "PUSH",
306142
306730
  payload: [pendingRequest]
306143
306731
  });
306732
+ }
306733
+ const hotStartPromise = (async () => {
306734
+ if (!this.hasPerformedHotStart) {
306735
+ this.hasPerformedHotStart = true;
306736
+ if (this.buffer.nodes.length > 0) {
306737
+ const nodesForHotStart = [...this.buffer.nodes, ...previewNodes];
306738
+ await this.performHotStartCalibration(nodesForHotStart, abortSignal);
306739
+ }
306740
+ }
306741
+ })();
306742
+ await Promise.all([this.orchestrator.waitForPipelines(), hotStartPromise]);
306743
+ let nodes = this.buffer.nodes;
306744
+ const previewNodeIds = /* @__PURE__ */ new Set();
306745
+ if (previewNodes.length > 0) {
306746
+ for (const n3 of previewNodes) {
306747
+ previewNodeIds.add(n3.id);
306748
+ }
306144
306749
  nodes = [...nodes, ...previewNodes];
306145
306750
  }
306146
306751
  const header = this.headerProvider ? await this.headerProvider() : void 0;
306147
- const headerTokens = header ? this.env.tokenCalculator.calculateContentTokens(header) : 0;
306148
306752
  const graphHash = nodes.map((n3) => n3.id).join("|");
306149
306753
  const headerHash = header ? JSON.stringify(header.parts) : "no-header";
306150
306754
  const totalHash = `${graphHash}::${headerHash}`;
@@ -306153,7 +306757,7 @@ var ContextManager = class {
306153
306757
  return this.lastRenderCache.result;
306154
306758
  }
306155
306759
  const protectionReasons = this.getProtectedNodeIds(nodes, activeTaskIds);
306156
- const { history: renderedHistory, didApplyManagement } = await render2(nodes, this.orchestrator, this.sidecar, this.tracer, this.env, protectionReasons, headerTokens);
306760
+ const { history: renderedHistory, didApplyManagement, baseUnits } = await render2(nodes, this.orchestrator, this.sidecar, this.tracer, this.env, this.advancedTokenCalculator, protectionReasons, header, previewNodeIds);
306157
306761
  checkContextInvariants(this.buffer.nodes, "RenderHistory");
306158
306762
  this.tracer.logEvent("ContextManager", "Finished rendering");
306159
306763
  const combinedHistory = header ? [header, ...renderedHistory] : renderedHistory;
@@ -306161,11 +306765,35 @@ var ContextManager = class {
306161
306765
  history: hardenHistory(combinedHistory, {
306162
306766
  sentinels: this.sidecar.sentinels
306163
306767
  }),
306164
- didApplyManagement
306768
+ didApplyManagement,
306769
+ baseUnits
306165
306770
  };
306166
306771
  this.lastRenderCache = { nodesHash: totalHash, result: result2 };
306167
306772
  return result2;
306168
306773
  }
306774
+ async performHotStartCalibration(nodes, abortSignal) {
306775
+ try {
306776
+ this.tracer.logEvent("ContextManager", "Performing Hot Start Token Calibration");
306777
+ const contents = this.env.graphMapper.fromGraph(nodes);
306778
+ const header = this.headerProvider ? await this.headerProvider() : void 0;
306779
+ const combinedHistory = header ? [header, ...contents] : contents;
306780
+ const baseUnits = this.advancedTokenCalculator.getRawBaseUnits(nodes) + (header ? this.advancedTokenCalculator.getRawBaseUnitsForContent(header) : 0);
306781
+ if (combinedHistory.length > 0) {
306782
+ const result2 = await this.env.llmClient.countTokens({
306783
+ contents: combinedHistory,
306784
+ abortSignal
306785
+ });
306786
+ if (result2.totalTokens > 0) {
306787
+ this.env.eventBus.emitTokenGroundTruth({
306788
+ actualTokens: result2.totalTokens,
306789
+ promptBaseUnits: baseUnits
306790
+ });
306791
+ }
306792
+ }
306793
+ } catch (error40) {
306794
+ this.tracer.logEvent("ContextManager", "Hot Start Token Calibration Failed (Ignored)", { error: error40 });
306795
+ }
306796
+ }
306169
306797
  };
306170
306798
 
306171
306799
  // packages/core/dist/src/context/processors/historyTruncationProcessor.js
@@ -306198,6 +306826,337 @@ var RollingSummaryProcessorOptionsSchema = {
306198
306826
  required: []
306199
306827
  };
306200
306828
 
306829
+ // packages/core/dist/src/context/utils/contextTokenCalculator.js
306830
+ var StaticTokenCalculator = class {
306831
+ charsPerToken;
306832
+ registry;
306833
+ tokenCache = /* @__PURE__ */ new Map();
306834
+ constructor(charsPerToken, registry2) {
306835
+ this.charsPerToken = charsPerToken;
306836
+ this.registry = registry2;
306837
+ }
306838
+ /**
306839
+ * Estimates tokens for a simple string based on character count.
306840
+ * Fast, but inherently inaccurate compared to real model tokenization.
306841
+ */
306842
+ estimateTokensForString(text) {
306843
+ return Math.ceil(text.length / this.charsPerToken);
306844
+ }
306845
+ /**
306846
+ * Fast, simple heuristic conversion from tokens to expected character length.
306847
+ * Useful for calculating truncation thresholds.
306848
+ */
306849
+ tokensToChars(tokens) {
306850
+ return tokens * this.charsPerToken;
306851
+ }
306852
+ /**
306853
+ * Pre-calculates and caches the token cost of a newly minted node.
306854
+ * Because nodes are immutable, this cost never changes for this node ID.
306855
+ */
306856
+ /**
306857
+ * Removes cached token counts for any nodes that are no longer in the given live set.
306858
+ * This prevents unbounded memory growth during long sessions.
306859
+ */
306860
+ garbageCollectCache(liveNodeIds) {
306861
+ for (const [id] of this.tokenCache) {
306862
+ if (!liveNodeIds.has(id)) {
306863
+ this.tokenCache.delete(id);
306864
+ }
306865
+ }
306866
+ }
306867
+ cacheNodeTokens(node) {
306868
+ const behavior = this.registry.get(node.type);
306869
+ const parts2 = behavior.getEstimatableParts(node);
306870
+ const tokens = this.estimateTokensForParts(parts2);
306871
+ this.tokenCache.set(node.id, tokens);
306872
+ return tokens;
306873
+ }
306874
+ /**
306875
+ * Retrieves the token cost of a single node from the cache.
306876
+ * If it misses the cache, it computes it and caches it.
306877
+ */
306878
+ getTokenCost(node) {
306879
+ const cached2 = this.tokenCache.get(node.id);
306880
+ if (cached2 !== void 0)
306881
+ return cached2;
306882
+ return this.cacheNodeTokens(node);
306883
+ }
306884
+ /**
306885
+ * Calculates a detailed breakdown of tokens by category for a list of nodes.
306886
+ * Useful for calibration tracing and debugging overestimation.
306887
+ */
306888
+ calculateTokenBreakdown(nodes) {
306889
+ const breakdown = { total: 0, text: 0, media: 0, tool: 0, overhead: 0 };
306890
+ const seenIds = /* @__PURE__ */ new Set();
306891
+ const seenTurnIds = /* @__PURE__ */ new Set();
306892
+ for (const node of nodes) {
306893
+ if (seenIds.has(node.id))
306894
+ continue;
306895
+ seenIds.add(node.id);
306896
+ if (node.turnId) {
306897
+ if (!seenTurnIds.has(node.turnId)) {
306898
+ seenTurnIds.add(node.turnId);
306899
+ breakdown.overhead += MSG_OVERHEAD_TOKENS;
306900
+ breakdown.total += MSG_OVERHEAD_TOKENS;
306901
+ }
306902
+ }
306903
+ const cost = this.getTokenCost(node);
306904
+ breakdown.total += cost;
306905
+ const behavior = this.registry.get(node.type);
306906
+ const parts2 = behavior.getEstimatableParts(node);
306907
+ for (const part of parts2) {
306908
+ if (typeof part.text === "string") {
306909
+ breakdown.text += estimateTokenCountSync([part], 0, this.charsPerToken);
306910
+ } else if (part.inlineData?.mimeType?.startsWith("image/") || part.fileData?.mimeType?.startsWith("image/")) {
306911
+ breakdown.media += estimateTokenCountSync([part], 0, this.charsPerToken);
306912
+ } else if (part.functionCall || part.functionResponse) {
306913
+ breakdown.tool += estimateTokenCountSync([part], 0, this.charsPerToken);
306914
+ } else {
306915
+ breakdown.overhead += estimateTokenCountSync([part], 0, this.charsPerToken);
306916
+ }
306917
+ }
306918
+ }
306919
+ return breakdown;
306920
+ }
306921
+ /**
306922
+ * For the static calculator, Raw Base Units are exactly the same as the final tokens,
306923
+ * because there is no dynamic learned weight (the multiplier is effectively 1.0).
306924
+ */
306925
+ getRawBaseUnits(nodes) {
306926
+ return this.calculateConcreteListTokens(nodes);
306927
+ }
306928
+ getRawBaseUnitsForContent(content) {
306929
+ return this.calculateContentTokens(content);
306930
+ }
306931
+ calculateTokensAndBaseUnits(nodes) {
306932
+ const baseUnits = this.calculateConcreteListTokens(nodes);
306933
+ return { tokens: baseUnits, baseUnits };
306934
+ }
306935
+ calculateContentTokensAndBaseUnits(content) {
306936
+ const baseUnits = this.calculateContentTokens(content);
306937
+ return { tokens: baseUnits, baseUnits };
306938
+ }
306939
+ /**
306940
+ * Fast calculation for a flat array of ConcreteNodes (The Nodes).
306941
+ * It relies entirely on the O(1) sidecar token cache.
306942
+ */
306943
+ calculateConcreteListTokens(nodes) {
306944
+ let tokens = 0;
306945
+ const seenIds = /* @__PURE__ */ new Set();
306946
+ const seenTurnIds = /* @__PURE__ */ new Set();
306947
+ for (const node of nodes) {
306948
+ if (!seenIds.has(node.id)) {
306949
+ seenIds.add(node.id);
306950
+ tokens += this.getTokenCost(node);
306951
+ if (node.turnId) {
306952
+ if (!seenTurnIds.has(node.turnId)) {
306953
+ seenTurnIds.add(node.turnId);
306954
+ tokens += MSG_OVERHEAD_TOKENS;
306955
+ }
306956
+ }
306957
+ }
306958
+ }
306959
+ return tokens;
306960
+ }
306961
+ /**
306962
+ * Calculates the token cost for a single Gemini Content object.
306963
+ */
306964
+ calculateContentTokens(content) {
306965
+ return this.estimateTokensForParts(content.parts || []) + MSG_OVERHEAD_TOKENS;
306966
+ }
306967
+ /**
306968
+ * Slower, precise estimation for a Gemini Content/Part graph.
306969
+ * Deeply inspects the nested structure and uses the base tokenization math.
306970
+ */
306971
+ partTokenCache = /* @__PURE__ */ new WeakMap();
306972
+ estimateTokensForParts(parts2) {
306973
+ let total = 0;
306974
+ for (const part of parts2) {
306975
+ if (part !== null && typeof part === "object") {
306976
+ let cost = this.partTokenCache.get(part);
306977
+ if (cost === void 0) {
306978
+ cost = estimateTokenCountSync([part], 0, this.charsPerToken);
306979
+ this.partTokenCache.set(part, cost);
306980
+ }
306981
+ total += cost;
306982
+ } else {
306983
+ total += estimateTokenCountSync([part], 0, this.charsPerToken);
306984
+ }
306985
+ }
306986
+ return total;
306987
+ }
306988
+ };
306989
+
306990
+ // packages/core/dist/src/context/utils/adaptiveTokenCalculator.js
306991
+ var AdaptiveTokenCalculator = class {
306992
+ learnedWeight = 1;
306993
+ baseCalculator;
306994
+ constructor(charsPerToken, registry2, eventBus) {
306995
+ this.baseCalculator = new StaticTokenCalculator(charsPerToken, registry2);
306996
+ eventBus.onTokenGroundTruth((event) => {
306997
+ this.handleGroundTruth(event.actualTokens, event.promptBaseUnits);
306998
+ });
306999
+ }
307000
+ handleGroundTruth(actualTokens, promptBaseUnits) {
307001
+ if (promptBaseUnits <= 0)
307002
+ return;
307003
+ const targetWeight = actualTokens / promptBaseUnits;
307004
+ const oldWeight = this.learnedWeight;
307005
+ const learningRate = 0.2;
307006
+ const newWeight = oldWeight * (1 - learningRate) + targetWeight * learningRate;
307007
+ this.learnedWeight = Math.max(0.5, Math.min(newWeight, 2));
307008
+ debugLogger.log(`[AdaptiveTokenCalculator] Learned weight updated to ${this.learnedWeight.toFixed(3)} (API Tokens: ${actualTokens}, Base Units: ${promptBaseUnits}, Target Ratio: ${targetWeight.toFixed(3)})`);
307009
+ }
307010
+ /**
307011
+ * Retrieves the current learned weight multiplier.
307012
+ */
307013
+ getLearnedWeight() {
307014
+ return this.learnedWeight;
307015
+ }
307016
+ /**
307017
+ * Returns the exact, unweighted Base Heuristic Units for the graph.
307018
+ * This is used exactly once per interaction to capture the baseline sent to the API.
307019
+ */
307020
+ getRawBaseUnits(nodes) {
307021
+ return this.baseCalculator.calculateConcreteListTokens(nodes);
307022
+ }
307023
+ /**
307024
+ * Returns the exact, unweighted Base Heuristic Units for a raw content chunk.
307025
+ */
307026
+ getRawBaseUnitsForContent(content) {
307027
+ return this.baseCalculator.calculateContentTokens(content);
307028
+ }
307029
+ calculateTokensAndBaseUnits(nodes) {
307030
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
307031
+ return {
307032
+ tokens: Math.round(baseUnits * this.learnedWeight),
307033
+ baseUnits
307034
+ };
307035
+ }
307036
+ calculateContentTokensAndBaseUnits(content) {
307037
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
307038
+ return {
307039
+ tokens: Math.round(baseUnits * this.learnedWeight),
307040
+ baseUnits
307041
+ };
307042
+ }
307043
+ // --- Delegation and Weighting ---
307044
+ garbageCollectCache(liveNodeIds) {
307045
+ this.baseCalculator.garbageCollectCache(liveNodeIds);
307046
+ }
307047
+ cacheNodeTokens(node) {
307048
+ return this.baseCalculator.cacheNodeTokens(node);
307049
+ }
307050
+ calculateTokenBreakdown(nodes) {
307051
+ const raw = this.baseCalculator.calculateTokenBreakdown(nodes);
307052
+ return {
307053
+ text: Math.round(raw.text * this.learnedWeight),
307054
+ media: Math.round(raw.media * this.learnedWeight),
307055
+ tool: Math.round(raw.tool * this.learnedWeight),
307056
+ overhead: Math.round(raw.overhead * this.learnedWeight),
307057
+ total: Math.round(raw.total * this.learnedWeight)
307058
+ };
307059
+ }
307060
+ estimateTokensForParts(parts2) {
307061
+ const baseUnits = this.baseCalculator.estimateTokensForParts(parts2);
307062
+ return Math.round(baseUnits * this.learnedWeight);
307063
+ }
307064
+ getTokenCost(node) {
307065
+ const baseUnits = this.baseCalculator.getTokenCost(node);
307066
+ return Math.round(baseUnits * this.learnedWeight);
307067
+ }
307068
+ calculateConcreteListTokens(nodes) {
307069
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
307070
+ return Math.round(baseUnits * this.learnedWeight);
307071
+ }
307072
+ calculateContentTokens(content) {
307073
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
307074
+ return Math.round(baseUnits * this.learnedWeight);
307075
+ }
307076
+ estimateTokensForString(text) {
307077
+ const baseUnits = this.baseCalculator.estimateTokensForString(text);
307078
+ return Math.round(baseUnits * this.learnedWeight);
307079
+ }
307080
+ tokensToChars(tokens) {
307081
+ return this.baseCalculator.tokensToChars(tokens / this.learnedWeight);
307082
+ }
307083
+ };
307084
+
307085
+ // packages/core/dist/src/context/graph/behaviorRegistry.js
307086
+ var NodeBehaviorRegistry = class {
307087
+ behaviors = /* @__PURE__ */ new Map();
307088
+ register(behavior) {
307089
+ this.behaviors.set(behavior.type, behavior);
307090
+ }
307091
+ get(type2) {
307092
+ const behavior = this.behaviors.get(type2);
307093
+ if (!behavior) {
307094
+ throw new Error(`Unregistered Node type: ${type2}`);
307095
+ }
307096
+ return behavior;
307097
+ }
307098
+ };
307099
+
307100
+ // packages/core/dist/src/context/graph/builtinBehaviors.js
307101
+ var UserPromptBehavior = {
307102
+ type: NodeType.USER_PROMPT,
307103
+ getEstimatableParts(node) {
307104
+ return [node.payload];
307105
+ }
307106
+ };
307107
+ var AgentThoughtBehavior = {
307108
+ type: NodeType.AGENT_THOUGHT,
307109
+ getEstimatableParts(node) {
307110
+ return [node.payload];
307111
+ }
307112
+ };
307113
+ var ToolExecutionBehavior = {
307114
+ type: NodeType.TOOL_EXECUTION,
307115
+ getEstimatableParts(node) {
307116
+ return [node.payload];
307117
+ }
307118
+ };
307119
+ var MaskedToolBehavior = {
307120
+ type: NodeType.MASKED_TOOL,
307121
+ getEstimatableParts(node) {
307122
+ return [node.payload];
307123
+ }
307124
+ };
307125
+ var AgentYieldBehavior = {
307126
+ type: NodeType.AGENT_YIELD,
307127
+ getEstimatableParts() {
307128
+ return [];
307129
+ }
307130
+ };
307131
+ var SystemEventBehavior = {
307132
+ type: NodeType.SYSTEM_EVENT,
307133
+ getEstimatableParts(node) {
307134
+ return [node.payload];
307135
+ }
307136
+ };
307137
+ var SnapshotBehavior = {
307138
+ type: NodeType.SNAPSHOT,
307139
+ getEstimatableParts(node) {
307140
+ return [node.payload];
307141
+ }
307142
+ };
307143
+ var RollingSummaryBehavior = {
307144
+ type: NodeType.ROLLING_SUMMARY,
307145
+ getEstimatableParts(node) {
307146
+ return [node.payload];
307147
+ }
307148
+ };
307149
+ function registerBuiltInBehaviors(registry2) {
307150
+ registry2.register(UserPromptBehavior);
307151
+ registry2.register(AgentThoughtBehavior);
307152
+ registry2.register(ToolExecutionBehavior);
307153
+ registry2.register(MaskedToolBehavior);
307154
+ registry2.register(AgentYieldBehavior);
307155
+ registry2.register(SystemEventBehavior);
307156
+ registry2.register(SnapshotBehavior);
307157
+ registry2.register(RollingSummaryBehavior);
307158
+ }
307159
+
306201
307160
  // packages/core/dist/src/context/initializer.js
306202
307161
  async function initializeContextManager(config2, chat, lastPromptId) {
306203
307162
  const isV1Enabled = config2.getContextManagementConfig().enabled;
@@ -306247,9 +307206,15 @@ async function initializeContextManager(config2, chat, lastPromptId) {
306247
307206
  sessionId: lastPromptId
306248
307207
  });
306249
307208
  const eventBus = new ContextEventBus();
306250
- const env2 = new ContextEnvironmentImpl(() => config2.getBaseLlmClient(), config2.getSessionId(), lastPromptId, logDir, projectTempDir, tracer, 4, eventBus);
307209
+ const charsPerToken = 3;
307210
+ const behaviorRegistry = new NodeBehaviorRegistry();
307211
+ registerBuiltInBehaviors(behaviorRegistry);
307212
+ const calculator = new AdaptiveTokenCalculator(charsPerToken, behaviorRegistry, eventBus);
307213
+ const env2 = new ContextEnvironmentImpl(() => config2.getBaseLlmClient(), config2.getSessionId(), lastPromptId, logDir, projectTempDir, tracer, charsPerToken, eventBus, calculator, behaviorRegistry, {
307214
+ calibrateTokenCalculation: !!process.env["GEMINI_CONTEXT_CALIBRATE_TOKEN_CALCULATIONS"]
307215
+ });
306251
307216
  const orchestrator = new PipelineOrchestrator(sidecarProfile.buildPipelines(env2), sidecarProfile.buildAsyncPipelines(env2), env2, eventBus, tracer);
306252
- return new ContextManager(sidecarProfile, env2, tracer, orchestrator, chat.agentHistory, async () => {
307217
+ return new ContextManager(sidecarProfile, env2, tracer, orchestrator, chat.agentHistory, calculator, async () => {
306253
307218
  const parts2 = await getEnvironmentContext(config2);
306254
307219
  return { role: "user", parts: parts2 };
306255
307220
  });
@@ -306619,10 +307584,12 @@ var GeminiClient = class {
306619
307584
  return turn;
306620
307585
  }
306621
307586
  const modelForLimitCheck = this._getActiveModelForCurrentTurn();
307587
+ let currentBaseUnits = 0;
306622
307588
  if (this.config.getContextManagementConfig().enabled) {
306623
307589
  if (this.contextManager) {
306624
307590
  const pendingRequest = createUserContent(request);
306625
- const { history: newHistory, didApplyManagement } = await this.contextManager.renderHistory(pendingRequest);
307591
+ const { history: newHistory, didApplyManagement, baseUnits } = await this.contextManager.renderHistory(pendingRequest, void 0, signal);
307592
+ currentBaseUnits = baseUnits;
306626
307593
  if (didApplyManagement) {
306627
307594
  this.getChat().setHistory(newHistory, { silent: true });
306628
307595
  }
@@ -306722,6 +307689,15 @@ var GeminiClient = class {
306722
307689
  break;
306723
307690
  }
306724
307691
  yield event;
307692
+ if (event.type === GeminiEventType.Finished && this.contextManager) {
307693
+ const usageMetadata = event.value.usageMetadata;
307694
+ if (usageMetadata && usageMetadata.promptTokenCount !== void 0) {
307695
+ this.contextManager.getEnvironment().eventBus.emitTokenGroundTruth({
307696
+ actualTokens: usageMetadata.promptTokenCount,
307697
+ promptBaseUnits: currentBaseUnits
307698
+ });
307699
+ }
307700
+ }
306725
307701
  this.updateTelemetryTokenCount();
306726
307702
  if (event.type === GeminiEventType.Error) {
306727
307703
  isError = true;
@@ -307215,7 +308191,7 @@ var ToolExecutor = class {
307215
308191
  completedToolCall = await this.createSuccessResult(call, toolResult);
307216
308192
  } else {
307217
308193
  const displayText = typeof toolResult.returnDisplay === "string" ? toolResult.returnDisplay : void 0;
307218
- completedToolCall = this.createErrorResult(call, new Error(toolResult.error.message), toolResult.error.type, displayText, toolResult.tailToolCallRequest);
308194
+ completedToolCall = this.createErrorResult(call, new Error(toolResult.error.message), toolResult.error.type, displayText, toolResult.tailToolCallRequest, toolResult.display);
307219
308195
  }
307220
308196
  } catch (executionError) {
307221
308197
  spanMetadata.error = executionError;
@@ -307313,6 +308289,7 @@ var ToolExecutor = class {
307313
308289
  response: {
307314
308290
  callId: call.request.callId,
307315
308291
  responseParts,
308292
+ display: toolResult?.display,
307316
308293
  resultDisplay: toolResult?.returnDisplay,
307317
308294
  error: void 0,
307318
308295
  errorType: void 0,
@@ -307335,6 +308312,7 @@ var ToolExecutor = class {
307335
308312
  const successResponse = {
307336
308313
  callId,
307337
308314
  responseParts: response,
308315
+ display: toolResult.display,
307338
308316
  resultDisplay: toolResult.returnDisplay,
307339
308317
  error: void 0,
307340
308318
  errorType: void 0,
@@ -307359,8 +308337,8 @@ var ToolExecutor = class {
307359
308337
  tailToolCallRequest: toolResult.tailToolCallRequest
307360
308338
  };
307361
308339
  }
307362
- createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest) {
307363
- const response = this.createErrorResponse(call.request, error40, errorType, returnDisplay);
308340
+ createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest, display) {
308341
+ const response = this.createErrorResponse(call.request, error40, errorType, returnDisplay, display);
307364
308342
  const startTime = "startTime" in call ? call.startTime : void 0;
307365
308343
  return {
307366
308344
  status: CoreToolCallStatus.Error,
@@ -307374,11 +308352,12 @@ var ToolExecutor = class {
307374
308352
  tailToolCallRequest
307375
308353
  };
307376
308354
  }
307377
- createErrorResponse(request, error40, errorType, returnDisplay) {
308355
+ createErrorResponse(request, error40, errorType, returnDisplay, display) {
307378
308356
  const displayText = returnDisplay ?? error40.message;
307379
308357
  return {
307380
308358
  callId: request.callId,
307381
308359
  error: error40,
308360
+ display,
307382
308361
  responseParts: [
307383
308362
  {
307384
308363
  functionResponse: {
@@ -307650,6 +308629,16 @@ var Scheduler = class {
307650
308629
  }, () => {
307651
308630
  try {
307652
308631
  const invocation = tool.build(request.args);
308632
+ if (!request.display) {
308633
+ request.display = populateToolDisplay({
308634
+ name: tool.name,
308635
+ invocation,
308636
+ displayName: tool.displayName
308637
+ });
308638
+ if (!request.display.description) {
308639
+ request.display.description = tool.description;
308640
+ }
308641
+ }
307653
308642
  return {
307654
308643
  status: CoreToolCallStatus.Validating,
307655
308644
  request,
@@ -308376,8 +309365,8 @@ var WorkspaceContext = class {
308376
309365
  * @returns True if the path is within the root directory, false otherwise
308377
309366
  */
308378
309367
  isPathWithinRoot(pathToCheck, rootDirectory) {
308379
- const relative12 = path61.relative(rootDirectory, pathToCheck);
308380
- return !relative12.startsWith(`..${path61.sep}`) && relative12 !== ".." && !path61.isAbsolute(relative12);
309368
+ const relative11 = path61.relative(rootDirectory, pathToCheck);
309369
+ return !relative11.startsWith(`..${path61.sep}`) && relative11 !== ".." && !path61.isAbsolute(relative11);
308381
309370
  }
308382
309371
  };
308383
309372
 
@@ -308702,6 +309691,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
308702
309691
  compressionService;
308703
309692
  parentCallId;
308704
309693
  hasFailedCompressionAttempt = false;
309694
+ cache;
308705
309695
  get executionContext() {
308706
309696
  return {
308707
309697
  config: this.context.config,
@@ -308819,6 +309809,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
308819
309809
  this.onActivity = onActivity;
308820
309810
  this.compressionService = new ChatCompressionService();
308821
309811
  this.parentCallId = parentCallId;
309812
+ this.cache = new import_lru_cache.default(10);
308822
309813
  this.agentId = Math.random().toString(36).slice(2, 8);
308823
309814
  }
308824
309815
  /**
@@ -309019,7 +310010,14 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309019
310010
  try {
309020
310011
  const initialHints = this.context.config.injectionService.getInjectionsAfter(startIndex, "user_steering");
309021
310012
  const formattedInitialHints = formatUserHintsForModel(initialHints);
309022
- const environmentMemory = this.context.config.isJitContextEnabled?.() ? this.context.config.getSessionMemory() : this.context.config.getEnvironmentMemory();
310013
+ let environmentMemory;
310014
+ if (this.context.config.isJitContextEnabled?.()) {
310015
+ environmentMemory = this.definition.includeExtensionContext === false ? this.context.config.getSessionMemory({
310016
+ includeExtensionContext: false
310017
+ }) : this.context.config.getSessionMemory();
310018
+ } else {
310019
+ environmentMemory = this.context.config.getEnvironmentMemory();
310020
+ }
309023
310021
  const initialParts = [];
309024
310022
  if (environmentMemory) {
309025
310023
  initialParts.push({ text: environmentMemory });
@@ -309222,22 +310220,26 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309222
310220
  const requestedModel = resolvedConfig.model;
309223
310221
  let modelToUse;
309224
310222
  if (isAutoModel(requestedModel)) {
309225
- try {
309226
- const routingContext = {
309227
- history: chat.getHistory(
309228
- /*curated=*/
309229
- true
309230
- ),
309231
- request: message.parts || [],
309232
- signal,
309233
- requestedModel
309234
- };
309235
- const router = this.context.config.getModelRouterService();
309236
- const decision = await router.route(routingContext);
309237
- modelToUse = decision.model;
309238
- } catch (error40) {
309239
- debugLogger.warn(`Error during model routing: ${error40}`);
309240
- modelToUse = DEFAULT_GEMINI_MODEL;
310223
+ modelToUse = this.cache.get("modelToUse");
310224
+ if (!modelToUse) {
310225
+ try {
310226
+ const routingContext = {
310227
+ history: chat.getHistory(
310228
+ /*curated=*/
310229
+ true
310230
+ ),
310231
+ request: message.parts || [],
310232
+ signal,
310233
+ requestedModel
310234
+ };
310235
+ const router = this.context.config.getModelRouterService();
310236
+ const decision = await router.route(routingContext);
310237
+ modelToUse = decision.model;
310238
+ } catch (error40) {
310239
+ debugLogger.warn(`Error during model routing: ${error40}`);
310240
+ modelToUse = DEFAULT_GEMINI_MODEL;
310241
+ }
310242
+ this.cache.set("modelToUse", modelToUse);
309241
310243
  }
309242
310244
  } else {
309243
310245
  modelToUse = requestedModel;
@@ -309446,12 +310448,14 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309446
310448
  const part = syncResults.get(callId);
309447
310449
  if (part) {
309448
310450
  toolResponseParts.push(part);
310451
+ continue;
309449
310452
  }
309450
- }
309451
- if (functionCalls.length > 0 && toolResponseParts.length === 0 && !taskCompleted) {
309452
- toolResponseParts.push({
309453
- text: "All tool calls failed or were unauthorized. Please analyze the errors and try an alternative approach."
309454
- });
310453
+ const isAborted = signal.aborted;
310454
+ const isTaskComplete = functionCall.name === COMPLETE_TASK_TOOL_NAME && taskCompleted;
310455
+ if (isAborted || isTaskComplete) {
310456
+ continue;
310457
+ }
310458
+ throw new Error(`[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.`);
309455
310459
  }
309456
310460
  return {
309457
310461
  nextMessage: { role: "user", parts: toolResponseParts },
@@ -309760,7 +310764,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309760
310764
  isSubagentProgress: true,
309761
310765
  agentName: this.definition.name,
309762
310766
  recentActivity: [],
309763
- state: "running"
310767
+ state: SubagentState.RUNNING
309764
310768
  };
309765
310769
  updateOutput(initialProgress);
309766
310770
  }
@@ -309772,14 +310776,14 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309772
310776
  case "THOUGHT_CHUNK": {
309773
310777
  const text = String(activity.data["text"]);
309774
310778
  const lastItem = recentActivity[recentActivity.length - 1];
309775
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
310779
+ if (lastItem && lastItem.type === "thought" && lastItem.status === SubagentState.RUNNING) {
309776
310780
  lastItem.content = sanitizeThoughtContent(text);
309777
310781
  } else {
309778
310782
  recentActivity.push({
309779
310783
  id: randomUUID14(),
309780
310784
  type: "thought",
309781
310785
  content: sanitizeThoughtContent(text),
309782
- status: "running"
310786
+ status: SubagentState.RUNNING
309783
310787
  });
309784
310788
  }
309785
310789
  updated = true;
@@ -309801,7 +310805,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309801
310805
  displayName,
309802
310806
  description,
309803
310807
  args: args2,
309804
- status: "running"
310808
+ status: SubagentState.RUNNING
309805
310809
  });
309806
310810
  updated = true;
309807
310811
  const latestTool = recentActivity[recentActivity.length - 1];
@@ -309815,8 +310819,8 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309815
310819
  const data = activity.data["data"];
309816
310820
  const isError = isToolActivityError(data);
309817
310821
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
309818
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === name3 && recentActivity[i3].status === "running") {
309819
- recentActivity[i3].status = isError ? "error" : "completed";
310822
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === name3 && recentActivity[i3].status === SubagentState.RUNNING) {
310823
+ recentActivity[i3].status = isError ? SubagentState.ERROR : SubagentState.COMPLETED;
309820
310824
  updated = true;
309821
310825
  this.publishActivity(recentActivity[i3]);
309822
310826
  break;
@@ -309833,16 +310837,16 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309833
310837
  const toolName = activity.data["name"] ? String(activity.data["name"]) : void 0;
309834
310838
  if (toolName && (isCancellation || isRejection)) {
309835
310839
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
309836
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running") {
309837
- recentActivity[i3].status = "cancelled";
310840
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === SubagentState.RUNNING) {
310841
+ recentActivity[i3].status = SubagentState.CANCELLED;
309838
310842
  updated = true;
309839
310843
  break;
309840
310844
  }
309841
310845
  }
309842
310846
  } else if (toolName) {
309843
310847
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
309844
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === "running") {
309845
- recentActivity[i3].status = "error";
310848
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === SubagentState.RUNNING) {
310849
+ recentActivity[i3].status = SubagentState.ERROR;
309846
310850
  updated = true;
309847
310851
  break;
309848
310852
  }
@@ -309852,7 +310856,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309852
310856
  id: randomUUID14(),
309853
310857
  type: "thought",
309854
310858
  content: isCancellation || isRejection ? sanitizedError : `Error: ${sanitizedError}`,
309855
- status: isCancellation || isRejection ? "cancelled" : "error"
310859
+ status: isCancellation || isRejection ? SubagentState.CANCELLED : SubagentState.ERROR
309856
310860
  });
309857
310861
  updated = true;
309858
310862
  break;
@@ -309866,7 +310870,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309866
310870
  agentName: this.definition.name,
309867
310871
  recentActivity: [...recentActivity],
309868
310872
  // Copy to avoid mutation issues
309869
- state: "running"
310873
+ state: SubagentState.RUNNING
309870
310874
  };
309871
310875
  updateOutput(progress2);
309872
310876
  }
@@ -309878,7 +310882,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309878
310882
  isSubagentProgress: true,
309879
310883
  agentName: this.definition.name,
309880
310884
  recentActivity: [...recentActivity],
309881
- state: "cancelled"
310885
+ state: SubagentState.CANCELLED
309882
310886
  };
309883
310887
  if (updateOutput) {
309884
310888
  updateOutput(progress2);
@@ -309891,7 +310895,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309891
310895
  isSubagentProgress: true,
309892
310896
  agentName: this.definition.name,
309893
310897
  recentActivity: [...recentActivity],
309894
- state: "completed",
310898
+ state: SubagentState.COMPLETED,
309895
310899
  result: output.result,
309896
310900
  terminateReason: output.terminate_reason
309897
310901
  };
@@ -309912,18 +310916,18 @@ ${output.result}`;
309912
310916
  debugLogger.error(`Subagent '${this.definition.name}' failed:`, error40);
309913
310917
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || errorMessage.includes("Aborted");
309914
310918
  for (const item of recentActivity) {
309915
- if (item.status === "running") {
309916
- item.status = isAbort ? "cancelled" : "error";
310919
+ if (item.status === SubagentState.RUNNING) {
310920
+ item.status = isAbort ? SubagentState.CANCELLED : SubagentState.ERROR;
309917
310921
  }
309918
310922
  }
309919
310923
  if (!isAbort) {
309920
310924
  const lastActivity = recentActivity[recentActivity.length - 1];
309921
- if (!lastActivity || lastActivity.status !== "error") {
310925
+ if (!lastActivity || lastActivity.status !== SubagentState.ERROR) {
309922
310926
  recentActivity.push({
309923
310927
  id: randomUUID14(),
309924
310928
  type: "thought",
309925
310929
  content: `Error: ${errorMessage}`,
309926
- status: "error"
310930
+ status: SubagentState.ERROR
309927
310931
  });
309928
310932
  }
309929
310933
  }
@@ -309931,7 +310935,7 @@ ${output.result}`;
309931
310935
  isSubagentProgress: true,
309932
310936
  agentName: this.definition.name,
309933
310937
  recentActivity: [...recentActivity],
309934
- state: isAbort ? "cancelled" : "error"
310938
+ state: isAbort ? SubagentState.CANCELLED : SubagentState.ERROR
309935
310939
  };
309936
310940
  if (updateOutput) {
309937
310941
  updateOutput(progress);
@@ -310046,7 +311050,7 @@ var A2AResultReassembler = class {
310046
311050
  id: "auth-required",
310047
311051
  type: "thought",
310048
311052
  content: AUTH_REQUIRED_MSG,
310049
- status: "running"
311053
+ status: SubagentState.RUNNING
310050
311054
  });
310051
311055
  }
310052
311056
  this.messageLog.forEach((msg, index) => {
@@ -310054,7 +311058,7 @@ var A2AResultReassembler = class {
310054
311058
  id: `msg-${index}`,
310055
311059
  type: "thought",
310056
311060
  content: msg.trim(),
310057
- status: "completed"
311061
+ status: SubagentState.COMPLETED
310058
311062
  });
310059
311063
  });
310060
311064
  if (items.length === 0 && !isAuthRequired) {
@@ -310062,7 +311066,7 @@ var A2AResultReassembler = class {
310062
311066
  id: "pending",
310063
311067
  type: "thought",
310064
311068
  content: "Working...",
310065
- status: "running"
311069
+ status: SubagentState.RUNNING
310066
311070
  });
310067
311071
  }
310068
311072
  return items;
@@ -310247,13 +311251,13 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
310247
311251
  updateOutput({
310248
311252
  isSubagentProgress: true,
310249
311253
  agentName,
310250
- state: "running",
311254
+ state: SubagentState.RUNNING,
310251
311255
  recentActivity: [
310252
311256
  {
310253
311257
  id: "pending",
310254
311258
  type: "thought",
310255
311259
  content: "Working...",
310256
- status: "running"
311260
+ status: SubagentState.RUNNING
310257
311261
  }
310258
311262
  ]
310259
311263
  });
@@ -310284,7 +311288,7 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
310284
311288
  updateOutput({
310285
311289
  isSubagentProgress: true,
310286
311290
  agentName,
310287
- state: "running",
311291
+ state: SubagentState.RUNNING,
310288
311292
  recentActivity: reassembler.toActivityItems(),
310289
311293
  result: reassembler.toString()
310290
311294
  });
@@ -310304,7 +311308,7 @@ ${JSON.stringify(finalResponse, null, 2)}`);
310304
311308
  const finalProgress = {
310305
311309
  isSubagentProgress: true,
310306
311310
  agentName,
310307
- state: "completed",
311311
+ state: SubagentState.COMPLETED,
310308
311312
  result: finalOutput,
310309
311313
  recentActivity: reassembler.toActivityItems()
310310
311314
  };
@@ -310324,7 +311328,7 @@ ${errorMessage}` : errorMessage;
310324
311328
  const errorProgress = {
310325
311329
  isSubagentProgress: true,
310326
311330
  agentName,
310327
- state: "error",
311331
+ state: SubagentState.ERROR,
310328
311332
  result: fullDisplay,
310329
311333
  recentActivity: reassembler.toActivityItems()
310330
311334
  };
@@ -311834,7 +312838,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311834
312838
  isSubagentProgress: true,
311835
312839
  agentName: this.agentName,
311836
312840
  recentActivity: [],
311837
- state: "running"
312841
+ state: SubagentState.RUNNING
311838
312842
  };
311839
312843
  updateOutput(initialProgress);
311840
312844
  }
@@ -311844,7 +312848,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311844
312848
  id: randomUUID15(),
311845
312849
  type: "thought",
311846
312850
  content: sanitizedMsg,
311847
- status: "completed"
312851
+ status: SubagentState.COMPLETED
311848
312852
  });
311849
312853
  if (recentActivity.length > MAX_RECENT_ACTIVITY) {
311850
312854
  recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
@@ -311853,7 +312857,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311853
312857
  isSubagentProgress: true,
311854
312858
  agentName: this.agentName,
311855
312859
  recentActivity: [...recentActivity],
311856
- state: "running"
312860
+ state: SubagentState.RUNNING
311857
312861
  });
311858
312862
  } : void 0;
311859
312863
  const result2 = await createBrowserAgentDefinition(this.config, this.messageBus, printOutput);
@@ -311869,14 +312873,14 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311869
312873
  case "THOUGHT_CHUNK": {
311870
312874
  const text = String(activity.data["text"]);
311871
312875
  const lastItem = recentActivity[recentActivity.length - 1];
311872
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
312876
+ if (lastItem && lastItem.type === "thought" && lastItem.status === SubagentState.RUNNING) {
311873
312877
  lastItem.content = sanitizeThoughtContent(text);
311874
312878
  } else {
311875
312879
  recentActivity.push({
311876
312880
  id: randomUUID15(),
311877
312881
  type: "thought",
311878
312882
  content: sanitizeThoughtContent(text),
311879
- status: "running"
312883
+ status: SubagentState.RUNNING
311880
312884
  });
311881
312885
  }
311882
312886
  updated = true;
@@ -311895,7 +312899,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311895
312899
  displayName,
311896
312900
  description,
311897
312901
  args: args2,
311898
- status: "running"
312902
+ status: SubagentState.RUNNING
311899
312903
  });
311900
312904
  updated = true;
311901
312905
  break;
@@ -311905,8 +312909,8 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311905
312909
  const data = activity.data["data"];
311906
312910
  const isError = isToolActivityError(data);
311907
312911
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
311908
- if (recentActivity[i3].type === "tool_call" && callId != null && recentActivity[i3].id === callId && recentActivity[i3].status === "running") {
311909
- recentActivity[i3].status = isError ? "error" : "completed";
312912
+ if (recentActivity[i3].type === "tool_call" && callId != null && recentActivity[i3].id === callId && recentActivity[i3].status === SubagentState.RUNNING) {
312913
+ recentActivity[i3].status = isError ? SubagentState.ERROR : SubagentState.COMPLETED;
311910
312914
  updated = true;
311911
312915
  break;
311912
312916
  }
@@ -311917,10 +312921,10 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311917
312921
  const error40 = String(activity.data["error"]);
311918
312922
  const isCancellation = error40 === "Request cancelled.";
311919
312923
  const callId = activity.data["callId"] ? String(activity.data["callId"]) : void 0;
311920
- const newStatus = isCancellation ? "cancelled" : "error";
312924
+ const newStatus = isCancellation ? SubagentState.CANCELLED : SubagentState.ERROR;
311921
312925
  if (callId) {
311922
312926
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
311923
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === "running") {
312927
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === SubagentState.RUNNING) {
311924
312928
  recentActivity[i3].status = newStatus;
311925
312929
  updated = true;
311926
312930
  break;
@@ -311928,7 +312932,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311928
312932
  }
311929
312933
  } else {
311930
312934
  for (const item of recentActivity) {
311931
- if (item.type === "tool_call" && item.status === "running") {
312935
+ if (item.type === "tool_call" && item.status === SubagentState.RUNNING) {
311932
312936
  item.status = newStatus;
311933
312937
  updated = true;
311934
312938
  }
@@ -311955,7 +312959,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311955
312959
  isSubagentProgress: true,
311956
312960
  agentName: this.agentName,
311957
312961
  recentActivity: [...recentActivity],
311958
- state: "running"
312962
+ state: SubagentState.RUNNING
311959
312963
  };
311960
312964
  updateOutput(progress2);
311961
312965
  }
@@ -311974,11 +312978,11 @@ Result:
311974
312978
  ${output.result}`;
311975
312979
  let progressState;
311976
312980
  if (output.terminate_reason === AgentTerminateMode.ABORTED) {
311977
- progressState = "cancelled";
312981
+ progressState = SubagentState.CANCELLED;
311978
312982
  } else if (output.terminate_reason === AgentTerminateMode.GOAL) {
311979
- progressState = "completed";
312983
+ progressState = SubagentState.COMPLETED;
311980
312984
  } else {
311981
- progressState = "error";
312985
+ progressState = SubagentState.ERROR;
311982
312986
  }
311983
312987
  const progress = {
311984
312988
  isSubagentProgress: true,
@@ -312000,15 +313004,15 @@ ${output.result}`;
312000
313004
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || rawErrorMessage.includes("Aborted");
312001
313005
  const errorMessage = sanitizeErrorMessage(rawErrorMessage);
312002
313006
  for (const item of recentActivity) {
312003
- if (item.status === "running") {
312004
- item.status = isAbort ? "cancelled" : "error";
313007
+ if (item.status === SubagentState.RUNNING) {
313008
+ item.status = isAbort ? SubagentState.CANCELLED : SubagentState.ERROR;
312005
313009
  }
312006
313010
  }
312007
313011
  const progress = {
312008
313012
  isSubagentProgress: true,
312009
313013
  agentName: this.agentName,
312010
313014
  recentActivity: [...recentActivity],
312011
- state: isAbort ? "cancelled" : "error"
313015
+ state: isAbort ? SubagentState.CANCELLED : SubagentState.ERROR
312012
313016
  };
312013
313017
  if (updateOutput) {
312014
313018
  updateOutput(progress);
@@ -312675,7 +313679,12 @@ ${reminder}`;
312675
313679
  if (!text) {
312676
313680
  throw new Error("Invalid response from Local Gemini API: No text found");
312677
313681
  }
312678
- return JSON.parse(result2.text);
313682
+ const parsed = JSON.parse(result2.text);
313683
+ const isRecord3 = (val) => typeof val === "object" && val !== null && !Array.isArray(val);
313684
+ if (isRecord3(parsed)) {
313685
+ return parsed;
313686
+ }
313687
+ throw new Error("Invalid JSON response format from Local LLM");
312679
313688
  } catch (error40) {
312680
313689
  debugLogger.error(`[LocalLiteRtLmClient] Failed to generate content:`, error40);
312681
313690
  throw error40;
@@ -317289,9 +318298,15 @@ var GitService = class _GitService {
317289
318298
  const gitConfigPath = path66.join(repoDir, ".gitconfig");
317290
318299
  const systemConfigPath = path66.join(repoDir, ".gitconfig_system_empty");
317291
318300
  return {
318301
+ ...sanitizeEnvironment(process.env, getSecureSanitizationConfig({
318302
+ enableEnvironmentVariableRedaction: true
318303
+ })),
317292
318304
  // Prevent git from using the user's global git config.
317293
318305
  GIT_CONFIG_GLOBAL: gitConfigPath,
317294
318306
  GIT_CONFIG_SYSTEM: systemConfigPath,
318307
+ // Ensure we don't inherit isolation-breaking variables from the user environment.
318308
+ GIT_DIR: void 0,
318309
+ GIT_WORK_TREE: void 0,
317295
318310
  // Explicitly provide identity to prevent "Author identity unknown" errors
317296
318311
  // inside sandboxed environments like Docker where the gitconfig might not
317297
318312
  // be picked up properly.
@@ -317346,9 +318361,9 @@ var GitService = class _GitService {
317346
318361
  get shadowGitRepository() {
317347
318362
  const repoDir = this.getHistoryDir();
317348
318363
  return simpleGit(this.projectRoot).env({
318364
+ ...this.getShadowRepoEnv(repoDir),
317349
318365
  GIT_DIR: path66.join(repoDir, ".git"),
317350
- GIT_WORK_TREE: this.projectRoot,
317351
- ...this.getShadowRepoEnv(repoDir)
318366
+ GIT_WORK_TREE: this.projectRoot
317352
318367
  });
317353
318368
  }
317354
318369
  async getCurrentCommitHash() {
@@ -318195,16 +319210,19 @@ var TrackerVisualizeTool = class _TrackerVisualizeTool extends BaseDeclarativeTo
318195
319210
  // packages/core/dist/src/availability/modelAvailabilityService.js
318196
319211
  var ModelAvailabilityService = class {
318197
319212
  health = /* @__PURE__ */ new Map();
318198
- markTerminal(model, reason) {
319213
+ markTerminal(modelId, reason) {
319214
+ const model = normalizeModelId(modelId);
318199
319215
  this.setState(model, {
318200
319216
  status: "terminal",
318201
319217
  reason
318202
319218
  });
318203
319219
  }
318204
- markHealthy(model) {
319220
+ markHealthy(modelId) {
319221
+ const model = normalizeModelId(modelId);
318205
319222
  this.clearState(model);
318206
319223
  }
318207
- markRetryOncePerTurn(model, attempts = 1) {
319224
+ markRetryOncePerTurn(modelId, attempts = 1) {
319225
+ const model = normalizeModelId(modelId);
318208
319226
  const currentState = this.health.get(model);
318209
319227
  if (currentState?.status === "terminal") {
318210
319228
  return;
@@ -318220,13 +319238,15 @@ var ModelAvailabilityService = class {
318220
319238
  attempts
318221
319239
  });
318222
319240
  }
318223
- consumeStickyAttempt(model) {
319241
+ consumeStickyAttempt(modelId) {
319242
+ const model = normalizeModelId(modelId);
318224
319243
  const state = this.health.get(model);
318225
319244
  if (state?.status === "sticky_retry") {
318226
319245
  this.setState(model, { ...state, consumed: true });
318227
319246
  }
318228
319247
  }
318229
- snapshot(model) {
319248
+ snapshot(modelId) {
319249
+ const model = normalizeModelId(modelId);
318230
319250
  const state = this.health.get(model);
318231
319251
  if (!state) {
318232
319252
  return { available: true };
@@ -318239,9 +319259,10 @@ var ModelAvailabilityService = class {
318239
319259
  }
318240
319260
  return { available: true };
318241
319261
  }
318242
- selectFirstAvailable(models) {
319262
+ selectFirstAvailable(modelIds) {
318243
319263
  const skipped = [];
318244
- for (const model of models) {
319264
+ for (const modelId of modelIds) {
319265
+ const model = normalizeModelId(modelId);
318245
319266
  const snapshot = this.snapshot(model);
318246
319267
  if (snapshot.available) {
318247
319268
  const state = this.health.get(model);
@@ -318408,7 +319429,13 @@ ${formattedHistory}
318408
319429
  const routerResponse = ClassifierResponseSchema.parse(jsonResponse);
318409
319430
  const reasoning = routerResponse.reasoning;
318410
319431
  const latencyMs = Date.now() - startTime;
318411
- const selectedModel = resolveClassifierModel(context2.requestedModel ?? config2.getModel(), routerResponse.model_choice);
319432
+ const [useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview] = await Promise.all([
319433
+ config2.getGemini31Launched(),
319434
+ config2.getGemini31FlashLiteLaunched(),
319435
+ config2.getUseCustomToolModel(),
319436
+ config2.getHasAccessToPreviewModel?.() ?? true
319437
+ ]);
319438
+ const selectedModel = resolveClassifierModel(context2.requestedModel ?? config2.getModel(), routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318412
319439
  return {
318413
319440
  model: selectedModel,
318414
319441
  metadata: {
@@ -318566,7 +319593,13 @@ var ClassifierStrategy = class {
318566
319593
  config2.getGemini31FlashLiteLaunched(),
318567
319594
  config2.getUseCustomToolModel()
318568
319595
  ]);
318569
- const selectedModel = resolveClassifierModel(model, routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2);
319596
+ const selectedModel = normalizeModelId(resolveClassifierModel(normalizeModelId(model), routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2));
319597
+ const service = config2.getModelAvailabilityService();
319598
+ const snapshot = service.snapshot(selectedModel);
319599
+ if (!snapshot.available) {
319600
+ debugLogger.warn(`[Routing] Classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`);
319601
+ return null;
319602
+ }
318570
319603
  return {
318571
319604
  model: selectedModel,
318572
319605
  metadata: {
@@ -318664,7 +319697,15 @@ var NumericalClassifierStrategy = class {
318664
319697
  return null;
318665
319698
  }
318666
319699
  const promptId = getPromptIdWithFallback("classifier-router");
318667
- const finalHistory = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
319700
+ const candidateSlice = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
319701
+ let firstTextIndex = -1;
319702
+ for (let i3 = 0; i3 < candidateSlice.length; i3++) {
319703
+ if (!isFunctionCall(candidateSlice[i3]) && !isFunctionResponse(candidateSlice[i3])) {
319704
+ firstTextIndex = i3;
319705
+ break;
319706
+ }
319707
+ }
319708
+ const finalHistory = firstTextIndex === -1 ? [] : candidateSlice.slice(firstTextIndex);
318668
319709
  const requestParts = Array.isArray(context2.request) ? context2.request : [context2.request];
318669
319710
  const sanitizedRequest = requestParts.map((part) => {
318670
319711
  if (typeof part === "string") {
@@ -318692,7 +319733,13 @@ var NumericalClassifierStrategy = class {
318692
319733
  config2.getGemini31FlashLiteLaunched(),
318693
319734
  config2.getUseCustomToolModel()
318694
319735
  ]);
318695
- const selectedModel = resolveClassifierModel(model, modelAlias, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2);
319736
+ const selectedModel = normalizeModelId(resolveClassifierModel(normalizeModelId(model), modelAlias, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2));
319737
+ const service = config2.getModelAvailabilityService();
319738
+ const snapshot = service.snapshot(selectedModel);
319739
+ if (!snapshot.available) {
319740
+ debugLogger.warn(`[Routing] Numerical classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`);
319741
+ return null;
319742
+ }
318696
319743
  const latencyMs = Date.now() - startTime;
318697
319744
  return {
318698
319745
  model: selectedModel,
@@ -318834,12 +319881,14 @@ var ApprovalModeStrategy = class {
318834
319881
  const startTime = Date.now();
318835
319882
  const approvalMode = config2.getApprovalMode();
318836
319883
  const approvedPlanPath = config2.getApprovedPlanPath();
318837
- const [useGemini3_1, useCustomToolModel] = await Promise.all([
319884
+ const [useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview] = await Promise.all([
318838
319885
  config2.getGemini31Launched(),
318839
- config2.getUseCustomToolModel()
319886
+ config2.getGemini31FlashLiteLaunched(),
319887
+ config2.getUseCustomToolModel(),
319888
+ config2.getHasAccessToPreviewModel()
318840
319889
  ]);
318841
319890
  if (approvalMode === ApprovalMode.PLAN) {
318842
- const proModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_PRO, useGemini3_1, useCustomToolModel);
319891
+ const proModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_PRO, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318843
319892
  return {
318844
319893
  model: proModel,
318845
319894
  metadata: {
@@ -318849,7 +319898,7 @@ var ApprovalModeStrategy = class {
318849
319898
  }
318850
319899
  };
318851
319900
  } else if (approvedPlanPath) {
318852
- const flashModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_FLASH, useGemini3_1, useCustomToolModel);
319901
+ const flashModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_FLASH, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318853
319902
  return {
318854
319903
  model: flashModel,
318855
319904
  metadata: {
@@ -319153,6 +320202,19 @@ var DEFAULT_MODEL_CONFIGS = {
319153
320202
  extends: "gemini-3-flash-base",
319154
320203
  modelConfig: {}
319155
320204
  },
320205
+ "context-snapshotter": {
320206
+ extends: "gemini-3-flash-base",
320207
+ modelConfig: {
320208
+ generateContentConfig: {
320209
+ thinkingConfig: {
320210
+ thinkingLevel: ThinkingLevel.HIGH
320211
+ },
320212
+ temperature: 1,
320213
+ topP: 0.95,
320214
+ topK: 64
320215
+ }
320216
+ }
320217
+ },
319156
320218
  "chat-compression-3-pro": {
319157
320219
  modelConfig: {
319158
320220
  model: "gemini-3-pro-preview"
@@ -321786,7 +322848,7 @@ var HookEventHandler = class {
321786
322848
  const hookType = this.getHookTypeFromResult(result2);
321787
322849
  const hookCallEvent = new HookCallEvent(eventName, hookType, hookName, { ...input }, result2.duration, result2.success, result2.output ? { ...result2.output } : void 0, result2.exitCode, result2.stdout, result2.stderr, result2.error?.message);
321788
322850
  logHookCall(this.context.config, hookCallEvent);
321789
- if (result2.output?.systemMessage && result2.outputFormat === "json") {
322851
+ if (result2.output?.systemMessage) {
321790
322852
  coreEvents.emitHookSystemMessage({
321791
322853
  hookName,
321792
322854
  eventName,
@@ -323839,8 +324901,8 @@ var AllowedPathChecker = class {
323839
324901
  while (current && current !== path73.dirname(current)) {
323840
324902
  if (fs65.existsSync(current)) {
323841
324903
  const canonical = fs65.realpathSync(current);
323842
- const relative12 = path73.relative(current, resolved);
323843
- return path73.join(canonical, relative12);
324904
+ const relative11 = path73.relative(current, resolved);
324905
+ return path73.join(canonical, relative11);
323844
324906
  }
323845
324907
  current = path73.dirname(current);
323846
324908
  }
@@ -323850,8 +324912,8 @@ var AllowedPathChecker = class {
323850
324912
  }
323851
324913
  }
323852
324914
  isPathAllowed(targetPath, allowedDir) {
323853
- const relative12 = path73.relative(allowedDir, targetPath);
323854
- return relative12 === "" || !relative12.startsWith("..") && !path73.isAbsolute(relative12);
324915
+ const relative11 = path73.relative(allowedDir, targetPath);
324916
+ return relative11 === "" || !relative11.startsWith("..") && !path73.isAbsolute(relative11);
323855
324917
  }
323856
324918
  collectPathsToCheck(args2, includedArgs, excludedArgs, prefix = "") {
323857
324919
  const paths = [];
@@ -327069,21 +328131,29 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
327069
328131
  }
327070
328132
  }
327071
328133
  function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
328134
+ const baseFetch = transportOptions.fetch ?? globalThis.fetch;
328135
+ const httpOptions = {
328136
+ ...transportOptions,
328137
+ fetch: async (url3, init2) => {
328138
+ const res = await baseFetch(url3, init2);
328139
+ return init2?.method === "GET" && res.status === 404 ? new Response(null, { status: 405, statusText: "Method Not Allowed" }) : res;
328140
+ }
328141
+ };
327072
328142
  if (mcpServerConfig.httpUrl) {
327073
328143
  if (mcpServerConfig.url) {
327074
328144
  debugLogger.warn(`MCP server '${mcpServerName}': Both 'httpUrl' and 'url' are configured. Using deprecated 'httpUrl'. Please migrate to 'url' with 'type: "http"'.`);
327075
328145
  }
327076
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), transportOptions);
328146
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), httpOptions);
327077
328147
  }
327078
328148
  if (mcpServerConfig.url && mcpServerConfig.type) {
327079
328149
  if (mcpServerConfig.type === "http") {
327080
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
328150
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), httpOptions);
327081
328151
  } else if (mcpServerConfig.type === "sse") {
327082
328152
  return new SSEClientTransport(new URL(mcpServerConfig.url), transportOptions);
327083
328153
  }
327084
328154
  }
327085
328155
  if (mcpServerConfig.url) {
327086
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
328156
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), httpOptions);
327087
328157
  }
327088
328158
  throw new Error(`No URL configured for MCP server '${mcpServerName}'`);
327089
328159
  }
@@ -336035,7 +337105,15 @@ var Config = class {
336035
337105
  this.workspaceContext.addDirectory(dir);
336036
337106
  }
336037
337107
  if (this.planEnabled) {
336038
- const plansDir = this.storage.getPlansDir();
337108
+ let plansDir;
337109
+ try {
337110
+ plansDir = this.storage.getPlansDir();
337111
+ } catch (error40) {
337112
+ const errorMessage = error40 instanceof Error ? error40.message : String(error40);
337113
+ coreEvents.emitFeedback("warning", "Invalid custom plans directory: " + errorMessage + ". Falling back to default project temp directory.", error40);
337114
+ this.storage.setCustomPlansDir(void 0);
337115
+ plansDir = this.storage.getPlansDir();
337116
+ }
336039
337117
  try {
336040
337118
  await fs68.promises.access(plansDir);
336041
337119
  this.workspaceContext.addDirectory(plansDir);
@@ -336720,7 +337798,7 @@ var Config = class {
336720
337798
  if (this.experimentalJitContext && this.memoryContextManager) {
336721
337799
  await this.memoryContextManager.refresh();
336722
337800
  } else {
336723
- const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-KSYZVCWF.js");
337801
+ const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-XFCKEF3F.js");
336724
337802
  await refreshServerHierarchicalMemory2(this);
336725
337803
  }
336726
337804
  if (this._geminiClient?.isInitialized()) {
@@ -336755,12 +337833,13 @@ var Config = class {
336755
337833
  * user message when JIT is enabled. Returns empty string when JIT is
336756
337834
  * disabled (Tier 2 memory is already in the system instruction).
336757
337835
  */
336758
- getSessionMemory() {
337836
+ getSessionMemory(options) {
336759
337837
  if (!this.experimentalJitContext || !this.memoryContextManager) {
336760
337838
  return "";
336761
337839
  }
336762
337840
  const sections = [];
336763
- const extension = this.memoryContextManager.getExtensionMemory();
337841
+ const includeExtensionContext = options?.includeExtensionContext ?? true;
337842
+ const extension = includeExtensionContext ? this.memoryContextManager.getExtensionMemory() : "";
336764
337843
  const project = this.memoryContextManager.getEnvironmentMemory();
336765
337844
  if (extension?.trim()) {
336766
337845
  sections.push(`<extension_context>
@@ -337175,16 +338254,32 @@ ${sections.join("\n")}
337175
338254
  setIdeMode(value) {
337176
338255
  this.ideMode = value;
337177
338256
  }
337178
- isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot) {
338257
+ isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot, checkType = "write") {
337179
338258
  if (!hasScopedMemoryInboxAccess()) {
337180
338259
  return false;
337181
338260
  }
337182
338261
  const normalizedPath = path76.resolve(absolutePath);
338262
+ const resolvedMemoryRoot = resolveToRealPath(this.storage.getProjectMemoryTempDir());
338263
+ if (checkType === "read") {
338264
+ const resolvedInboxRoot = resolveToRealPath(inboxRoot);
338265
+ const normalizedInboxRoot = path76.resolve(inboxRoot);
338266
+ if (resolvedPath === resolvedInboxRoot || normalizedPath === normalizedInboxRoot) {
338267
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
338268
+ }
338269
+ for (const kind of ["private", "global"]) {
338270
+ const kindRoot = path76.join(inboxRoot, kind);
338271
+ const resolvedKindRoot = resolveToRealPath(kindRoot);
338272
+ const normalizedKindRoot = path76.resolve(kindRoot);
338273
+ if (resolvedPath === resolvedKindRoot || normalizedPath === normalizedKindRoot || isSubpath(resolvedKindRoot, resolvedPath) || isSubpath(normalizedKindRoot, normalizedPath)) {
338274
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
338275
+ }
338276
+ }
338277
+ return false;
338278
+ }
337183
338279
  const isCanonicalPatchPath = ["private", "global"].some((kind) => normalizedPath === path76.resolve(inboxRoot, kind, "extraction.patch"));
337184
338280
  if (!isCanonicalPatchPath) {
337185
338281
  return false;
337186
338282
  }
337187
- const resolvedMemoryRoot = resolveToRealPath(this.storage.getProjectMemoryTempDir());
337188
338283
  return isSubpath(resolvedMemoryRoot, resolvedPath);
337189
338284
  }
337190
338285
  isScopedAutoMemoryExtractionWritePathAllowed(absolutePath, resolvedPath) {
@@ -337214,7 +338309,9 @@ ${sections.join("\n")}
337214
338309
  * the auto-memory extraction agent and the `/memory inbox` review flow. The
337215
338310
  * main agent is denied access to it even though it falls inside the project
337216
338311
  * temp dir; the extraction agent receives a narrow execution-scoped exception
337217
- * for `.inbox/{private,global}/extraction.patch`.
338312
+ * for *writes* to `.inbox/{private,global}/extraction.patch`. Scoped *read*
338313
+ * access to the wider `.inbox/{private,global}/` subtree is granted in
338314
+ * `validatePathAccess` so the extractor can enumerate prior patches.
337218
338315
  *
337219
338316
  * @param absolutePath The absolute path to check.
337220
338317
  * @returns true if the path is allowed, false otherwise.
@@ -337266,6 +338363,12 @@ ${sections.join("\n")}
337266
338363
  if (this.getWorkspaceContext().isPathReadable(absolutePath)) {
337267
338364
  return null;
337268
338365
  }
338366
+ if (hasScopedMemoryInboxAccess()) {
338367
+ const inboxRoot = path76.join(this.storage.getProjectMemoryTempDir(), ".inbox");
338368
+ if (this.isScopedMemoryInboxPatchPathAllowed(absolutePath, resolveToRealPath(absolutePath), inboxRoot, "read")) {
338369
+ return null;
338370
+ }
338371
+ }
337269
338372
  }
337270
338373
  if (this.isPathAllowed(absolutePath)) {
337271
338374
  return null;
@@ -337592,10 +338695,10 @@ ${sections.join("\n")}
337592
338695
  return this.gemmaModelRouter;
337593
338696
  }
337594
338697
  getAgentSessionNoninteractiveEnabled() {
337595
- return this.agentSessionNoninteractiveEnabled;
338698
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionNoninteractiveEnabled;
337596
338699
  }
337597
338700
  getAgentSessionInteractiveEnabled() {
337598
- return this.agentSessionInteractiveEnabled;
338701
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionInteractiveEnabled;
337599
338702
  }
337600
338703
  /**
337601
338704
  * Get override settings for a specific agent.
@@ -338560,11 +339663,228 @@ async function isProjectSkillPatchTarget(targetPath, config2) {
338560
339663
  function hasParsedPatchHunks(parsedPatches) {
338561
339664
  return parsedPatches.length > 0 && parsedPatches.every((patch) => patch.hunks.length > 0);
338562
339665
  }
339666
+ function getMemoryPatchRoot(memoryDir, kind) {
339667
+ return path80.join(memoryDir, ".inbox", kind);
339668
+ }
339669
+ function isSubpathOrSame(childPath, parentPath) {
339670
+ return isSubpath(parentPath, childPath);
339671
+ }
339672
+ function normalizeInboxMemoryPatchPath(relativePath) {
339673
+ if (relativePath.length === 0 || path80.isAbsolute(relativePath) || relativePath.includes("\\")) {
339674
+ return void 0;
339675
+ }
339676
+ const normalizedPath = path80.posix.normalize(relativePath);
339677
+ if (normalizedPath === "." || normalizedPath.startsWith("../") || normalizedPath === ".." || !normalizedPath.endsWith(".patch")) {
339678
+ return void 0;
339679
+ }
339680
+ return normalizedPath;
339681
+ }
339682
+ function getAllowedMemoryPatchRoots(config2, kind) {
339683
+ switch (kind) {
339684
+ case "private":
339685
+ return [path80.resolve(config2.storage.getProjectMemoryTempDir())];
339686
+ case "global":
339687
+ return [path80.resolve(getGlobalMemoryFilePath())];
339688
+ default:
339689
+ throw new Error(`Unknown memory patch kind: ${kind}`);
339690
+ }
339691
+ }
339692
+ function hasMarkdownExtension(fileName) {
339693
+ return fileName.toLowerCase().endsWith(".md");
339694
+ }
339695
+ function isAllowedPrivateMemoryFileName(fileName) {
339696
+ if (fileName === PROJECT_MEMORY_INDEX_FILENAME) {
339697
+ return true;
339698
+ }
339699
+ return !fileName.startsWith(".") && hasMarkdownExtension(fileName);
339700
+ }
339701
+ function uniqueResolvedPaths(paths) {
339702
+ return Array.from(new Set(paths.map((filePath) => path80.resolve(filePath))));
339703
+ }
339704
+ function isSamePath(leftPath, rightPath) {
339705
+ return isSubpath(leftPath, rightPath) && isSubpath(rightPath, leftPath);
339706
+ }
339707
+ function includesSamePath(paths, targetPath) {
339708
+ return paths.some((candidate) => isSamePath(candidate, targetPath));
339709
+ }
339710
+ function isAllowedPrivateMemoryDocumentPath(targetPath, memoryDirs) {
339711
+ const resolvedTargetPath = path80.resolve(targetPath);
339712
+ const targetDir = path80.dirname(resolvedTargetPath);
339713
+ if (!includesSamePath(memoryDirs, targetDir)) {
339714
+ return false;
339715
+ }
339716
+ return isAllowedPrivateMemoryFileName(path80.basename(resolvedTargetPath));
339717
+ }
339718
+ function isAllowedGlobalMemoryDocumentPath(targetPath, globalMemoryFiles) {
339719
+ const resolvedTargetPath = path80.resolve(targetPath);
339720
+ return includesSamePath(globalMemoryFiles, resolvedTargetPath);
339721
+ }
339722
+ async function getMemoryPatchTargetValidationContext(config2, kind) {
339723
+ const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
339724
+ if (kind === "global") {
339725
+ const rawGlobalMemoryFile = path80.resolve(getGlobalMemoryFilePath());
339726
+ const canonicalGlobalMemoryFiles = await canonicalizeAllowedPatchRoots([
339727
+ rawGlobalMemoryFile
339728
+ ]);
339729
+ return {
339730
+ kind,
339731
+ allowedRoots,
339732
+ privateMemoryDirs: [],
339733
+ globalMemoryFiles: uniqueResolvedPaths([
339734
+ rawGlobalMemoryFile,
339735
+ ...canonicalGlobalMemoryFiles
339736
+ ])
339737
+ };
339738
+ }
339739
+ const rawPrivateMemoryDir = path80.resolve(config2.storage.getProjectMemoryTempDir());
339740
+ const canonicalPrivateMemoryDirs = await canonicalizeAllowedPatchRoots([
339741
+ rawPrivateMemoryDir
339742
+ ]);
339743
+ const privateMemoryDirs = uniqueResolvedPaths([
339744
+ rawPrivateMemoryDir,
339745
+ ...canonicalPrivateMemoryDirs
339746
+ ]);
339747
+ return { kind, allowedRoots, privateMemoryDirs, globalMemoryFiles: [] };
339748
+ }
339749
+ function isResolvedMemoryPatchTargetAllowed(resolvedTargetPath, context2) {
339750
+ if (context2.kind === "global") {
339751
+ return isAllowedGlobalMemoryDocumentPath(resolvedTargetPath, context2.globalMemoryFiles);
339752
+ }
339753
+ if (context2.kind === "private") {
339754
+ return isAllowedPrivateMemoryDocumentPath(resolvedTargetPath, context2.privateMemoryDirs);
339755
+ }
339756
+ return true;
339757
+ }
339758
+ async function resolveMemoryPatchTargetWithinAllowedSet(targetPath, context2) {
339759
+ const resolvedTargetPath = await resolveTargetWithinAllowedRoots(targetPath, context2.allowedRoots);
339760
+ if (!resolvedTargetPath) {
339761
+ return void 0;
339762
+ }
339763
+ if (context2.kind === "private" && (!isAllowedPrivateMemoryDocumentPath(targetPath, context2.privateMemoryDirs) || !isAllowedPrivateMemoryDocumentPath(resolvedTargetPath, context2.privateMemoryDirs))) {
339764
+ return void 0;
339765
+ }
339766
+ if (context2.kind === "global" && (!isAllowedGlobalMemoryDocumentPath(targetPath, context2.globalMemoryFiles) || !isAllowedGlobalMemoryDocumentPath(resolvedTargetPath, context2.globalMemoryFiles))) {
339767
+ return void 0;
339768
+ }
339769
+ return resolvedTargetPath;
339770
+ }
339771
+ async function findDisallowedMemoryPatchTarget(parsedPatches, context2) {
339772
+ const validated = validateParsedSkillPatchHeaders(parsedPatches);
339773
+ if (!validated.success) {
339774
+ return void 0;
339775
+ }
339776
+ for (const header of validated.patches) {
339777
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, context2)) {
339778
+ return header.targetPath;
339779
+ }
339780
+ }
339781
+ return void 0;
339782
+ }
339783
+ async function getInboxMemoryPatchSourcePath(config2, kind, relativePath) {
339784
+ const normalizedPath = normalizeInboxMemoryPatchPath(relativePath);
339785
+ if (!normalizedPath) {
339786
+ return void 0;
339787
+ }
339788
+ const patchRoot = path80.resolve(getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind));
339789
+ const sourcePath = path80.resolve(patchRoot, ...normalizedPath.split("/"));
339790
+ if (!isSubpathOrSame(sourcePath, patchRoot)) {
339791
+ return void 0;
339792
+ }
339793
+ return sourcePath;
339794
+ }
339795
+ async function listInboxPatchFiles(config2, kind) {
339796
+ const patchRoot = getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind);
339797
+ const found = [];
339798
+ async function walk(currentDir) {
339799
+ let dirEntries;
339800
+ try {
339801
+ dirEntries = await fs71.readdir(currentDir, { withFileTypes: true });
339802
+ } catch {
339803
+ return;
339804
+ }
339805
+ for (const entry of dirEntries) {
339806
+ const entryPath = path80.join(currentDir, entry.name);
339807
+ if (entry.isDirectory()) {
339808
+ await walk(entryPath);
339809
+ continue;
339810
+ }
339811
+ if (entry.isFile() && entry.name.endsWith(".patch")) {
339812
+ found.push(entryPath);
339813
+ }
339814
+ }
339815
+ }
339816
+ await walk(patchRoot);
339817
+ return found.sort();
339818
+ }
339819
+ async function validateInboxMemoryPatchFile(config2, kind, sourcePath) {
339820
+ let content;
339821
+ try {
339822
+ content = await fs71.readFile(sourcePath, "utf-8");
339823
+ } catch (error40) {
339824
+ return {
339825
+ valid: false,
339826
+ reason: `failed to read patch: ${error40 instanceof Error ? error40.message : String(error40)}`
339827
+ };
339828
+ }
339829
+ let parsed;
339830
+ try {
339831
+ parsed = parsePatch(content);
339832
+ } catch (error40) {
339833
+ return {
339834
+ valid: false,
339835
+ reason: `failed to parse patch: ${error40 instanceof Error ? error40.message : String(error40)}`
339836
+ };
339837
+ }
339838
+ if (!hasParsedPatchHunks(parsed)) {
339839
+ return { valid: false, reason: "no hunks found in patch" };
339840
+ }
339841
+ const validated = validateParsedSkillPatchHeaders(parsed);
339842
+ if (!validated.success) {
339843
+ switch (validated.reason) {
339844
+ case "missingTargetPath":
339845
+ return {
339846
+ valid: false,
339847
+ reason: "missing target file path in patch header"
339848
+ };
339849
+ case "invalidPatchHeaders":
339850
+ return {
339851
+ valid: false,
339852
+ reason: `invalid diff headers${validated.targetPath ? `: ${validated.targetPath}` : ""}`
339853
+ };
339854
+ default:
339855
+ return { valid: false, reason: "invalid patch headers" };
339856
+ }
339857
+ }
339858
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
339859
+ for (const header of validated.patches) {
339860
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, validationContext)) {
339861
+ return {
339862
+ valid: false,
339863
+ reason: `target file is outside ${kind} memory roots: ${header.targetPath}`
339864
+ };
339865
+ }
339866
+ }
339867
+ return { valid: true };
339868
+ }
339869
+ async function listValidInboxPatchFiles(config2, kind) {
339870
+ const patchFiles = await listInboxPatchFiles(config2, kind);
339871
+ if (patchFiles.length === 0) {
339872
+ return [];
339873
+ }
339874
+ const valid = [];
339875
+ for (const sourcePath of patchFiles) {
339876
+ const validation = await validateInboxMemoryPatchFile(config2, kind, sourcePath);
339877
+ if (validation.valid) {
339878
+ valid.push(sourcePath);
339879
+ }
339880
+ }
339881
+ return valid;
339882
+ }
338563
339883
  async function applyParsedSkillPatches(parsedPatches, config2) {
338564
339884
  const allowedRoots = await getCanonicalAllowedSkillPatchRoots(config2);
338565
339885
  return applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots);
338566
339886
  }
338567
- async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
339887
+ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots, options = {}) {
338568
339888
  const results = /* @__PURE__ */ new Map();
338569
339889
  const patchedContentByTarget = /* @__PURE__ */ new Map();
338570
339890
  const originalContentByTarget = /* @__PURE__ */ new Map();
@@ -338575,7 +339895,7 @@ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
338575
339895
  for (const [index, patch] of parsedPatches.entries()) {
338576
339896
  const { targetPath, isNewFile } = validatedHeaders.patches[index];
338577
339897
  const resolvedTargetPath = await resolveTargetWithinAllowedRoots(targetPath, allowedRoots);
338578
- if (!resolvedTargetPath) {
339898
+ if (!resolvedTargetPath || options.isResolvedTargetAllowed && !options.isResolvedTargetAllowed(resolvedTargetPath)) {
338579
339899
  return {
338580
339900
  success: false,
338581
339901
  reason: "outsideAllowedRoots",
@@ -339031,6 +340351,7 @@ var SkillExtractionAgent = (skillsDir, sessionIndex, existingSkillsSummary, memo
339031
340351
  },
339032
340352
  memoryInboxAccess: true,
339033
340353
  autoMemoryExtractionWriteAccess: true,
340354
+ includeExtensionContext: false,
339034
340355
  toolConfig: {
339035
340356
  tools: [
339036
340357
  ACTIVATE_SKILL_TOOL_NAME,
@@ -339756,6 +341077,28 @@ async function snapshotFiles(rootDir, shouldIncludeFile = () => true, shouldDesc
339756
341077
  async function snapshotInboxCandidates(memoryDir) {
339757
341078
  return snapshotFiles(path81.join(memoryDir, ".inbox"));
339758
341079
  }
341080
+ var MEMORY_INBOX_PATCH_KINDS = [
341081
+ "private",
341082
+ "global"
341083
+ ];
341084
+ async function validateMemoryInboxPatches(config2) {
341085
+ for (const kind of MEMORY_INBOX_PATCH_KINDS) {
341086
+ const patchFiles = await listInboxPatchFiles(config2, kind);
341087
+ for (const patchFile of patchFiles) {
341088
+ const validation = await validateInboxMemoryPatchFile(config2, kind, patchFile);
341089
+ if (validation.valid) {
341090
+ continue;
341091
+ }
341092
+ try {
341093
+ await fs72.unlink(patchFile);
341094
+ debugLogger.warn(`[MemoryService] Dropped invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}`);
341095
+ } catch (error40) {
341096
+ const message = error40 instanceof Error ? error40.message : String(error40);
341097
+ debugLogger.warn(`[MemoryService] Failed to drop invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}; unlink failed: ${message}`);
341098
+ }
341099
+ }
341100
+ }
341101
+ }
339759
341102
  async function buildPendingInboxSummary(memoryDir) {
339760
341103
  const sections = [];
339761
341104
  for (const kind of ["private", "global"]) {
@@ -339964,6 +341307,7 @@ ${pendingInboxSummary}`);
339964
341307
  if (validPatches.length > 0) {
339965
341308
  debugLogger.log(`[MemoryService] ${validPatches.length} valid patch(es) currently in inbox; ${patchesCreatedThisRun.length} created or updated this run`);
339966
341309
  }
341310
+ await validateMemoryInboxPatches(config2);
339967
341311
  const memoryFilesUpdated = [];
339968
341312
  const memoryCandidatesCreated = prefixRelativePaths(".inbox", getChangedSnapshotPaths(diffFileSnapshots(inboxCandidatesBefore, await snapshotInboxCandidates(memoryDir))));
339969
341313
  const processedSessions = candidateSessions.filter((session) => processedSessionKeys.has(getSessionVersionKey(session))).map((session) => ({
@@ -340249,33 +341593,6 @@ function formatParsedDiff(parsed) {
340249
341593
  function getErrorMessage4(error40) {
340250
341594
  return error40 instanceof Error ? error40.message : String(error40);
340251
341595
  }
340252
- function getMemoryPatchRoot(memoryDir, kind) {
340253
- return path82.join(memoryDir, ".inbox", kind);
340254
- }
340255
- function isSubpathOrSame(childPath, parentPath) {
340256
- const relativePath = path82.relative(parentPath, childPath);
340257
- return relativePath === "" || !relativePath.startsWith("..") && !path82.isAbsolute(relativePath);
340258
- }
340259
- function normalizeInboxMemoryPatchPath(relativePath) {
340260
- if (relativePath.length === 0 || path82.isAbsolute(relativePath) || relativePath.includes("\\")) {
340261
- return void 0;
340262
- }
340263
- const normalizedPath = path82.posix.normalize(relativePath);
340264
- if (normalizedPath === "." || normalizedPath.startsWith("../") || normalizedPath === ".." || !normalizedPath.endsWith(".patch")) {
340265
- return void 0;
340266
- }
340267
- return normalizedPath;
340268
- }
340269
- function getAllowedMemoryPatchRoots(config2, kind) {
340270
- switch (kind) {
340271
- case "private":
340272
- return [path82.resolve(config2.storage.getProjectMemoryTempDir())];
340273
- case "global":
340274
- return [path82.resolve(getGlobalMemoryFilePath())];
340275
- default:
340276
- throw new Error(`Unknown memory patch kind: ${kind}`);
340277
- }
340278
- }
340279
341596
  async function getFileMtimeIso(filePath) {
340280
341597
  try {
340281
341598
  const stats = await fs73.stat(filePath);
@@ -340284,18 +341601,6 @@ async function getFileMtimeIso(filePath) {
340284
341601
  return void 0;
340285
341602
  }
340286
341603
  }
340287
- async function getInboxMemoryPatchSourcePath(config2, kind, relativePath) {
340288
- const normalizedPath = normalizeInboxMemoryPatchPath(relativePath);
340289
- if (!normalizedPath) {
340290
- return void 0;
340291
- }
340292
- const patchRoot = path82.resolve(getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind));
340293
- const sourcePath = path82.resolve(patchRoot, ...normalizedPath.split("/"));
340294
- if (!isSubpathOrSame(sourcePath, patchRoot)) {
340295
- return void 0;
340296
- }
340297
- return sourcePath;
340298
- }
340299
341604
  async function patchTargetsProjectSkills(targetPaths, config2) {
340300
341605
  for (const targetPath of targetPaths) {
340301
341606
  if (await isProjectSkillPatchTarget(targetPath, config2)) {
@@ -340322,70 +341627,11 @@ function formatMemoryKindLabel(kind) {
340322
341627
  return kind;
340323
341628
  }
340324
341629
  }
340325
- async function listInboxPatchFiles(config2, kind) {
340326
- const patchRoot = getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind);
340327
- const found = [];
340328
- async function walk(currentDir) {
340329
- let dirEntries;
340330
- try {
340331
- dirEntries = await fs73.readdir(currentDir, { withFileTypes: true });
340332
- } catch {
340333
- return;
340334
- }
340335
- for (const entry of dirEntries) {
340336
- const entryPath = path82.join(currentDir, entry.name);
340337
- if (entry.isDirectory()) {
340338
- await walk(entryPath);
340339
- continue;
340340
- }
340341
- if (entry.isFile() && entry.name.endsWith(".patch")) {
340342
- found.push(entryPath);
340343
- }
340344
- }
340345
- }
340346
- await walk(patchRoot);
340347
- return found.sort();
340348
- }
340349
- async function listValidInboxPatchFiles(config2, kind) {
340350
- const patchFiles = await listInboxPatchFiles(config2, kind);
340351
- if (patchFiles.length === 0) {
340352
- return [];
340353
- }
340354
- const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
340355
- const valid = [];
340356
- for (const sourcePath of patchFiles) {
340357
- let content;
340358
- try {
340359
- content = await fs73.readFile(sourcePath, "utf-8");
340360
- } catch {
340361
- continue;
340362
- }
340363
- let parsed;
340364
- try {
340365
- parsed = parsePatch(content);
340366
- } catch {
340367
- continue;
340368
- }
340369
- if (!hasParsedPatchHunks(parsed)) {
340370
- continue;
340371
- }
340372
- const validated = validateParsedSkillPatchHeaders(parsed);
340373
- if (!validated.success) {
340374
- continue;
340375
- }
340376
- const targetsAllAllowed = await Promise.all(validated.patches.map(async (header) => await resolveTargetWithinAllowedRoots(header.targetPath, allowedRoots) !== void 0));
340377
- if (!targetsAllAllowed.every(Boolean)) {
340378
- continue;
340379
- }
340380
- valid.push(sourcePath);
340381
- }
340382
- return valid;
340383
- }
340384
341630
  async function listInboxMemoryPatches(config2) {
340385
341631
  const kinds = ["private", "global"];
340386
341632
  const aggregated = [];
340387
341633
  for (const kind of kinds) {
340388
- const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
341634
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
340389
341635
  const patchFiles = await listInboxPatchFiles(config2, kind);
340390
341636
  const aggregatedEntries = [];
340391
341637
  const sourceFiles = [];
@@ -340410,7 +341656,7 @@ async function listInboxMemoryPatches(config2) {
340410
341656
  if (!validated.success) {
340411
341657
  continue;
340412
341658
  }
340413
- const targetsAllAllowed = await Promise.all(validated.patches.map(async (header) => await resolveTargetWithinAllowedRoots(header.targetPath, allowedRoots) !== void 0));
341659
+ const targetsAllAllowed = await Promise.all(validated.patches.map(async (header) => await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, validationContext) !== void 0));
340414
341660
  if (!targetsAllAllowed.every(Boolean)) {
340415
341661
  continue;
340416
341662
  }
@@ -340591,8 +341837,17 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
340591
341837
  message: `Memory patch "${displayName}" contains no valid hunks.`
340592
341838
  };
340593
341839
  }
340594
- const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
340595
- const applied = await applyParsedPatchesWithAllowedRoots(parsed, allowedRoots);
341840
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
341841
+ const disallowedTargetPath = await findDisallowedMemoryPatchTarget(parsed, validationContext);
341842
+ if (disallowedTargetPath) {
341843
+ return {
341844
+ success: false,
341845
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${disallowedTargetPath}`
341846
+ };
341847
+ }
341848
+ const applied = await applyParsedPatchesWithAllowedRoots(parsed, validationContext.allowedRoots, {
341849
+ isResolvedTargetAllowed: (resolvedTargetPath) => isResolvedMemoryPatchTargetAllowed(resolvedTargetPath, validationContext)
341850
+ });
340596
341851
  if (!applied.success) {
340597
341852
  switch (applied.reason) {
340598
341853
  case "missingTargetPath":
@@ -340608,7 +341863,7 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
340608
341863
  case "outsideAllowedRoots":
340609
341864
  return {
340610
341865
  success: false,
340611
- message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root: ${applied.targetPath}`
341866
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${applied.targetPath}`
340612
341867
  };
340613
341868
  case "newFileAlreadyExists":
340614
341869
  return {
@@ -341482,8 +342737,9 @@ function loadIgnoreRules(service, ignoreDirs = []) {
341482
342737
  const ignorer = new Ignore2();
341483
342738
  const ignoreFiles = service.getAllIgnoreFilePaths();
341484
342739
  for (const filePath of ignoreFiles) {
341485
- if (fs75.existsSync(filePath)) {
342740
+ try {
341486
342741
  ignorer.add(fs75.readFileSync(filePath, "utf8"));
342742
+ } catch {
341487
342743
  }
341488
342744
  }
341489
342745
  const allIgnoreDirs = [".git", ...ignoreDirs];
@@ -342641,11 +343897,11 @@ var AsyncFzf = class {
342641
343897
  // packages/core/node_modules/chokidar/index.js
342642
343898
  import { EventEmitter as EventEmitter8 } from "node:events";
342643
343899
  import { stat as statcb, Stats } from "node:fs";
342644
- import { readdir as readdir10, stat as stat7 } from "node:fs/promises";
343900
+ import { readdir as readdir11, stat as stat7 } from "node:fs/promises";
342645
343901
  import * as sp2 from "node:path";
342646
343902
 
342647
343903
  // packages/core/node_modules/readdirp/index.js
342648
- import { lstat as lstat3, readdir as readdir9, realpath as realpath4, stat as stat5 } from "node:fs/promises";
343904
+ import { lstat as lstat3, readdir as readdir10, realpath as realpath4, stat as stat5 } from "node:fs/promises";
342649
343905
  import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "node:path";
342650
343906
  import { Readable as Readable3 } from "node:stream";
342651
343907
  var EntryTypes = {
@@ -342797,7 +344053,7 @@ var ReaddirpStream = class extends Readable3 {
342797
344053
  async _exploreDir(path101, depth) {
342798
344054
  let files;
342799
344055
  try {
342800
- files = await readdir9(path101, this._rdOptions);
344056
+ files = await readdir10(path101, this._rdOptions);
342801
344057
  } catch (error40) {
342802
344058
  this._onError(error40);
342803
344059
  }
@@ -343662,11 +344918,11 @@ function createPattern(matcher) {
343662
344918
  if (matcher.path === string4)
343663
344919
  return true;
343664
344920
  if (matcher.recursive) {
343665
- const relative12 = sp2.relative(matcher.path, string4);
343666
- if (!relative12) {
344921
+ const relative11 = sp2.relative(matcher.path, string4);
344922
+ if (!relative11) {
343667
344923
  return false;
343668
344924
  }
343669
- return !relative12.startsWith("..") && !sp2.isAbsolute(relative12);
344925
+ return !relative11.startsWith("..") && !sp2.isAbsolute(relative11);
343670
344926
  }
343671
344927
  return false;
343672
344928
  };
@@ -343768,7 +345024,7 @@ var DirEntry = class {
343768
345024
  return;
343769
345025
  const dir = this.path;
343770
345026
  try {
343771
- await readdir10(dir);
345027
+ await readdir11(dir);
343772
345028
  } catch (err2) {
343773
345029
  if (this._removeWatcher) {
343774
345030
  this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
@@ -344614,13 +345870,23 @@ var RecursiveFileSearch = class {
344614
345870
  if (pattern.includes("*") || !this.fzf) {
344615
345871
  filteredCandidates = await filter3(candidates, pattern, options.signal);
344616
345872
  } else {
344617
- filteredCandidates = await this.fzf.find(pattern).then((results2) => (
344618
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
344619
- results2.map((entry) => entry.item)
344620
- )).catch(() => {
345873
+ try {
345874
+ const fzfResult = await this.fzf.find(pattern);
345875
+ if (Array.isArray(fzfResult)) {
345876
+ filteredCandidates = fzfResult.map((entry) => {
345877
+ if (typeof entry === "object" && entry !== null && "item" in entry) {
345878
+ return String(entry.item);
345879
+ }
345880
+ return String(entry);
345881
+ });
345882
+ } else {
345883
+ shouldCache = false;
345884
+ filteredCandidates = [];
345885
+ }
345886
+ } catch {
344621
345887
  shouldCache = false;
344622
- return [];
344623
- });
345888
+ filteredCandidates = [];
345889
+ }
344624
345890
  }
344625
345891
  if (shouldCache) {
344626
345892
  this.resultCache.set(pattern, filteredCandidates);
@@ -345224,8 +346490,8 @@ function normalizePathCandidate(candidate, projectRoot) {
345224
346490
  }
345225
346491
  let normalized2 = trimmed2.replace(/\\/g, "/");
345226
346492
  if (path88.isAbsolute(trimmed2)) {
345227
- const relative12 = path88.relative(projectRoot, trimmed2);
345228
- normalized2 = relative12 && !relative12.startsWith("..") && !path88.isAbsolute(relative12) ? relative12.replace(/\\/g, "/") : path88.basename(trimmed2);
346493
+ const relative11 = path88.relative(projectRoot, trimmed2);
346494
+ normalized2 = relative11 && !relative11.startsWith("..") && !path88.isAbsolute(relative11) ? relative11.replace(/\\/g, "/") : path88.basename(trimmed2);
345229
346495
  }
345230
346496
  if (normalized2.length > 120) {
345231
346497
  normalized2 = normalized2.split("/").slice(-3).join("/");
@@ -345940,6 +347206,7 @@ function contentPartsToGeminiParts(content) {
345940
347206
  result2.push({ text: part.text });
345941
347207
  break;
345942
347208
  default:
347209
+ debugLogger.warn(`Unhandled ContentPart type: ${JSON.stringify(part)} fallback to serialization`);
345943
347210
  result2.push({ text: JSON.stringify(part) });
345944
347211
  break;
345945
347212
  }
@@ -345959,50 +347226,6 @@ function buildToolResponseData(response) {
345959
347226
  return Object.keys(parts2).length > 0 ? parts2 : void 0;
345960
347227
  }
345961
347228
 
345962
- // packages/core/dist/src/agent/tool-display-utils.js
345963
- function populateToolDisplay({ name: name3, invocation, resultDisplay, displayName }) {
345964
- const display = {
345965
- name: displayName || name3,
345966
- description: invocation?.getDescription?.()
345967
- };
345968
- if (resultDisplay) {
345969
- display.result = toolResultDisplayToDisplayContent(resultDisplay);
345970
- }
345971
- return display;
345972
- }
345973
- function toolResultDisplayToDisplayContent(resultDisplay) {
345974
- if (typeof resultDisplay === "string") {
345975
- return { type: "text", text: resultDisplay };
345976
- }
345977
- if (typeof resultDisplay === "object" && resultDisplay !== null && "fileDiff" in resultDisplay && "newContent" in resultDisplay) {
345978
- return {
345979
- type: "diff",
345980
- path: resultDisplay.filePath || resultDisplay.fileName,
345981
- beforeText: resultDisplay.originalContent ?? "",
345982
- afterText: resultDisplay.newContent
345983
- };
345984
- }
345985
- return {
345986
- type: "text",
345987
- text: JSON.stringify(resultDisplay)
345988
- };
345989
- }
345990
- function renderDisplayDiff(diff) {
345991
- return createPatch(diff.path || "file", diff.beforeText, diff.afterText, "Original", "Modified", { context: 3 });
345992
- }
345993
- function displayContentToString(display) {
345994
- if (!display) {
345995
- return void 0;
345996
- }
345997
- if (display.type === "text") {
345998
- return display.text;
345999
- }
346000
- if (display.type === "diff") {
346001
- return renderDisplayDiff(display);
346002
- }
346003
- return JSON.stringify(display);
346004
- }
346005
-
346006
347229
  // packages/core/dist/src/agent/event-translator.js
346007
347230
  function createTranslationState(streamId) {
346008
347231
  return {
@@ -346130,15 +347353,16 @@ function translateEvent(event, state) {
346130
347353
  out2.push(makeEvent("tool_request", state, {
346131
347354
  requestId: event.value.callId,
346132
347355
  name: event.value.name,
346133
- args: event.value.args
347356
+ args: event.value.args,
347357
+ display: event.value.display
346134
347358
  }));
346135
347359
  break;
346136
347360
  case GeminiEventType.ToolCallResponse: {
346137
347361
  ensureStreamStart(state, out2);
346138
347362
  const data = buildToolResponseData(event.value);
346139
- const display = event.value.resultDisplay ? {
347363
+ const display = event.value.display ?? (event.value.resultDisplay ? {
346140
347364
  result: toolResultDisplayToDisplayContent(event.value.resultDisplay)
346141
- } : void 0;
347365
+ } : void 0);
346142
347366
  out2.push(makeEvent("tool_response", state, {
346143
347367
  requestId: event.value.callId,
346144
347368
  name: state.pendingToolNames.get(event.value.callId) ?? "unknown",
@@ -346160,7 +347384,6 @@ function translateEvent(event, state) {
346160
347384
  ((x) => {
346161
347385
  throw new Error(`Unhandled event type: ${JSON.stringify(x)}`);
346162
347386
  })(event);
346163
- break;
346164
347387
  }
346165
347388
  return out2;
346166
347389
  }
@@ -346360,6 +347583,7 @@ var LegacyAgentProtocol = class {
346360
347583
  } else {
346361
347584
  this._emitErrorAndAgentEnd(err2);
346362
347585
  }
347586
+ } finally {
346363
347587
  this._clearActiveStream();
346364
347588
  }
346365
347589
  }
@@ -346433,7 +347657,8 @@ var LegacyAgentProtocol = class {
346433
347657
  name: request.name,
346434
347658
  invocation: "invocation" in tc ? tc.invocation : void 0,
346435
347659
  resultDisplay: response.resultDisplay,
346436
- displayName: "tool" in tc ? tc.tool?.displayName : void 0
347660
+ displayName: "tool" in tc ? tc.tool?.displayName : void 0,
347661
+ display: response.display
346437
347662
  });
346438
347663
  const data = buildToolResponseData(response);
346439
347664
  this._emit([
@@ -346527,6 +347752,7 @@ var LegacyAgentProtocol = class {
346527
347752
  const meta = {};
346528
347753
  if (err2 instanceof Error) {
346529
347754
  meta["errorName"] = err2.constructor.name;
347755
+ meta["stack"] = err2.stack;
346530
347756
  if ("exitCode" in err2 && typeof err2.exitCode === "number") {
346531
347757
  meta["exitCode"] = err2.exitCode;
346532
347758
  }
@@ -349214,7 +350440,7 @@ var ENCODING_ALIASES = {
349214
350440
  var serializeEncoding = (encoding) => typeof encoding === "string" ? `"${encoding}"` : String(encoding);
349215
350441
 
349216
350442
  // node_modules/execa/lib/arguments/cwd.js
349217
- import { statSync as statSync3 } from "node:fs";
350443
+ import { statSync as statSync4 } from "node:fs";
349218
350444
  import path94 from "node:path";
349219
350445
  import process20 from "node:process";
349220
350446
  var normalizeCwd = (cwd = getDefaultCwd()) => {
@@ -349236,7 +350462,7 @@ var fixCwdError = (originalMessage, cwd) => {
349236
350462
  }
349237
350463
  let cwdStat;
349238
350464
  try {
349239
- cwdStat = statSync3(cwd);
350465
+ cwdStat = statSync4(cwd);
349240
350466
  } catch (error40) {
349241
350467
  return `The "cwd" option is invalid: ${cwd}.
349242
350468
  ${error40.message}
@@ -353892,8 +355118,8 @@ function isGeminiWorktree(dirPath, projectRoot) {
353892
355118
  const realDirPath = realpathSync4(dirPath);
353893
355119
  const realProjectRoot = realpathSync4(projectRoot);
353894
355120
  const worktreesBaseDir = path96.join(realProjectRoot, ".gemini", "worktrees");
353895
- const relative12 = path96.relative(worktreesBaseDir, realDirPath);
353896
- return !relative12.startsWith("..") && !path96.isAbsolute(relative12);
355121
+ const relative11 = path96.relative(worktreesBaseDir, realDirPath);
355122
+ return !relative11.startsWith("..") && !path96.isAbsolute(relative11);
353897
355123
  } catch {
353898
355124
  return false;
353899
355125
  }
@@ -355224,6 +356450,7 @@ export {
355224
356450
  CacheService,
355225
356451
  createCache,
355226
356452
  ProjectIdRequiredError,
356453
+ InvalidNumericProjectIdError,
355227
356454
  ValidationCancelledError,
355228
356455
  IneligibleTierError,
355229
356456
  resetUserDataCacheForTesting,
@@ -355311,6 +356538,11 @@ export {
355311
356538
  GeminiChat,
355312
356539
  isSchemaDepthError,
355313
356540
  isInvalidArgumentError,
356541
+ stripToolCallIdPrefixes,
356542
+ populateToolDisplay,
356543
+ toolResultDisplayToDisplayContent,
356544
+ renderDisplayDiff,
356545
+ displayContentToString,
355314
356546
  GeminiEventType,
355315
356547
  CompressionStatus,
355316
356548
  Turn,
@@ -355348,6 +356580,7 @@ export {
355348
356580
  SubagentActivityErrorType,
355349
356581
  SUBAGENT_REJECTED_ERROR_PREFIX,
355350
356582
  SUBAGENT_CANCELLED_ERROR_MESSAGE,
356583
+ SubagentState,
355351
356584
  isSubagentProgress,
355352
356585
  isToolActivityError,
355353
356586
  getAgentCardLoadOptions,
@@ -355377,6 +356610,16 @@ export {
355377
356610
  getPolicyDenialError,
355378
356611
  checkPolicy,
355379
356612
  updatePolicy,
356613
+ NodeType,
356614
+ isAgentThought,
356615
+ isAgentYield,
356616
+ isToolExecution,
356617
+ isMaskedTool,
356618
+ isUserPrompt,
356619
+ isSystemEvent,
356620
+ isSnapshot,
356621
+ isRollingSummary,
356622
+ SnapshotGenerator,
355380
356623
  generalistProfile,
355381
356624
  stressTestProfile,
355382
356625
  GeminiClient,
@@ -355522,6 +356765,7 @@ export {
355522
356765
  performRestore,
355523
356766
  performInit,
355524
356767
  isProjectSkillPatchTarget,
356768
+ getAllowedMemoryPatchRoots,
355525
356769
  validatePatches,
355526
356770
  startMemoryService,
355527
356771
  showMemory,
@@ -355531,7 +356775,6 @@ export {
355531
356775
  listInboxSkills,
355532
356776
  moveInboxSkill,
355533
356777
  dismissInboxSkill,
355534
- getAllowedMemoryPatchRoots,
355535
356778
  listInboxMemoryPatches,
355536
356779
  applyInboxMemoryPatch,
355537
356780
  dismissInboxMemoryPatch,
@@ -355567,10 +356810,6 @@ export {
355567
356810
  geminiPartsToContentParts,
355568
356811
  contentPartsToGeminiParts,
355569
356812
  buildToolResponseData,
355570
- populateToolDisplay,
355571
- toolResultDisplayToDisplayContent,
355572
- renderDisplayDiff,
355573
- displayContentToString,
355574
356813
  createTranslationState,
355575
356814
  translateEvent,
355576
356815
  mapFinishReason,