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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/bundle/{chunk-AS4E6DX7.js → chunk-43AGRA7S.js} +3 -3
  2. package/bundle/{chunk-UZZVXATH.js → chunk-46T44JOY.js} +1 -1
  3. package/bundle/{chunk-BI5ZICGL.js → chunk-4TLQKGTR.js} +1 -1
  4. package/bundle/{chunk-BZZHETT5.js → chunk-6XOSIMPZ.js} +8 -9
  5. package/bundle/{chunk-6K3EFSDX.js → chunk-HQXINMBL.js} +2 -2
  6. package/bundle/{chunk-I5JMJ2LU.js → chunk-JENIU3E3.js} +1 -1
  7. package/bundle/{chunk-LK7LIPO6.js → chunk-LBQFRHYD.js} +1 -1
  8. package/bundle/{chunk-5AFGMGVT.js → chunk-LFGJVOVZ.js} +486 -381
  9. package/bundle/{chunk-UVBJHP26.js → chunk-MRHFLHPJ.js} +2 -2
  10. package/bundle/{chunk-7LOMS5HP.js → chunk-MXKXLNQD.js} +3 -3
  11. package/bundle/{chunk-ECNYAST2.js → chunk-N6QYTC2T.js} +5417 -5376
  12. package/bundle/{chunk-QZ2JZRLK.js → chunk-NBRZ4A3S.js} +2170 -791
  13. package/bundle/{chunk-L7GACEVA.js → chunk-P4UQCQUB.js} +3 -3
  14. package/bundle/{chunk-NHDN46IK.js → chunk-PGJUNQPO.js} +34 -16
  15. package/bundle/{chunk-GZ4FSF4B.js → chunk-PSWUV2OO.js} +3 -3
  16. package/bundle/{chunk-UKCYYERR.js → chunk-PYLHDAUK.js} +3 -3
  17. package/bundle/{chunk-47QC6PWE.js → chunk-Q23X5R4A.js} +486 -381
  18. package/bundle/{chunk-VERP26KN.js → chunk-QYUN3J2L.js} +533 -441
  19. package/bundle/{chunk-A564QXJJ.js → chunk-SAISHGWW.js} +1907 -716
  20. package/bundle/{chunk-IBIKJW2L.js → chunk-SYD5SJFT.js} +38 -23
  21. package/bundle/{chunk-WX6CHISQ.js → chunk-T3SUXLQQ.js} +2 -2
  22. package/bundle/{chunk-BUJZOWQ7.js → chunk-UIG2IVPJ.js} +34 -16
  23. package/bundle/{chunk-JEW7ZIWE.js → chunk-UJ26GAE5.js} +5326 -5290
  24. package/bundle/{chunk-ARLWCFGI.js → chunk-UNAVBUTP.js} +14729 -7452
  25. package/bundle/{chunk-7H3CQGS6.js → chunk-WQOLTO3C.js} +1 -1
  26. package/bundle/{chunk-KSNNZBTV.js → chunk-X26T73X6.js} +3 -3
  27. package/bundle/{cleanup-6PVHIK4C.js → cleanup-EIZJH2E3.js} +3 -3
  28. package/bundle/{cleanup-FRS7FPOS.js → cleanup-MI76P55B.js} +3 -3
  29. package/bundle/{cleanup-NDTUQVOW.js → cleanup-NZBQYB7U.js} +3 -3
  30. package/bundle/{core-RZFMBCSX.js → core-ERSGIOMQ.js} +30 -2
  31. package/bundle/{dist-7BJPFNU7.js → core-T2TBFAYG.js} +30 -2
  32. package/bundle/{devtoolsService-WER5PRLG.js → devtoolsService-7KZDSYEF.js} +3 -3
  33. package/bundle/{devtoolsService-6D355RSX.js → devtoolsService-FYTOIC37.js} +3 -3
  34. package/bundle/{devtoolsService-7SBW23VD.js → devtoolsService-LV5NJ2BT.js} +4 -5
  35. package/bundle/{dist-DTPIOJ3P.js → dist-ETX67B7P.js} +30 -2
  36. package/bundle/docs/changelogs/index.md +14 -0
  37. package/bundle/docs/changelogs/latest.md +108 -166
  38. package/bundle/docs/changelogs/preview.md +227 -103
  39. package/bundle/docs/cli/auto-memory.md +60 -38
  40. package/bundle/docs/cli/settings.md +1 -1
  41. package/bundle/docs/cli/tutorials/memory-management.md +1 -1
  42. package/bundle/docs/extensions/releasing.md +58 -24
  43. package/bundle/docs/reference/configuration.md +14 -1
  44. package/bundle/docs/reference/keyboard-shortcuts.md +23 -0
  45. package/bundle/{gemini-KMMF6AK3.js → gemini-IVKBXHDT.js} +160 -60
  46. package/bundle/{gemini-GLORNPU2.js → gemini-JKWQQTKP.js} +160 -60
  47. package/bundle/{gemini-HCJBP42A.js → gemini-Z77GAAR6.js} +331 -245
  48. package/bundle/gemini.js +8 -8
  49. package/bundle/{interactiveCli-5UVCH7FM.js → interactiveCli-36WZS6KT.js} +1704 -1457
  50. package/bundle/{interactiveCli-HBRMSAIT.js → interactiveCli-BQ36B66Z.js} +1703 -1457
  51. package/bundle/{interactiveCli-TWDP2H52.js → interactiveCli-SME5QTEN.js} +1967 -1739
  52. package/bundle/{liteRtServerManager-3YA2HL46.js → liteRtServerManager-2QD4R3A3.js} +5 -5
  53. package/bundle/{liteRtServerManager-BYQVAM6Y.js → liteRtServerManager-ISYDOBNC.js} +5 -5
  54. package/bundle/{liteRtServerManager-IQHHDTUM.js → liteRtServerManager-N6OMT6W5.js} +5 -5
  55. package/bundle/{memoryDiscovery-FB7MMKTA.js → memoryDiscovery-LLSKN6HL.js} +1 -1
  56. package/bundle/{memoryDiscovery-KSYZVCWF.js → memoryDiscovery-SJ7P6RCN.js} +1 -1
  57. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  58. package/bundle/{oauth2-provider-C66JRVDQ.js → oauth2-provider-DOSIH6VE.js} +2 -2
  59. package/bundle/{oauth2-provider-TUVQXNLY.js → oauth2-provider-TZF6EZRX.js} +2 -2
  60. package/bundle/{oauth2-provider-OAXWX3Z3.js → oauth2-provider-VFOABWBW.js} +73 -39
  61. package/bundle/{start-ELTWFVNO.js → start-3GPIRK3E.js} +7 -7
  62. package/bundle/{start-HHZI73VV.js → start-6NONW677.js} +7 -7
  63. package/bundle/{start-NCMR7HOQ.js → start-M6MUPEJS.js} +7 -7
  64. package/package.json +1 -1
  65. package/bundle/chunk-5MQ5VMQK.js +0 -17230
  66. package/bundle/chunk-66C7JVNE.js +0 -391
  67. package/bundle/chunk-A3GDBSEI.js +0 -512
  68. package/bundle/chunk-L6GBKGQX.js +0 -118
  69. package/bundle/chunk-LCB7VVYS.js +0 -356008
  70. package/bundle/chunk-OGZGOFAJ.js +0 -1571
  71. package/bundle/chunk-PBD26LJQ.js +0 -81544
  72. package/bundle/chunk-YDSDSLSO.js +0 -156
  73. package/bundle/cleanup-O4IDJYU2.js +0 -33
  74. package/bundle/devtoolsService-SPV43SGI.js +0 -857
  75. package/bundle/dist-ZZ5HEQGP.js +0 -2096
  76. package/bundle/gemini-3NXWUDHV.js +0 -16256
  77. package/bundle/interactiveCli-BNDKNCVJ.js +0 -34505
  78. package/bundle/liteRtServerManager-RTBP2SLV.js +0 -66
  79. package/bundle/oauth2-provider-ZPJOR5SG.js +0 -237
  80. package/bundle/start-S3TEO5BN.js +0 -19
@@ -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-UJ26GAE5.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
  }
@@ -246273,8 +246294,8 @@ var EventMetadataKey;
246273
246294
  })(EventMetadataKey || (EventMetadataKey = {}));
246274
246295
 
246275
246296
  // packages/core/dist/src/generated/git-commit.js
246276
- var GIT_COMMIT_INFO = "246f98459";
246277
- var CLI_VERSION = "0.42.0-preview.0";
246297
+ var GIT_COMMIT_INFO = "022e8baef";
246298
+ var CLI_VERSION = "0.43.0-preview.0";
246278
246299
 
246279
246300
  // packages/core/dist/src/ide/detect-ide.js
246280
246301
  var IDE_DEFINITIONS = {
@@ -248124,7 +248145,35 @@ var GcpMetricExporter = class extends import_opentelemetry_cloud_monitoring_expo
248124
248145
  prefix: "custom.googleapis.com/gemini_cli"
248125
248146
  });
248126
248147
  }
248148
+ export(metrics2, resultCallback) {
248149
+ super.export(metrics2, (result2) => {
248150
+ if (result2.code === import_core5.ExportResultCode.FAILED && result2.error) {
248151
+ const errorMessage = result2.error.message || String(result2.error);
248152
+ if (process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true" && errorMessage.includes("written more frequently than the maximum sampling period")) {
248153
+ resultCallback({ code: import_core5.ExportResultCode.SUCCESS });
248154
+ return;
248155
+ }
248156
+ }
248157
+ resultCallback(result2);
248158
+ });
248159
+ }
248127
248160
  };
248161
+ function truncateLogPayload(payload, limit = 2e5) {
248162
+ if (typeof payload === "string") {
248163
+ return payload.length > limit ? payload.substring(0, limit) + "... (truncated due to size)" : payload;
248164
+ }
248165
+ if (Array.isArray(payload)) {
248166
+ return payload.map((item) => truncateLogPayload(item, limit));
248167
+ }
248168
+ if (payload !== null && typeof payload === "object") {
248169
+ const truncatedObj = {};
248170
+ for (const [key, value] of Object.entries(payload)) {
248171
+ truncatedObj[key] = truncateLogPayload(value, limit);
248172
+ }
248173
+ return truncatedObj;
248174
+ }
248175
+ return payload;
248176
+ }
248128
248177
  var GcpLogExporter = class {
248129
248178
  logging;
248130
248179
  log;
@@ -248136,20 +248185,46 @@ var GcpLogExporter = class {
248136
248185
  export(logs3, resultCallback) {
248137
248186
  try {
248138
248187
  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
- }, {
248188
+ const rawPayload = {
248149
248189
  ...log.attributes,
248150
248190
  ...log.resource?.attributes,
248151
248191
  message: log.body
248152
- });
248192
+ };
248193
+ const isStrictTelemetry = process.env["GEMINI_STRICT_TELEMETRY_LIMITS"] === "true";
248194
+ let finalPayload = rawPayload;
248195
+ if (isStrictTelemetry) {
248196
+ let safePayload = truncateLogPayload(rawPayload, 1e4);
248197
+ let payloadString = JSON.stringify(safePayload);
248198
+ if (payloadString && payloadString.length > 1e5) {
248199
+ safePayload = truncateLogPayload(rawPayload, 2e3);
248200
+ payloadString = JSON.stringify(safePayload);
248201
+ if (payloadString && payloadString.length > 1e5) {
248202
+ safePayload = truncateLogPayload(rawPayload, 5e3);
248203
+ payloadString = JSON.stringify(safePayload);
248204
+ if (payloadString && payloadString.length > 1e5) {
248205
+ safePayload = {
248206
+ _warning: "Payload heavily truncated due to strict limits",
248207
+ data: payloadString.substring(0, 5e4) + "... (truncated)"
248208
+ };
248209
+ }
248210
+ }
248211
+ }
248212
+ finalPayload = safePayload;
248213
+ }
248214
+ const entry = this.log.entry(
248215
+ {
248216
+ severity: this.mapSeverityToCloudLogging(log.severityNumber),
248217
+ timestamp: new Date((0, import_core5.hrTimeToMilliseconds)(log.hrTime)),
248218
+ resource: {
248219
+ type: "global",
248220
+ labels: {
248221
+ project_id: this.logging.projectId
248222
+ }
248223
+ }
248224
+ },
248225
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
248226
+ finalPayload
248227
+ );
248153
248228
  return entry;
248154
248229
  });
248155
248230
  const writePromise = this.log.write(entries).then(() => {
@@ -269321,7 +269396,7 @@ function getVersion() {
269321
269396
  }
269322
269397
  versionPromise = (async () => {
269323
269398
  const pkgJson = await getPackageJson(__dirname4);
269324
- return "0.42.0-preview.1";
269399
+ return "0.43.0-preview.0";
269325
269400
  })();
269326
269401
  return versionPromise;
269327
269402
  }
@@ -270213,18 +270288,25 @@ function cloneChain(chain2) {
270213
270288
  return chain2.map(clonePolicy);
270214
270289
  }
270215
270290
 
270291
+ // packages/core/dist/src/utils/modelUtils.js
270292
+ function normalizeModelId(modelId) {
270293
+ return modelId.startsWith("models/") ? modelId.slice(7) : modelId;
270294
+ }
270295
+
270216
270296
  // packages/core/dist/src/availability/policyHelpers.js
270217
270297
  function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270218
- const modelFromConfig = preferredModel ?? config2.getActiveModel?.() ?? config2.getModel();
270219
- const configuredModel = config2.getModel();
270298
+ const normalizedPreferredModel = preferredModel ? normalizeModelId(preferredModel) : void 0;
270299
+ const modelFromConfig = normalizeModelId(normalizedPreferredModel ?? config2.getActiveModel?.() ?? config2.getModel());
270300
+ const configuredModel = normalizeModelId(config2.getModel());
270220
270301
  let chain2;
270221
270302
  const useGemini31 = config2.getGemini31LaunchedSync?.() ?? false;
270222
270303
  const useGemini31FlashLite = config2.getGemini31FlashLiteLaunchedSync?.() ?? false;
270223
270304
  const useCustomToolModel = config2.getUseCustomToolModelSync?.() ?? false;
270224
270305
  const hasAccessToPreview = config2.getHasAccessToPreviewModel?.() ?? true;
270225
- const resolvedModel = resolveModel(modelFromConfig, useGemini31, useGemini31FlashLite, useCustomToolModel, hasAccessToPreview, config2);
270226
- const isAutoPreferred = preferredModel ? isAutoModel(preferredModel, config2) : false;
270306
+ const resolvedModel = normalizeModelId(resolveModel(modelFromConfig, useGemini31, useGemini31FlashLite, useCustomToolModel, hasAccessToPreview, config2));
270307
+ const isAutoPreferred = normalizedPreferredModel ? isAutoModel(normalizedPreferredModel, config2) : false;
270227
270308
  const isAutoConfigured = isAutoModel(configuredModel, config2);
270309
+ const effectiveWrapsAround = wrapsAround || isAutoPreferred || isAutoConfigured || isGemini3Model(resolvedModel, config2);
270228
270310
  if (config2.getExperimentalDynamicModelConfiguration?.() === true) {
270229
270311
  const context2 = {
270230
270312
  useGemini3_1: useGemini31,
@@ -270233,13 +270315,13 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270233
270315
  };
270234
270316
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270235
270317
  chain2 = config2.modelConfigService.resolveChain("lite", context2);
270236
- } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270318
+ } else if (isGemini3Model(normalizeModelId(resolvedModel), config2) || isAutoPreferred || isAutoConfigured) {
270237
270319
  if (isAutoConfigured && config2.modelConfigService.getModelChain(configuredModel)) {
270238
270320
  chain2 = config2.modelConfigService.resolveChain(configuredModel, context2);
270239
270321
  }
270240
270322
  if (!chain2) {
270241
270323
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270242
- const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270324
+ const previewEnabled = hasAccessToPreview && (isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO);
270243
270325
  const autoPrefix = isAutoSelection ? "auto-" : "";
270244
270326
  const chainKey = previewEnabled ? "preview" : "default";
270245
270327
  chain2 = config2.modelConfigService.resolveChain(`${autoPrefix}${chainKey}`, context2);
@@ -270248,14 +270330,14 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270248
270330
  if (!chain2) {
270249
270331
  chain2 = createSingleModelChain(modelFromConfig);
270250
270332
  }
270251
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270333
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270252
270334
  } else {
270253
270335
  if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) {
270254
270336
  chain2 = getFlashLitePolicyChain();
270255
270337
  } else if (isGemini3Model(resolvedModel, config2) || isAutoPreferred || isAutoConfigured) {
270256
270338
  const isAutoSelection = isAutoPreferred || isAutoConfigured;
270257
270339
  if (hasAccessToPreview) {
270258
- const previewEnabled = isGemini3Model(resolvedModel, config2) || preferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270340
+ const previewEnabled = isGemini3Model(resolvedModel, config2) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO;
270259
270341
  chain2 = getModelPolicyChain({
270260
270342
  previewEnabled,
270261
270343
  isAutoSelection,
@@ -270277,7 +270359,7 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270277
270359
  } else {
270278
270360
  chain2 = createSingleModelChain(modelFromConfig);
270279
270361
  }
270280
- chain2 = applyDynamicSlicing(chain2, resolvedModel, wrapsAround);
270362
+ chain2 = applyDynamicSlicing(chain2, resolvedModel, effectiveWrapsAround);
270281
270363
  }
270282
270364
  if (config2?.getApprovalMode?.() === ApprovalMode.PLAN) {
270283
270365
  return chain2.map((policy) => ({
@@ -270288,14 +270370,16 @@ function resolvePolicyChain(config2, preferredModel, wrapsAround = false) {
270288
270370
  return chain2;
270289
270371
  }
270290
270372
  function applyDynamicSlicing(chain2, resolvedModel, wrapsAround) {
270291
- const activeIndex = chain2.findIndex((policy) => policy.model === resolvedModel);
270373
+ const normalizedResolved = normalizeModelId(resolvedModel);
270374
+ const activeIndex = chain2.findIndex((policy) => normalizeModelId(policy.model) === normalizedResolved);
270292
270375
  if (activeIndex !== -1) {
270293
270376
  return wrapsAround ? [...chain2.slice(activeIndex), ...chain2.slice(0, activeIndex)] : [...chain2.slice(activeIndex)];
270294
270377
  }
270295
270378
  return [createDefaultPolicy(resolvedModel, { isLastResort: true })];
270296
270379
  }
270297
270380
  function buildFallbackPolicyContext(chain2, failedModel, wrapsAround = false) {
270298
- const index = chain2.findIndex((policy) => policy.model === failedModel);
270381
+ const normalizedFailed = normalizeModelId(failedModel);
270382
+ const index = chain2.findIndex((policy) => normalizeModelId(policy.model) === normalizedFailed);
270299
270383
  if (index === -1) {
270300
270384
  return { failedPolicy: void 0, candidates: chain2 };
270301
270385
  }
@@ -270891,6 +270975,15 @@ var BaseLlmClient = class {
270891
270975
  }
270892
270976
  return text;
270893
270977
  }
270978
+ async countTokens(options) {
270979
+ const model = options.modelConfigKey ? this.config.modelConfigService.getResolvedConfig(options.modelConfigKey).model : this.config.getActiveModel();
270980
+ const result2 = await this.contentGenerator.countTokens({
270981
+ model,
270982
+ contents: options.contents,
270983
+ config: options.abortSignal ? { abortSignal: options.abortSignal } : void 0
270984
+ });
270985
+ return { totalTokens: result2.totalTokens || 0 };
270986
+ }
270894
270987
  async generateContent(options) {
270895
270988
  const { modelConfigKey, contents, systemInstruction, abortSignal, promptId, role, maxAttempts } = options;
270896
270989
  const shouldRetryOnContent = (response) => {
@@ -271470,6 +271563,9 @@ function isEditToolParams(args2) {
271470
271563
  }
271471
271564
  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
271565
  }
271566
+ function fileDiffToSummary(diff, editData) {
271567
+ return diff.diffStat ? `${diff.diffStat.model_added_lines} added, ${diff.diffStat.model_removed_lines} removed` : `${editData.occurrences} replacements`;
271568
+ }
271473
271569
  var EditToolInvocation = class extends BaseToolInvocation {
271474
271570
  config;
271475
271571
  resolvedPath;
@@ -271846,8 +271942,20 @@ ${snippet2}`);
271846
271942
  if (jitContext) {
271847
271943
  llmContent = appendJitContext(llmContent, jitContext);
271848
271944
  }
271945
+ const resultSummary = typeof displayResult === "string" ? displayResult : fileDiffToSummary(displayResult, editData);
271849
271946
  return {
271850
271947
  llmContent,
271948
+ display: {
271949
+ name: this._toolDisplayName,
271950
+ description: this.getDescription(),
271951
+ resultSummary,
271952
+ result: {
271953
+ type: "diff",
271954
+ path: this.resolvedPath,
271955
+ beforeText: editData.currentContent ?? "",
271956
+ afterText: editData.newContent
271957
+ }
271958
+ },
271851
271959
  returnDisplay: displayResult
271852
271960
  };
271853
271961
  } catch (error40) {
@@ -272377,6 +272485,17 @@ ${snippet2}`);
272377
272485
  }
272378
272486
  return {
272379
272487
  llmContent,
272488
+ display: {
272489
+ name: WRITE_FILE_DISPLAY_NAME,
272490
+ description: this.getDescription(),
272491
+ resultSummary: diffStat ? `${diffStat.model_added_lines} added, ${diffStat.model_removed_lines} removed` : "Written",
272492
+ result: {
272493
+ type: "diff",
272494
+ path: this.resolvedPath,
272495
+ beforeText: correctedContentResult.originalContent ?? "",
272496
+ afterText: correctedContentResult.correctedContent
272497
+ }
272498
+ },
272380
272499
  returnDisplay: displayResult
272381
272500
  };
272382
272501
  } catch (error40) {
@@ -273099,6 +273218,12 @@ var ProjectIdRequiredError = class extends Error {
273099
273218
  this.name = "ProjectIdRequiredError";
273100
273219
  }
273101
273220
  };
273221
+ var InvalidNumericProjectIdError = class extends Error {
273222
+ constructor(projectId) {
273223
+ 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.`);
273224
+ this.name = "InvalidNumericProjectIdError";
273225
+ }
273226
+ };
273102
273227
  var ValidationCancelledError = class extends Error {
273103
273228
  constructor() {
273104
273229
  super("User cancelled account validation");
@@ -273124,6 +273249,9 @@ function resetUserDataCacheForTesting() {
273124
273249
  }
273125
273250
  async function setupUser(client, config2, httpOptions = {}) {
273126
273251
  const projectId = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
273252
+ if (projectId && /^\d+$/.test(projectId)) {
273253
+ throw new InvalidNumericProjectIdError(projectId);
273254
+ }
273127
273255
  const projectCache = userDataCache.getOrCreate(client, () => createCache({
273128
273256
  storage: "map",
273129
273257
  defaultTtl: 3e4
@@ -273273,13 +273401,26 @@ function validateLoadCodeAssistResponse(res) {
273273
273401
 
273274
273402
  // packages/core/dist/src/utils/quotaErrorDetection.js
273275
273403
  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;
273404
+ if (typeof error40 !== "object" || error40 === null || !("error" in error40)) {
273405
+ return false;
273406
+ }
273407
+ const errorProp = error40.error;
273408
+ if (typeof errorProp !== "object" || errorProp === null) {
273409
+ return false;
273410
+ }
273411
+ return "code" in errorProp && typeof errorProp.code === "number" && "message" in errorProp && typeof errorProp.message === "string" && "status" in errorProp && typeof errorProp.status === "string";
273279
273412
  }
273280
273413
  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";
273414
+ if (typeof error40 !== "object" || error40 === null || !("message" in error40)) {
273415
+ return false;
273416
+ }
273417
+ if (typeof error40.message !== "string") {
273418
+ return false;
273419
+ }
273420
+ if ("status" in error40 && typeof error40.status !== "number") {
273421
+ return false;
273422
+ }
273423
+ return true;
273283
273424
  }
273284
273425
 
273285
273426
  // packages/core/dist/src/utils/tokenCalculation.js
@@ -273296,9 +273437,10 @@ function estimateTextTokens(text, charsPerToken) {
273296
273437
  return text.length / charsPerToken;
273297
273438
  }
273298
273439
  let tokens = 0;
273440
+ const asciiTokensPerChar = 1 / charsPerToken;
273299
273441
  for (let i3 = 0; i3 < text.length; i3++) {
273300
273442
  if (text.charCodeAt(i3) <= 127) {
273301
- tokens += ASCII_TOKENS_PER_CHAR;
273443
+ tokens += asciiTokensPerChar;
273302
273444
  } else {
273303
273445
  tokens += NON_ASCII_TOKENS_PER_CHAR;
273304
273446
  }
@@ -273937,10 +274079,6 @@ function validateBaseUrl(baseUrl) {
273937
274079
  }
273938
274080
  }
273939
274081
  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
274082
  const contentGeneratorConfig = {
273945
274083
  authType,
273946
274084
  proxy: config2?.getProxy(),
@@ -273951,6 +274089,10 @@ async function createContentGeneratorConfig(config2, authType, apiKey, baseUrl,
273951
274089
  if (authType === AuthType.LOGIN_WITH_GOOGLE || authType === AuthType.COMPUTE_ADC) {
273952
274090
  return contentGeneratorConfig;
273953
274091
  }
274092
+ const geminiApiKey = apiKey || process.env["GEMINI_API_KEY"] || await loadApiKey() || void 0;
274093
+ const googleApiKey = process.env["GOOGLE_API_KEY"] || void 0;
274094
+ const googleCloudProject = process.env["GOOGLE_CLOUD_PROJECT"] || process.env["GOOGLE_CLOUD_PROJECT_ID"] || void 0;
274095
+ const googleCloudLocation = process.env["GOOGLE_CLOUD_LOCATION"] || void 0;
273954
274096
  if (authType === AuthType.USE_GEMINI && geminiApiKey) {
273955
274097
  contentGeneratorConfig.apiKey = geminiApiKey;
273956
274098
  contentGeneratorConfig.vertexai = false;
@@ -274898,6 +275040,11 @@ ${directoryContent}`;
274898
275040
  }
274899
275041
  return {
274900
275042
  llmContent: resultMessage,
275043
+ display: {
275044
+ name: LS_DISPLAY_NAME,
275045
+ description: this.getDescription(),
275046
+ resultSummary: displayMessage
275047
+ },
274901
275048
  returnDisplay: {
274902
275049
  summary: displayMessage,
274903
275050
  files: entries.map((entry) => `${entry.isDirectory ? "[DIR] " : ""}${entry.name}`)
@@ -275130,7 +275277,7 @@ var IgnoreFileParser = class {
275130
275277
  return this.patterns;
275131
275278
  }
275132
275279
  getIgnoreFilePaths() {
275133
- return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter((filePath) => fs34.existsSync(filePath));
275280
+ return this.fileNames.slice().reverse().map((fileName) => path39.join(this.projectRoot, fileName)).filter((filePath) => fs34.statSync(filePath, { throwIfNoEntry: false })?.isFile() ?? false);
275134
275281
  }
275135
275282
  /**
275136
275283
  * Returns true if at least one ignore file exists and has patterns.
@@ -275353,7 +275500,8 @@ var FileDiscoveryService = class {
275353
275500
  const paths = [];
275354
275501
  if (this.gitIgnoreFilter && this.defaultFilterFileOptions.respectGitIgnore) {
275355
275502
  const gitIgnorePath = path41.join(this.projectRoot, ".gitignore");
275356
- if (fs36.existsSync(gitIgnorePath)) {
275503
+ const stat9 = fs36.statSync(gitIgnorePath, { throwIfNoEntry: false });
275504
+ if (stat9?.isFile()) {
275357
275505
  paths.push(gitIgnorePath);
275358
275506
  }
275359
275507
  }
@@ -275438,8 +275586,15 @@ ${result2.llmContent}`;
275438
275586
  llmContent = appendJitContextToParts(llmContent, jitContext);
275439
275587
  }
275440
275588
  }
275589
+ const displayResultSummary = result2.isTruncated ? `${result2.linesShown[0]}-${result2.linesShown[1]} of ${result2.originalLineCount}` : lines !== void 0 ? `${lines} lines` : void 0;
275441
275590
  return {
275442
275591
  llmContent,
275592
+ display: {
275593
+ name: READ_FILE_DISPLAY_NAME,
275594
+ description: this.getDescription(),
275595
+ resultSummary: displayResultSummary,
275596
+ result: { type: "text", text: result2.returnDisplay || "" }
275597
+ },
275443
275598
  returnDisplay: result2.returnDisplay || ""
275444
275599
  };
275445
275600
  }
@@ -275462,12 +275617,6 @@ var ReadFileTool = class _ReadFileTool extends BaseDeclarativeTool {
275462
275617
  if (validationError) {
275463
275618
  return validationError;
275464
275619
  }
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
275620
  if (params.start_line !== void 0 && params.end_line !== void 0 && params.start_line > params.end_line) {
275472
275621
  return "start_line cannot be greater than end_line";
275473
275622
  }
@@ -281703,10 +281852,10 @@ var Ignore = class {
281703
281852
  ignored(p) {
281704
281853
  const fullpath = p.fullpath();
281705
281854
  const fullpaths = `${fullpath}/`;
281706
- const relative12 = p.relative() || ".";
281707
- const relatives = `${relative12}/`;
281855
+ const relative11 = p.relative() || ".";
281856
+ const relatives = `${relative11}/`;
281708
281857
  for (const m of this.relative) {
281709
- if (m.match(relative12) || m.match(relatives))
281858
+ if (m.match(relative11) || m.match(relatives))
281710
281859
  return true;
281711
281860
  }
281712
281861
  for (const m of this.absolute) {
@@ -281717,9 +281866,9 @@ var Ignore = class {
281717
281866
  }
281718
281867
  childrenIgnored(p) {
281719
281868
  const fullpath = p.fullpath() + "/";
281720
- const relative12 = (p.relative() || ".") + "/";
281869
+ const relative11 = (p.relative() || ".") + "/";
281721
281870
  for (const m of this.relativeChildren) {
281722
- if (m.match(relative12))
281871
+ if (m.match(relative11))
281723
281872
  return true;
281724
281873
  }
281725
281874
  for (const m of this.absoluteChildren) {
@@ -282824,7 +282973,19 @@ var GrepToolInvocation = class extends BaseToolInvocation {
282824
282973
  } else {
282825
282974
  searchLocationDescription = `in path "${searchDirDisplay}"`;
282826
282975
  }
282827
- return await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
282976
+ const result2 = await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
282977
+ return {
282978
+ ...result2,
282979
+ display: {
282980
+ name: this._toolDisplayName,
282981
+ description: this.getDescription(),
282982
+ resultSummary: result2.returnDisplay.summary,
282983
+ result: {
282984
+ type: "text",
282985
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
282986
+ }
282987
+ }
282988
+ };
282828
282989
  } catch (error40) {
282829
282990
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
282830
282991
  const errorMessage = getErrorMessage(error40);
@@ -283283,7 +283444,19 @@ var GrepToolInvocation2 = class extends BaseToolInvocation {
283283
283444
  const matchCount = allMatches.filter((m) => !m.isContext).length;
283284
283445
  allMatches = await this.enrichWithRipgrepAutoContext(allMatches, matchCount, totalMaxMatches, searchDirAbs, timeoutController.signal);
283285
283446
  const searchLocationDescription = `in path "${searchDirDisplay}"`;
283286
- return await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283447
+ const result2 = await formatGrepResults(allMatches, this.params, searchLocationDescription, totalMaxMatches);
283448
+ return {
283449
+ ...result2,
283450
+ display: {
283451
+ name: this._toolDisplayName,
283452
+ description: this.getDescription(),
283453
+ resultSummary: result2.returnDisplay.summary,
283454
+ result: {
283455
+ type: "text",
283456
+ text: result2.llmContent.split("\n---\n").slice(1).join("\n---\n")
283457
+ }
283458
+ }
283459
+ };
283287
283460
  } catch (error40) {
283288
283461
  debugLogger.warn(`Error during GrepLogic execution: ${error40}`);
283289
283462
  const errorMessage = getErrorMessage(error40);
@@ -286819,8 +286992,18 @@ ${result2.output}`;
286819
286992
  ...executionError
286820
286993
  };
286821
286994
  }
286995
+ const displayResultSummary = result2.backgrounded ? `PID: ${result2.pid}` : result2.exitCode !== null && result2.exitCode !== 0 ? `Exit Code: ${result2.exitCode}` : void 0;
286822
286996
  return {
286823
286997
  llmContent,
286998
+ display: {
286999
+ name: "Shell",
287000
+ description: this.getDescription(),
287001
+ resultSummary: displayResultSummary,
287002
+ result: typeof returnDisplay === "string" ? { type: "text", text: returnDisplay } : (
287003
+ // TODO: Add support for terminal display type (AnsiOutput)
287004
+ void 0
287005
+ )
287006
+ },
286824
287007
  returnDisplay,
286825
287008
  data,
286826
287009
  ...executionError
@@ -292906,6 +293089,11 @@ Strategic Intent: ${strategicIntent.trim()}`;
292906
293089
  }
292907
293090
  return {
292908
293091
  llmContent,
293092
+ display: {
293093
+ format: "notice",
293094
+ name: title || UPDATE_TOPIC_DISPLAY_NAME,
293095
+ description: this.getDescription()
293096
+ },
292909
293097
  returnDisplay
292910
293098
  };
292911
293099
  }
@@ -293357,6 +293545,9 @@ var GeminiChat = class {
293357
293545
  this.chatRecordingService = new ChatRecordingService(context2);
293358
293546
  this.lastPromptTokenCount = estimateTokenCountSync(this.agentHistory.flatMap((c4) => c4.parts || []));
293359
293547
  }
293548
+ get loopContext() {
293549
+ return this.context;
293550
+ }
293360
293551
  async initialize(resumedSessionData, kind = "main") {
293361
293552
  await this.chatRecordingService.initialize(resumedSessionData, kind);
293362
293553
  }
@@ -293614,9 +293805,10 @@ var GeminiChat = class {
293614
293805
  lastModelToUse = modelToUse;
293615
293806
  lastConfig = config2;
293616
293807
  lastContentsToUse = contentsToUse;
293808
+ const finalContents = stripToolCallIdPrefixes(contentsToUse);
293617
293809
  return this.context.config.getContentGenerator().generateContentStream({
293618
293810
  model: modelToUse,
293619
- contents: contentsToUse,
293811
+ contents: finalContents,
293620
293812
  config: config2
293621
293813
  }, prompt_id, role);
293622
293814
  };
@@ -293785,7 +293977,9 @@ This error was probably caused by cyclic schema references in one of the followi
293785
293977
  const finalFunctionCallsMap = /* @__PURE__ */ new Map();
293786
293978
  const legacyFunctionCalls = [];
293787
293979
  const callIndexToId = /* @__PURE__ */ new Map();
293980
+ let runningFunctionCallCounter = 0;
293788
293981
  for await (const chunk of streamResponse) {
293982
+ const currentChunkStartCounter = runningFunctionCallCounter;
293789
293983
  const candidateWithReason = chunk?.candidates?.find((candidate) => candidate.finishReason);
293790
293984
  if (candidateWithReason) {
293791
293985
  finishReason = candidateWithReason.finishReason;
@@ -293794,18 +293988,30 @@ This error was probably caused by cyclic schema references in one of the followi
293794
293988
  if (this.context.config.isContextManagementEnabled()) {
293795
293989
  for (let i3 = 0; i3 < chunk.functionCalls.length; i3++) {
293796
293990
  const fnCall = chunk.functionCalls[i3];
293991
+ const globalIndex = currentChunkStartCounter + i3;
293797
293992
  if (!fnCall.id) {
293798
- let id = callIndexToId.get(i3);
293993
+ let id = callIndexToId.get(globalIndex);
293799
293994
  if (!id) {
293800
293995
  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}`);
293996
+ callIndexToId.set(globalIndex, id);
293997
+ debugLogger.log(`[GeminiChat] Assigned synthetic ID: ${id} to tool at index ${globalIndex}: ${fnCall.name}`);
293803
293998
  }
293804
293999
  fnCall.id = id;
293805
294000
  }
294001
+ const name3 = fnCall.name?.trim() || "generic_tool";
294002
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
294003
+ fnCall.id = `${name3}__${fnCall.id}`;
294004
+ }
293806
294005
  finalFunctionCallsMap.set(fnCall.id, fnCall);
293807
294006
  }
294007
+ runningFunctionCallCounter += chunk.functionCalls.length;
293808
294008
  } else {
294009
+ for (const fnCall of chunk.functionCalls) {
294010
+ const name3 = fnCall.name?.trim() || "generic_tool";
294011
+ if (fnCall.id && !fnCall.id.startsWith(`${name3}__`)) {
294012
+ fnCall.id = `${name3}__${fnCall.id}`;
294013
+ }
294014
+ }
293809
294015
  legacyFunctionCalls.push(...chunk.functionCalls);
293810
294016
  }
293811
294017
  }
@@ -293819,13 +294025,18 @@ This error was probably caused by cyclic schema references in one of the followi
293819
294025
  if (content.parts.some((part) => part.functionCall)) {
293820
294026
  hasToolCall = true;
293821
294027
  }
294028
+ let localFunctionCallCounter = 0;
293822
294029
  modelResponseParts.push(...content.parts.filter((part) => !part.thought).map((part) => {
293823
294030
  if (!this.context.config.isContextManagementEnabled()) {
293824
294031
  return part;
293825
294032
  }
294033
+ let callIndex;
294034
+ if (part.functionCall) {
294035
+ callIndex = currentChunkStartCounter + localFunctionCallCounter++;
294036
+ }
293826
294037
  return {
293827
294038
  ...part,
293828
- callIndex: chunk.functionCalls?.findIndex((fc) => fc.name === part.functionCall?.name)
294039
+ callIndex
293829
294040
  };
293830
294041
  }));
293831
294042
  }
@@ -293972,6 +294183,82 @@ function isSchemaDepthError(errorMessage) {
293972
294183
  function isInvalidArgumentError(errorMessage) {
293973
294184
  return errorMessage.includes("Request contains an invalid argument");
293974
294185
  }
294186
+ function stripToolCallIdPrefixes(contents) {
294187
+ return contents.map((content) => ({
294188
+ ...content,
294189
+ parts: (content.parts || []).map((part) => {
294190
+ const newPart = { ...part };
294191
+ if (newPart.functionCall) {
294192
+ const fc = newPart.functionCall;
294193
+ const name3 = fc.name?.trim() || "generic_tool";
294194
+ if (fc.id && fc.id.startsWith(`${name3}__`)) {
294195
+ newPart.functionCall = {
294196
+ name: fc.name,
294197
+ args: fc.args,
294198
+ id: fc.id.substring(name3.length + 2)
294199
+ };
294200
+ }
294201
+ }
294202
+ if (newPart.functionResponse) {
294203
+ const fr = newPart.functionResponse;
294204
+ const name3 = fr.name?.trim() || "generic_tool";
294205
+ if (fr.id && fr.id.startsWith(`${name3}__`)) {
294206
+ newPart.functionResponse = {
294207
+ name: fr.name,
294208
+ response: fr.response,
294209
+ id: fr.id.substring(name3.length + 2)
294210
+ };
294211
+ }
294212
+ }
294213
+ return newPart;
294214
+ })
294215
+ }));
294216
+ }
294217
+
294218
+ // packages/core/dist/src/agent/tool-display-utils.js
294219
+ function populateToolDisplay({ name: name3, invocation, resultDisplay, displayName, display: prevDisplay }) {
294220
+ const display = {
294221
+ name: displayName || name3,
294222
+ description: invocation?.getDescription?.(),
294223
+ ...prevDisplay
294224
+ };
294225
+ if (resultDisplay !== void 0 && display.result === void 0) {
294226
+ display.result = toolResultDisplayToDisplayContent(resultDisplay);
294227
+ }
294228
+ return display;
294229
+ }
294230
+ function toolResultDisplayToDisplayContent(resultDisplay) {
294231
+ if (typeof resultDisplay === "string") {
294232
+ return { type: "text", text: resultDisplay };
294233
+ }
294234
+ if (typeof resultDisplay === "object" && resultDisplay !== null && "fileDiff" in resultDisplay && "newContent" in resultDisplay) {
294235
+ return {
294236
+ type: "diff",
294237
+ path: resultDisplay.filePath || resultDisplay.fileName,
294238
+ beforeText: resultDisplay.originalContent ?? "",
294239
+ afterText: resultDisplay.newContent
294240
+ };
294241
+ }
294242
+ return {
294243
+ type: "text",
294244
+ text: JSON.stringify(resultDisplay)
294245
+ };
294246
+ }
294247
+ function renderDisplayDiff(diff) {
294248
+ return createPatch(diff.path || "file", diff.beforeText, diff.afterText, "Original", "Modified", { context: 3 });
294249
+ }
294250
+ function displayContentToString(display) {
294251
+ if (!display) {
294252
+ return void 0;
294253
+ }
294254
+ if (display.type === "text") {
294255
+ return display.text;
294256
+ }
294257
+ if (display.type === "diff") {
294258
+ return renderDisplayDiff(display);
294259
+ }
294260
+ return JSON.stringify(display);
294261
+ }
293975
294262
 
293976
294263
  // packages/core/dist/src/core/turn.js
293977
294264
  var GeminiEventType;
@@ -294129,13 +294416,33 @@ ${[...this.pendingCitations].sort().join("\n")}`
294129
294416
  }
294130
294417
  }
294131
294418
  handlePendingFunctionCall(fnCall, traceId) {
294132
- const name3 = fnCall.name || "undefined_tool_name";
294419
+ const name3 = fnCall.name?.trim() || "generic_tool";
294133
294420
  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++}`);
294421
+ const rawCallId = fnCall.id ?? (this.chat.context.config.isContextManagementEnabled() ? `synth_${this.prompt_id}_${Date.now()}_${this.callCounter++}` : `${name3}_${Date.now()}_${this.callCounter++}`);
294422
+ const callId = rawCallId.startsWith(`${name3}__`) ? rawCallId : `${name3}__${rawCallId}`;
294423
+ fnCall.id = callId;
294424
+ const tool = this.chat.loopContext.toolRegistry.getTool(name3);
294425
+ let display;
294426
+ if (tool) {
294427
+ let invocation;
294428
+ try {
294429
+ invocation = tool.build(args2);
294430
+ } catch {
294431
+ }
294432
+ display = populateToolDisplay({
294433
+ name: name3,
294434
+ invocation,
294435
+ displayName: tool.displayName
294436
+ });
294437
+ if (!display.description) {
294438
+ display.description = tool.description;
294439
+ }
294440
+ }
294135
294441
  const toolCallRequest = {
294136
294442
  callId,
294137
294443
  name: name3,
294138
294444
  args: args2,
294445
+ display,
294139
294446
  isClientInitiated: false,
294140
294447
  prompt_id: this.prompt_id,
294141
294448
  traceId
@@ -294277,7 +294584,7 @@ Use the following guidelines to optimize your search and read patterns.
294277
294584
  - Prefer using tools like ${GREP_TOOL_NAME} to identify points of interest instead of reading lots of files individually.
294278
294585
  - If you need to read multiple ranges in a file, do so parallel, in as few turns as possible.
294279
294586
  - 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.
294587
+ - ${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
294588
  - You can compensate for the risk of missing results with scoped or limited searches by doing multiple searches in parallel.
294282
294589
  - Your primary goal is still to do your best quality work. Efficiency is an important, but secondary concern.
294283
294590
  </guidelines>
@@ -296756,6 +297063,13 @@ var SubagentActivityErrorType;
296756
297063
  })(SubagentActivityErrorType || (SubagentActivityErrorType = {}));
296757
297064
  var SUBAGENT_REJECTED_ERROR_PREFIX = "User rejected this operation.";
296758
297065
  var SUBAGENT_CANCELLED_ERROR_MESSAGE = "Request cancelled.";
297066
+ var SubagentState;
297067
+ (function(SubagentState2) {
297068
+ SubagentState2["RUNNING"] = "running";
297069
+ SubagentState2["COMPLETED"] = "completed";
297070
+ SubagentState2["ERROR"] = "error";
297071
+ SubagentState2["CANCELLED"] = "cancelled";
297072
+ })(SubagentState || (SubagentState = {}));
296759
297073
  function isSubagentProgress(obj) {
296760
297074
  return typeof obj === "object" && obj !== null && "isSubagentProgress" in obj && obj.isSubagentProgress === true;
296761
297075
  }
@@ -300957,7 +301271,7 @@ var A2AAuthProviderFactory = class _A2AAuthProviderFactory {
300957
301271
  return provider;
300958
301272
  }
300959
301273
  case "oauth2": {
300960
- const { OAuth2AuthProvider } = await import("./oauth2-provider-ZPJOR5SG.js");
301274
+ const { OAuth2AuthProvider } = await import("./oauth2-provider-DOSIH6VE.js");
300961
301275
  const provider = new OAuth2AuthProvider(authConfig, options.agentName ?? "unknown", agentCard, options.agentCardUrl);
300962
301276
  await provider.initialize();
300963
301277
  return provider;
@@ -302191,8 +302505,10 @@ var SchedulerStateManager = class {
302191
302505
  const call = this.activeCalls.get(callId);
302192
302506
  if (!call || call.status === CoreToolCallStatus.Error)
302193
302507
  return;
302508
+ const display = call.request.display ? { ...call.request.display } : { name: call.request.name };
302509
+ display.description = newInvocation.getDescription();
302194
302510
  this.activeCalls.set(callId, this.patchCall(call, {
302195
- request: { ...call.request, args: newArgs },
302511
+ request: { ...call.request, args: newArgs, display },
302196
302512
  invocation: newInvocation
302197
302513
  }));
302198
302514
  this.emitUpdate();
@@ -304384,9 +304700,30 @@ var NodeType;
304384
304700
  NodeType2["SNAPSHOT"] = "SNAPSHOT";
304385
304701
  NodeType2["ROLLING_SUMMARY"] = "ROLLING_SUMMARY";
304386
304702
  })(NodeType || (NodeType = {}));
304703
+ function isAgentThought(node) {
304704
+ return node.type === NodeType.AGENT_THOUGHT;
304705
+ }
304706
+ function isAgentYield(node) {
304707
+ return node.type === NodeType.AGENT_YIELD;
304708
+ }
304387
304709
  function isToolExecution(node) {
304388
304710
  return node.type === NodeType.TOOL_EXECUTION;
304389
304711
  }
304712
+ function isMaskedTool(node) {
304713
+ return node.type === NodeType.MASKED_TOOL;
304714
+ }
304715
+ function isUserPrompt(node) {
304716
+ return node.type === NodeType.USER_PROMPT;
304717
+ }
304718
+ function isSystemEvent(node) {
304719
+ return node.type === NodeType.SYSTEM_EVENT;
304720
+ }
304721
+ function isSnapshot(node) {
304722
+ return node.type === NodeType.SNAPSHOT;
304723
+ }
304724
+ function isRollingSummary(node) {
304725
+ return node.type === NodeType.ROLLING_SUMMARY;
304726
+ }
304390
304727
 
304391
304728
  // packages/core/dist/src/context/processors/nodeDistillationProcessor.js
304392
304729
  var NodeDistillationProcessorOptionsSchema = {
@@ -304519,44 +304856,279 @@ function createNodeDistillationProcessor(id, env2, options) {
304519
304856
  }
304520
304857
 
304521
304858
  // packages/core/dist/src/context/processors/stateSnapshotProcessor.js
304522
- import { randomUUID as randomUUID8 } from "node:crypto";
304859
+ import { randomUUID as randomUUID9 } from "node:crypto";
304860
+
304861
+ // packages/core/dist/src/context/utils/formatNodesForLlm.js
304862
+ function getSemanticToolWrapper(toolName) {
304863
+ if (toolName.includes("search") || toolName.includes("grep"))
304864
+ return `SEARCH RESULTS`;
304865
+ if (toolName.includes("list") || toolName.includes("dir"))
304866
+ return `WORKSPACE STRUCTURE`;
304867
+ if (toolName.includes("shell") || toolName.includes("cmd"))
304868
+ return `SHELL EXECUTION`;
304869
+ if (toolName.includes("read") || toolName.includes("fetch"))
304870
+ return `FILE/WEB CONTENT`;
304871
+ return `TOOL RESPONSE`;
304872
+ }
304873
+ function formatNodesForLlm(nodes, options = {}) {
304874
+ const maxToolChars = options.maxToolResponseChars ?? 2e3;
304875
+ let transcript = "";
304876
+ const uniqueTurns = Array.from(new Set(nodes.map((n3) => n3.turnId).filter(Boolean)));
304877
+ for (const node of nodes) {
304878
+ const payload = node.payload;
304879
+ let nodeContent = "";
304880
+ if (payload.text) {
304881
+ nodeContent = payload.text;
304882
+ } else if (payload.functionCall) {
304883
+ nodeContent = `CALL: ${payload.functionCall.name}(${JSON.stringify(payload.functionCall.args)})`;
304884
+ } else if (payload.functionResponse) {
304885
+ const toolName = payload.functionResponse.name || "unknown_tool";
304886
+ const rawResponse = JSON.stringify(payload.functionResponse.response);
304887
+ const semanticWrapper = getSemanticToolWrapper(toolName);
304888
+ let formattedResponse = rawResponse;
304889
+ if (rawResponse.length > maxToolChars) {
304890
+ const half = Math.floor(maxToolChars / 2);
304891
+ const truncatedCount = rawResponse.length - maxToolChars;
304892
+ formattedResponse = `${rawResponse.substring(0, half)}... [TRUNCATED ${truncatedCount} chars] ...${rawResponse.substring(rawResponse.length - half)}`;
304893
+ }
304894
+ nodeContent = `[${semanticWrapper} (${toolName})]: ${formattedResponse}`;
304895
+ } else {
304896
+ nodeContent = JSON.stringify(payload);
304897
+ }
304898
+ const role = (node.role || "system").toUpperCase();
304899
+ let turnMarker = "";
304900
+ if (node.turnId) {
304901
+ const idx = uniqueTurns.indexOf(node.turnId);
304902
+ if (idx !== -1) {
304903
+ const relativeIdx = idx - (uniqueTurns.length - 1);
304904
+ turnMarker = `[Turn ${relativeIdx}] `;
304905
+ }
304906
+ }
304907
+ transcript += `${turnMarker}[${role}] [${node.type}]: ${nodeContent}
304908
+ `;
304909
+ }
304910
+ return transcript;
304911
+ }
304523
304912
 
304524
304913
  // packages/core/dist/src/context/utils/snapshotGenerator.js
304914
+ import { randomUUID as randomUUID8 } from "node:crypto";
304915
+ function isStringArray(value) {
304916
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
304917
+ }
304918
+ function isNumberArray(value) {
304919
+ return Array.isArray(value) && value.every((item) => typeof item === "number");
304920
+ }
304921
+ function isTaskArray(value) {
304922
+ return Array.isArray(value) && value.every((item) => {
304923
+ if (!isRecord(item))
304924
+ return false;
304925
+ const id = item["id"];
304926
+ const desc = item["description"];
304927
+ return typeof id === "string" && typeof desc === "string";
304928
+ });
304929
+ }
304930
+ function isString(value) {
304931
+ return typeof value === "string";
304932
+ }
304933
+ function findLatestSnapshotBaseline(targets) {
304934
+ const lastSnapshotNode = [...targets].reverse().find((n3) => n3.type === NodeType.SNAPSHOT && n3.payload.text);
304935
+ if (lastSnapshotNode?.payload.text) {
304936
+ return {
304937
+ text: lastSnapshotNode.payload.text,
304938
+ abstractsIds: lastSnapshotNode.abstractsIds ? [...lastSnapshotNode.abstractsIds] : [],
304939
+ id: lastSnapshotNode.id
304940
+ };
304941
+ }
304942
+ return void 0;
304943
+ }
304525
304944
  var SnapshotGenerator = class {
304526
304945
  env;
304527
304946
  constructor(env2) {
304528
304947
  this.env = env2;
304529
304948
  }
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.
304949
+ async synthesizeSnapshot(nodes, previousStateJson, options = {}) {
304950
+ const emptyState = {
304951
+ active_tasks: [],
304952
+ discovered_facts: [],
304953
+ constraints_and_preferences: [],
304954
+ recent_arc: []
304955
+ };
304956
+ let previousState = emptyState;
304957
+ if (previousStateJson) {
304958
+ try {
304959
+ const parsed = JSON.parse(previousStateJson);
304960
+ if (isRecord(parsed)) {
304961
+ let loadedArc = [];
304962
+ if (isStringArray(parsed["recent_arc"])) {
304963
+ loadedArc = parsed["recent_arc"];
304964
+ } else if (isString(parsed["summary"]) && parsed["summary"]) {
304965
+ loadedArc = [parsed["summary"]];
304966
+ }
304967
+ previousState = {
304968
+ active_tasks: isTaskArray(parsed["active_tasks"]) ? parsed["active_tasks"] : [],
304969
+ discovered_facts: isStringArray(parsed["discovered_facts"]) ? parsed["discovered_facts"] : [],
304970
+ constraints_and_preferences: isStringArray(parsed["constraints_and_preferences"]) ? parsed["constraints_and_preferences"] : [],
304971
+ recent_arc: loadedArc
304972
+ };
304973
+ }
304974
+ } catch {
304975
+ }
304976
+ }
304977
+ let pressureWarning = "";
304978
+ const stateString = JSON.stringify(previousState);
304979
+ const estimatedTokens = this.env.tokenCalculator.estimateTokensForString(stateString);
304980
+ const maxTokens = options.maxStateTokens ?? 4e3;
304981
+ if (estimatedTokens > maxTokens * 0.8) {
304982
+ pressureWarning = `
304533
304983
 
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
- `;
304984
+ [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
304985
  }
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 || "";
304986
+ const systemPrompt = `You are an expert Context Memory Manager. You maintain the long-term "Master State" of the AI agent's memory.
304987
+ You will be provided with the CURRENT Master State and a raw transcript of new conversation turns.
304988
+ Your task is to generate a JSON Delta Patch representing what has changed in the transcript.${pressureWarning}
304989
+
304990
+ CRITICAL OPERATIONAL RULES:
304991
+ 1. FACTS: Extract explicit empirical facts (file paths, exact error codes, specific configs).
304992
+ 2. PRUNING: Keep facts dense. Use obsolete indices to aggressively delete facts that are no longer relevant to the current objective.
304993
+ 3. TASKS: Add any new active user requests to "new_tasks".
304994
+ 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.`;
304995
+ const userPromptText = `CURRENT MASTER STATE:
304996
+ ${JSON.stringify(previousState, null, 2)}
304997
+
304998
+ TRANSCRIPT OF NEW TURNS:
304999
+ ${formatNodesForLlm(nodes)}`;
305000
+ const patchSchema = {
305001
+ type: "object",
305002
+ properties: {
305003
+ new_facts: {
305004
+ type: "array",
305005
+ items: { type: "string" },
305006
+ description: "New specific, empirical facts discovered in this transcript chunk."
305007
+ },
305008
+ new_constraints: {
305009
+ type: "array",
305010
+ items: { type: "string" },
305011
+ description: "New specific rules or instructions provided by the user in this chunk."
305012
+ },
305013
+ new_tasks: {
305014
+ type: "array",
305015
+ items: {
305016
+ type: "object",
305017
+ properties: {
305018
+ description: {
305019
+ type: "string",
305020
+ description: "The task goal/description."
305021
+ }
305022
+ }
305023
+ }
305024
+ },
305025
+ resolved_task_ids: {
305026
+ type: "array",
305027
+ items: { type: "string" },
305028
+ description: "IDs of tasks from the CURRENT MASTER STATE that were explicitly completed or abandoned in this transcript chunk."
305029
+ },
305030
+ obsolete_fact_indices: {
305031
+ type: "array",
305032
+ items: { type: "number" },
305033
+ description: "Array indices of facts from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
305034
+ },
305035
+ obsolete_constraint_indices: {
305036
+ type: "array",
305037
+ items: { type: "number" },
305038
+ description: "Array indices of constraints from CURRENT MASTER STATE that are no longer true or relevant and should be deleted."
305039
+ },
305040
+ chronological_summary: {
305041
+ type: "string",
305042
+ description: "A 1-2 sentence summary of the mechanical actions taken in this transcript chunk."
305043
+ }
305044
+ }
305045
+ };
305046
+ let patch = {};
305047
+ try {
305048
+ const result2 = await this.env.llmClient.generateJson({
305049
+ role: LlmRole.UTILITY_STATE_SNAPSHOT_PROCESSOR,
305050
+ modelConfigKey: { model: "context-snapshotter" },
305051
+ contents: [{ role: "user", parts: [{ text: userPromptText }] }],
305052
+ systemInstruction: { role: "system", parts: [{ text: systemPrompt }] },
305053
+ schema: patchSchema,
305054
+ promptId: this.env.promptId,
305055
+ abortSignal: new AbortController().signal
305056
+ });
305057
+ if (isRecord(result2)) {
305058
+ patch = result2;
305059
+ }
305060
+ } catch {
305061
+ return JSON.stringify(previousState);
305062
+ }
305063
+ const newState = {
305064
+ active_tasks: [...previousState.active_tasks],
305065
+ discovered_facts: [...previousState.discovered_facts],
305066
+ constraints_and_preferences: [
305067
+ ...previousState.constraints_and_preferences
305068
+ ],
305069
+ recent_arc: [...previousState.recent_arc]
305070
+ };
305071
+ const resolvedIds = patch["resolved_task_ids"];
305072
+ if (isStringArray(resolvedIds)) {
305073
+ const resolvedSet = new Set(resolvedIds);
305074
+ newState.active_tasks = newState.active_tasks.filter((t2) => !resolvedSet.has(t2.id));
305075
+ }
305076
+ const obsFacts = patch["obsolete_fact_indices"];
305077
+ if (isNumberArray(obsFacts)) {
305078
+ const dropSet = new Set(obsFacts);
305079
+ newState.discovered_facts = newState.discovered_facts.filter((_, i3) => !dropSet.has(i3));
305080
+ }
305081
+ const obsConstraints = patch["obsolete_constraint_indices"];
305082
+ if (isNumberArray(obsConstraints)) {
305083
+ const dropSet = new Set(obsConstraints);
305084
+ newState.constraints_and_preferences = newState.constraints_and_preferences.filter((_, i3) => !dropSet.has(i3));
305085
+ }
305086
+ const newTasks = patch["new_tasks"];
305087
+ if (Array.isArray(newTasks)) {
305088
+ for (const t2 of newTasks) {
305089
+ if (isRecord(t2)) {
305090
+ const desc = t2["description"];
305091
+ if (typeof desc === "string" && desc) {
305092
+ newState.active_tasks.push({
305093
+ id: `task_${randomUUID8().slice(0, 8)}`,
305094
+ description: desc
305095
+ });
305096
+ }
305097
+ }
305098
+ }
305099
+ }
305100
+ const newFacts = patch["new_facts"];
305101
+ if (isStringArray(newFacts)) {
305102
+ newState.discovered_facts.push(...newFacts);
305103
+ }
305104
+ const newConstraints = patch["new_constraints"];
305105
+ if (isStringArray(newConstraints)) {
305106
+ newState.constraints_and_preferences.push(...newConstraints);
305107
+ }
305108
+ const chronoSummary = patch["chronological_summary"];
305109
+ if (typeof chronoSummary === "string" && chronoSummary) {
305110
+ newState.recent_arc.push(chronoSummary);
305111
+ const maxTurns = options.maxSummaryTurns ?? 5;
305112
+ if (newState.recent_arc.length > maxTurns) {
305113
+ newState.recent_arc = newState.recent_arc.slice(-maxTurns);
305114
+ }
305115
+ }
305116
+ let currentTokens = this.env.tokenCalculator.estimateTokensForString(JSON.stringify(newState));
305117
+ while (currentTokens > maxTokens) {
305118
+ if (newState.discovered_facts.length > 0) {
305119
+ newState.discovered_facts.shift();
305120
+ } else if (newState.constraints_and_preferences.length > 0) {
305121
+ newState.constraints_and_preferences.shift();
305122
+ } else if (newState.recent_arc.length > 0) {
305123
+ newState.recent_arc.shift();
305124
+ } else if (newState.active_tasks.length > 0) {
305125
+ newState.active_tasks.shift();
305126
+ } else {
305127
+ break;
305128
+ }
305129
+ currentTokens = this.env.tokenCalculator.estimateTokensForString(JSON.stringify(newState));
305130
+ }
305131
+ return JSON.stringify(newState);
304560
305132
  }
304561
305133
  };
304562
305134
 
@@ -304571,7 +305143,9 @@ var StateSnapshotProcessorOptionsSchema = {
304571
305143
  },
304572
305144
  freeTokensTarget: { type: "number", nullable: true },
304573
305145
  model: { type: "string", nullable: true },
304574
- systemInstruction: { type: "string", nullable: true }
305146
+ systemInstruction: { type: "string", nullable: true },
305147
+ maxSummaryTurns: { type: "number", nullable: true },
305148
+ maxStateTokens: { type: "number", nullable: true }
304575
305149
  },
304576
305150
  required: []
304577
305151
  };
@@ -304595,7 +305169,7 @@ function createStateSnapshotProcessor(id, env2, options) {
304595
305169
  const targetIds = new Set(targets.map((t2) => t2.id));
304596
305170
  const isValid = consumedIds.every((id2) => targetIds.has(id2));
304597
305171
  if (isValid) {
304598
- const newId = randomUUID8();
305172
+ const newId = randomUUID9();
304599
305173
  const snapshotNode = {
304600
305174
  id: newId,
304601
305175
  turnId: newId,
@@ -304636,9 +305210,29 @@ function createStateSnapshotProcessor(id, env2, options) {
304636
305210
  }
304637
305211
  if (nodesToSummarize.length < 2)
304638
305212
  return targets;
305213
+ let previousStateJson = void 0;
305214
+ let baselineIdToConsume = void 0;
305215
+ const baseline = findLatestSnapshotBaseline(targets);
305216
+ if (baseline) {
305217
+ previousStateJson = baseline.text;
305218
+ const summaryIdx = nodesToSummarize.findIndex((n3) => n3.id === baseline.id);
305219
+ if (summaryIdx !== -1) {
305220
+ baselineIdToConsume = baseline.id;
305221
+ nodesToSummarize.splice(summaryIdx, 1);
305222
+ }
305223
+ } else {
305224
+ debugLogger.log("[StateSnapshotProcessor] No previous snapshot found in context graph. Initializing new Master State baseline.");
305225
+ }
304639
305226
  try {
304640
- const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, options.systemInstruction);
304641
- const newId = randomUUID8();
305227
+ const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, previousStateJson, {
305228
+ maxSummaryTurns: options.maxSummaryTurns,
305229
+ maxStateTokens: options.maxStateTokens
305230
+ });
305231
+ const newId = randomUUID9();
305232
+ const consumedIds = nodesToSummarize.map((n3) => n3.id);
305233
+ if (baselineIdToConsume && !consumedIds.includes(baselineIdToConsume)) {
305234
+ consumedIds.push(baselineIdToConsume);
305235
+ }
304642
305236
  const snapshotNode = {
304643
305237
  id: newId,
304644
305238
  turnId: newId,
@@ -304646,9 +305240,8 @@ function createStateSnapshotProcessor(id, env2, options) {
304646
305240
  timestamp: nodesToSummarize[nodesToSummarize.length - 1].timestamp,
304647
305241
  role: "user",
304648
305242
  payload: { text: snapshotText },
304649
- abstractsIds: nodesToSummarize.map((n3) => n3.id)
305243
+ abstractsIds: [...consumedIds]
304650
305244
  };
304651
- const consumedIds = nodesToSummarize.map((n3) => n3.id);
304652
305245
  const returnedNodes = targets.filter((t2) => !consumedIds.includes(t2.id));
304653
305246
  const firstRemovedIdx = targets.findIndex((t2) => consumedIds.includes(t2.id));
304654
305247
  if (firstRemovedIdx !== -1) {
@@ -304667,7 +305260,6 @@ function createStateSnapshotProcessor(id, env2, options) {
304667
305260
  }
304668
305261
 
304669
305262
  // packages/core/dist/src/context/processors/stateSnapshotAsyncProcessor.js
304670
- import { randomUUID as randomUUID9 } from "node:crypto";
304671
305263
  var StateSnapshotAsyncProcessorOptionsSchema = {
304672
305264
  type: "object",
304673
305265
  properties: {
@@ -304676,7 +305268,9 @@ var StateSnapshotAsyncProcessorOptionsSchema = {
304676
305268
  enum: ["accumulate", "point-in-time"],
304677
305269
  nullable: true
304678
305270
  },
304679
- systemInstruction: { type: "string", nullable: true }
305271
+ systemInstruction: { type: "string", nullable: true },
305272
+ maxSummaryTurns: { type: "number", nullable: true },
305273
+ maxStateTokens: { type: "number", nullable: true }
304680
305274
  },
304681
305275
  required: []
304682
305276
  };
@@ -304689,9 +305283,10 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
304689
305283
  if (targets.length === 0)
304690
305284
  return;
304691
305285
  try {
304692
- let nodesToSummarize = [...targets];
304693
305286
  let previousConsumedIds = [];
304694
305287
  const processorType = options.type ?? "point-in-time";
305288
+ const nodesToSummarize = [...targets];
305289
+ let previousStateJson = void 0;
304695
305290
  if (processorType === "accumulate") {
304696
305291
  const proposedSnapshots = inbox.getMessages("PROPOSED_SNAPSHOT");
304697
305292
  const accumulateSnapshots = proposedSnapshots.filter((s2) => s2.payload.type === "accumulate");
@@ -304700,19 +305295,29 @@ function createStateSnapshotAsyncProcessor(id, env2, options) {
304700
305295
  inbox.consume(latest.id);
304701
305296
  env2.inbox.drainConsumed(/* @__PURE__ */ new Set([latest.id]));
304702
305297
  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];
305298
+ previousStateJson = latest.payload.newText;
305299
+ } else {
305300
+ const baseline = findLatestSnapshotBaseline(targets);
305301
+ if (baseline) {
305302
+ previousStateJson = baseline.text;
305303
+ previousConsumedIds = [...baseline.abstractsIds];
305304
+ } else {
305305
+ debugLogger.log("[StateSnapshotAsyncProcessor] No previous snapshot found in Inbox or Graph. Initializing new Master State baseline in background.");
305306
+ }
304713
305307
  }
304714
305308
  }
304715
- const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, options.systemInstruction);
305309
+ if (previousStateJson) {
305310
+ const summaryIdx = nodesToSummarize.findIndex((n3) => n3.type === NodeType.SNAPSHOT && n3.payload.text === previousStateJson);
305311
+ if (summaryIdx !== -1) {
305312
+ nodesToSummarize.splice(summaryIdx, 1);
305313
+ }
305314
+ }
305315
+ if (nodesToSummarize.length === 0)
305316
+ return;
305317
+ const snapshotText = await generator.synthesizeSnapshot(nodesToSummarize, previousStateJson, {
305318
+ maxSummaryTurns: options.maxSummaryTurns,
305319
+ maxStateTokens: options.maxStateTokens
305320
+ });
304716
305321
  const newConsumedIds = [
304717
305322
  ...previousConsumedIds,
304718
305323
  ...targets.map((t2) => t2.id)
@@ -304789,7 +305394,9 @@ var generalistProfile = {
304789
305394
  triggers: ["gc_backstop"],
304790
305395
  processors: [
304791
305396
  createStateSnapshotProcessor("StateSnapshotSync", env2, resolveProcessorOptions(config2, "StateSnapshotSync", {
304792
- target: "max"
305397
+ target: "max",
305398
+ maxStateTokens: 4e3,
305399
+ maxSummaryTurns: 5
304793
305400
  }))
304794
305401
  ]
304795
305402
  }
@@ -304801,7 +305408,9 @@ var generalistProfile = {
304801
305408
  triggers: ["nodes_aged_out"],
304802
305409
  processors: [
304803
305410
  createStateSnapshotAsyncProcessor("StateSnapshotAsync", env2, resolveProcessorOptions(config2, "StateSnapshotAsync", {
304804
- type: "accumulate"
305411
+ type: "accumulate",
305412
+ maxStateTokens: 4e3,
305413
+ maxSummaryTurns: 5
304805
305414
  }))
304806
305415
  ]
304807
305416
  }
@@ -304997,6 +305606,12 @@ var ContextTracer = class {
304997
305606
  // packages/core/dist/src/context/eventBus.js
304998
305607
  import { EventEmitter as EventEmitter4 } from "node:events";
304999
305608
  var ContextEventBus = class extends EventEmitter4 {
305609
+ emitTokenGroundTruth(event) {
305610
+ this.emit("TOKEN_GROUND_TRUTH", event);
305611
+ }
305612
+ onTokenGroundTruth(listener) {
305613
+ this.on("TOKEN_GROUND_TRUTH", listener);
305614
+ }
305000
305615
  emitPristineHistoryUpdated(event) {
305001
305616
  this.emit("PRISTINE_HISTORY_UPDATED", event);
305002
305617
  }
@@ -305023,149 +305638,6 @@ var ContextEventBus = class extends EventEmitter4 {
305023
305638
  }
305024
305639
  };
305025
305640
 
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
305641
  // packages/core/dist/src/context/pipeline/inbox.js
305170
305642
  import { randomUUID as randomUUID11 } from "node:crypto";
305171
305643
  var LiveInbox = class {
@@ -305203,81 +305675,6 @@ var InboxSnapshotImpl = class {
305203
305675
  }
305204
305676
  };
305205
305677
 
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
305678
  // packages/core/dist/src/context/graph/toGraph.js
305282
305679
  import { randomUUID as randomUUID12, createHash as createHash7 } from "node:crypto";
305283
305680
  var PART_HASH_CACHE = /* @__PURE__ */ new WeakMap();
@@ -305347,9 +305744,9 @@ var ContextGraphBuilder = class {
305347
305744
  const msg = history[turnIdx];
305348
305745
  if (!msg.parts)
305349
305746
  continue;
305350
- if (turnIdx === 0 && msg.role === "user" && msg.parts.length === 1) {
305747
+ if (msg.role === "user" && msg.parts.length === 1) {
305351
305748
  const text = msg.parts[0].text;
305352
- if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI.")) {
305749
+ if (text?.startsWith("<session_context>") && text?.includes("This is the Gemini CLI")) {
305353
305750
  debugLogger.log("[ContextGraphBuilder] Skipping legacy environment header turn from graph.");
305354
305751
  continue;
305355
305752
  }
@@ -305449,10 +305846,11 @@ var ContextEnvironmentImpl = class {
305449
305846
  charsPerToken;
305450
305847
  eventBus;
305451
305848
  tokenCalculator;
305452
- inbox;
305453
305849
  behaviorRegistry;
305850
+ renderOptions;
305851
+ inbox;
305454
305852
  graphMapper;
305455
- constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus) {
305853
+ constructor(llmClientProvider, sessionId, promptId, traceDir, projectTempDir, tracer, charsPerToken, eventBus, tokenCalculator, behaviorRegistry, renderOptions) {
305456
305854
  this.llmClientProvider = llmClientProvider;
305457
305855
  this.sessionId = sessionId;
305458
305856
  this.promptId = promptId;
@@ -305461,9 +305859,9 @@ var ContextEnvironmentImpl = class {
305461
305859
  this.tracer = tracer;
305462
305860
  this.charsPerToken = charsPerToken;
305463
305861
  this.eventBus = eventBus;
305464
- this.behaviorRegistry = new NodeBehaviorRegistry();
305465
- registerBuiltInBehaviors(this.behaviorRegistry);
305466
- this.tokenCalculator = new ContextTokenCalculator(this.charsPerToken, this.behaviorRegistry);
305862
+ this.tokenCalculator = tokenCalculator;
305863
+ this.behaviorRegistry = behaviorRegistry;
305864
+ this.renderOptions = renderOptions;
305467
305865
  this.inbox = new LiveInbox();
305468
305866
  this.graphMapper = new ContextGraphMapper();
305469
305867
  }
@@ -305501,30 +305899,6 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305501
305899
  }
305502
305900
  return new _ContextWorkingBufferImpl(pristineNodes, pristineMap, initialProvenance, []);
305503
305901
  }
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
305902
  /**
305529
305903
  * Generates an entirely new buffer instance by calculating the delta between the processor's input and output.
305530
305904
  */
@@ -305602,10 +305976,90 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305602
305976
  finalPristineMap = prunedPristineMap;
305603
305977
  return new _ContextWorkingBufferImpl(newGraph, finalPristineMap, newProvenanceMap, [...this.history, mutation]);
305604
305978
  }
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));
305979
+ /**
305980
+ * Rebuilds the working buffer in the exact chronological order of the authoritative pristine history,
305981
+ * while preserving injected/summarized nodes at their relative positions.
305982
+ */
305983
+ syncPristineHistory(authoritativePristineNodes) {
305984
+ const newPristineMap = new Map(this.pristineNodesMap);
305608
305985
  const newProvenanceMap = new Map(this.provenanceMap);
305986
+ const authoritativeIds = new Set(authoritativePristineNodes.map((n3) => n3.id));
305987
+ for (const node of authoritativePristineNodes) {
305988
+ if (!newPristineMap.has(node.id)) {
305989
+ newPristineMap.set(node.id, node);
305990
+ newProvenanceMap.set(node.id, /* @__PURE__ */ new Set([node.id]));
305991
+ }
305992
+ }
305993
+ const survivingCurrentNodes = this.nodes.filter((n3) => {
305994
+ if (authoritativeIds.has(n3.id))
305995
+ return true;
305996
+ if (!this.pristineNodesMap.has(n3.id))
305997
+ return true;
305998
+ const roots = newProvenanceMap.get(n3.id);
305999
+ return !roots || roots.size === 0;
306000
+ }).filter((n3) => {
306001
+ if (!authoritativeIds.has(n3.id) && !this.pristineNodesMap.has(n3.id)) {
306002
+ const roots = newProvenanceMap.get(n3.id);
306003
+ if (roots && roots.size > 0) {
306004
+ for (const root of roots) {
306005
+ if (!authoritativeIds.has(root)) {
306006
+ return false;
306007
+ }
306008
+ }
306009
+ }
306010
+ }
306011
+ return true;
306012
+ });
306013
+ const coveredPristineIds = /* @__PURE__ */ new Set();
306014
+ for (const node of survivingCurrentNodes) {
306015
+ if (!authoritativeIds.has(node.id)) {
306016
+ const roots = newProvenanceMap.get(node.id);
306017
+ if (roots) {
306018
+ for (const root of roots) {
306019
+ coveredPristineIds.add(root);
306020
+ }
306021
+ }
306022
+ }
306023
+ }
306024
+ const pristineIndexMap = new Map(authoritativePristineNodes.map((n3, idx) => [n3.id, idx]));
306025
+ const getPristineIndex = (nodeId) => {
306026
+ const roots = newProvenanceMap.get(nodeId);
306027
+ if (!roots || roots.size === 0)
306028
+ return -1;
306029
+ let maxIndex = -1;
306030
+ for (const root of roots) {
306031
+ const idx = pristineIndexMap.get(root);
306032
+ if (idx !== void 0 && idx > maxIndex) {
306033
+ maxIndex = idx;
306034
+ }
306035
+ }
306036
+ return maxIndex;
306037
+ };
306038
+ const nodeOrder = new Array();
306039
+ for (let i3 = 0; i3 < authoritativePristineNodes.length; i3++) {
306040
+ const node = authoritativePristineNodes[i3];
306041
+ if (!coveredPristineIds.has(node.id)) {
306042
+ nodeOrder.push({ node, sortKey: i3, originalIndex: -1 });
306043
+ }
306044
+ }
306045
+ for (let i3 = 0; i3 < survivingCurrentNodes.length; i3++) {
306046
+ const node = survivingCurrentNodes[i3];
306047
+ if (!authoritativeIds.has(node.id)) {
306048
+ const baseSortKey = getPristineIndex(node.id);
306049
+ nodeOrder.push({
306050
+ node,
306051
+ sortKey: baseSortKey === -1 ? -1 : baseSortKey + 0.5,
306052
+ // Interleave after pristine roots, or at start if injected
306053
+ originalIndex: i3
306054
+ });
306055
+ }
306056
+ }
306057
+ nodeOrder.sort((a2, b) => {
306058
+ if (a2.sortKey !== b.sortKey)
306059
+ return a2.sortKey - b.sortKey;
306060
+ return a2.originalIndex - b.originalIndex;
306061
+ });
306062
+ const newGraph = nodeOrder.map((item) => item.node);
305609
306063
  const reachablePristineIds = /* @__PURE__ */ new Set();
305610
306064
  const reachableCurrentIds = /* @__PURE__ */ new Set();
305611
306065
  for (const node of newGraph) {
@@ -305613,7 +306067,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305613
306067
  const roots = newProvenanceMap.get(node.id);
305614
306068
  if (roots) {
305615
306069
  for (const root of roots) {
305616
- if (retainedIds.has(root) || !this.pristineNodesMap.has(root)) {
306070
+ if (authoritativeIds.has(root) || !this.pristineNodesMap.has(root)) {
305617
306071
  reachablePristineIds.add(root);
305618
306072
  }
305619
306073
  }
@@ -305626,7 +306080,7 @@ var ContextWorkingBufferImpl = class _ContextWorkingBufferImpl {
305626
306080
  }
305627
306081
  const prunedPristineMap = /* @__PURE__ */ new Map();
305628
306082
  for (const id of reachablePristineIds) {
305629
- const node = this.pristineNodesMap.get(id);
306083
+ const node = newPristineMap.get(id);
305630
306084
  if (node)
305631
306085
  prunedPristineMap.set(id, node);
305632
306086
  }
@@ -305653,6 +306107,7 @@ var PipelineOrchestrator = class {
305653
306107
  activeTimers = [];
305654
306108
  pendingPipelines = /* @__PURE__ */ new Map();
305655
306109
  pipelineMutex = /* @__PURE__ */ new Map();
306110
+ pipelineScheduled = /* @__PURE__ */ new Set();
305656
306111
  nodeProvider;
305657
306112
  constructor(pipelines, asyncPipelines, env2, eventBus, tracer) {
305658
306113
  this.pipelines = pipelines;
@@ -305693,25 +306148,37 @@ var PipelineOrchestrator = class {
305693
306148
  this.activeTimers.push(timer);
305694
306149
  } else if (trigger === "retained_exceeded" || trigger === "nodes_aged_out") {
305695
306150
  this.eventBus.onConsolidationNeeded((event) => {
305696
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
306151
+ void executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
305697
306152
  });
305698
306153
  } else if (trigger === "new_message" || trigger === "nodes_added") {
305699
306154
  this.eventBus.onChunkReceived((event) => {
305700
- executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
306155
+ void executeFn(pipeline, event.nodes, event.targetNodeIds, /* @__PURE__ */ new Set());
305701
306156
  });
305702
306157
  }
305703
306158
  }
305704
306159
  }
305705
306160
  };
305706
- bindTriggers(this.pipelines, (pipeline, nodes, targets, protectedIds) => {
306161
+ const handleSyncExecution = async (pipeline, nodes, targets, protectedIds) => {
306162
+ if (this.pipelineScheduled.has(pipeline.name)) {
306163
+ debugLogger.log(`[Orchestrator] Pipeline ${pipeline.name} already scheduled (sync), dropping.`);
306164
+ return;
306165
+ }
306166
+ this.pipelineScheduled.add(pipeline.name);
305707
306167
  const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
305708
306168
  const nextPromise = (async () => {
305709
306169
  try {
305710
306170
  await existing;
305711
- const latestNodes = this.nodeProvider();
306171
+ this.pipelineScheduled.delete(pipeline.name);
306172
+ const latestNodes = this.nodeProvider ? this.nodeProvider() : nodes;
306173
+ const latestTargets = latestNodes.filter((n3) => targets.has(n3.id));
306174
+ debugLogger.log(`[Orchestrator] Executing sync pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`);
306175
+ if (latestTargets.length === 0) {
306176
+ debugLogger.log(`[Orchestrator] No latest targets for sync pipeline ${pipeline.name}, returning.`);
306177
+ return;
306178
+ }
305712
306179
  await this.executePipelineAsync(pipeline, latestNodes, new Set(targets), new Set(protectedIds));
305713
306180
  } catch (e2) {
305714
- debugLogger.error(`Pipeline chain ${pipeline.name} failed:`, e2);
306181
+ debugLogger.error(`Sync pipeline chain ${pipeline.name} failed:`, e2);
305715
306182
  }
305716
306183
  })();
305717
306184
  this.pipelineMutex.set(pipeline.name, nextPromise);
@@ -305723,18 +306190,47 @@ var PipelineOrchestrator = class {
305723
306190
  this.pipelineMutex.delete(pipeline.name);
305724
306191
  }
305725
306192
  });
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));
306193
+ };
306194
+ const handleAsyncExecution = async (pipeline, nodes, targets) => {
306195
+ if (this.pipelineScheduled.has(pipeline.name)) {
306196
+ debugLogger.log(`[Orchestrator] Pipeline ${pipeline.name} already scheduled (async), dropping.`);
306197
+ return;
305736
306198
  }
305737
- });
306199
+ this.pipelineScheduled.add(pipeline.name);
306200
+ const existing = this.pipelineMutex.get(pipeline.name) || Promise.resolve();
306201
+ const nextPromise = (async () => {
306202
+ try {
306203
+ await existing;
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 async pipeline ${pipeline.name} with ${latestTargets.length} latest targets.`);
306208
+ const inboxSnapshot = new InboxSnapshotImpl(this.env.inbox.getMessages() || []);
306209
+ for (const processor of pipeline.processors) {
306210
+ debugLogger.log(`[Orchestrator] Running async processor ${processor.id}`);
306211
+ await processor.process({
306212
+ targets: latestTargets,
306213
+ inbox: inboxSnapshot,
306214
+ buffer: ContextWorkingBufferImpl.initialize(latestNodes)
306215
+ });
306216
+ }
306217
+ this.env.inbox.drainConsumed(inboxSnapshot.getConsumedIds());
306218
+ } catch (e2) {
306219
+ debugLogger.error(`Async pipeline chain ${pipeline.name} failed:`, e2);
306220
+ }
306221
+ })();
306222
+ this.pipelineMutex.set(pipeline.name, nextPromise);
306223
+ const pipelineId = `${pipeline.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
306224
+ this.pendingPipelines.set(pipelineId, nextPromise);
306225
+ void nextPromise.finally(() => {
306226
+ this.pendingPipelines.delete(pipelineId);
306227
+ if (this.pipelineMutex.get(pipeline.name) === nextPromise) {
306228
+ this.pipelineMutex.delete(pipeline.name);
306229
+ }
306230
+ });
306231
+ };
306232
+ bindTriggers(this.pipelines, (pipeline, nodes, targets, protectedIds) => handleSyncExecution(pipeline, nodes, targets, protectedIds));
306233
+ bindTriggers(this.asyncPipelines, (pipeline, nodes, targets) => handleAsyncExecution(pipeline, nodes, targets));
305738
306234
  }
305739
306235
  shutdown() {
305740
306236
  for (const timer of this.activeTimers) {
@@ -305889,17 +306385,54 @@ var HistoryObserver = class {
305889
306385
  }
305890
306386
  };
305891
306387
 
306388
+ // packages/core/dist/src/context/utils/tokenCalibration.js
306389
+ function performCalibration(env2, finalNodes, finalContents) {
306390
+ if (!env2.renderOptions?.calibrateTokenCalculation) {
306391
+ return;
306392
+ }
306393
+ void (async () => {
306394
+ try {
306395
+ const exactResp = await env2.llmClient.countTokens({
306396
+ contents: finalContents
306397
+ });
306398
+ const exactTokens = typeof exactResp.totalTokens === "number" ? exactResp.totalTokens : 0;
306399
+ const estimatedTokens = env2.tokenCalculator.calculateConcreteListTokens(finalNodes);
306400
+ const delta = Math.abs(exactTokens - estimatedTokens);
306401
+ const tolerance = Math.max(exactTokens, estimatedTokens) * 0.2;
306402
+ env2.tracer.logEvent("Render", "Token Calibration Measurement", {
306403
+ exactTokens,
306404
+ estimatedTokens,
306405
+ delta,
306406
+ isWithinTolerance: delta <= tolerance
306407
+ });
306408
+ if (delta > tolerance) {
306409
+ debugLogger.error(`[Token Calibration] Large deviation detected: exact ${exactTokens} vs estimated ${estimatedTokens} (delta: ${delta})`);
306410
+ }
306411
+ } catch {
306412
+ }
306413
+ })();
306414
+ }
306415
+
305892
306416
  // packages/core/dist/src/context/graph/render.js
305893
- async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionReasons = /* @__PURE__ */ new Map(), headerTokens = 0) {
306417
+ async function render2(nodes, orchestrator, sidecar, tracer, env2, advancedTokenCalculator, protectionReasons = /* @__PURE__ */ new Map(), header, previewNodeIds = /* @__PURE__ */ new Set()) {
306418
+ let headerTokens = 0;
306419
+ let headerBaseUnits = 0;
306420
+ if (header) {
306421
+ const costs = advancedTokenCalculator.calculateContentTokensAndBaseUnits(header);
306422
+ headerTokens = costs.tokens;
306423
+ headerBaseUnits = costs.baseUnits;
306424
+ }
305894
306425
  if (!sidecar.config.budget) {
305895
- const contents2 = env2.graphMapper.fromGraph(nodes);
306426
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
306427
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
305896
306428
  tracer.logEvent("Render", "Render Context to LLM (No Budget)", {
305897
306429
  renderedContext: contents2
305898
306430
  });
305899
- return { history: contents2, didApplyManagement: false };
306431
+ const baseUnits = advancedTokenCalculator.getRawBaseUnits(nodes) + headerBaseUnits;
306432
+ return { history: contents2, didApplyManagement: false, baseUnits };
305900
306433
  }
305901
306434
  const maxTokens = sidecar.config.budget.maxTokens;
305902
- const graphTokens = env2.tokenCalculator.calculateConcreteListTokens(nodes);
306435
+ const { tokens: graphTokens, baseUnits: graphBaseUnits } = advancedTokenCalculator.calculateTokensAndBaseUnits(nodes);
305903
306436
  const currentTokens = graphTokens + headerTokens;
305904
306437
  const protectedIds = new Set(protectionReasons.keys());
305905
306438
  tracer.logEvent("Render", "Budget Audit", {
@@ -305919,11 +306452,17 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305919
306452
  });
305920
306453
  if (currentTokens <= maxTokens) {
305921
306454
  tracer.logEvent("Render", `View is within maxTokens (${currentTokens} <= ${maxTokens}). Returning view.`);
305922
- const contents2 = env2.graphMapper.fromGraph(nodes);
306455
+ const visibleNodes2 = nodes.filter((n3) => !previewNodeIds.has(n3.id));
306456
+ const contents2 = env2.graphMapper.fromGraph(visibleNodes2);
305923
306457
  tracer.logEvent("Render", "Render Context for LLM", {
305924
306458
  renderedContext: contents2
305925
306459
  });
305926
- return { history: contents2, didApplyManagement: false };
306460
+ performCalibration(env2, visibleNodes2, contents2);
306461
+ return {
306462
+ history: contents2,
306463
+ didApplyManagement: false,
306464
+ baseUnits: graphBaseUnits + headerBaseUnits
306465
+ };
305927
306466
  }
305928
306467
  const targetDelta = currentTokens - sidecar.config.budget.retainedTokens;
305929
306468
  tracer.logEvent("Render", `View exceeds maxTokens (${currentTokens} > ${maxTokens}). Hitting Synchronous Pressure Barrier.`, { targetDelta });
@@ -305931,9 +306470,10 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305931
306470
  let rollingTokens = 0;
305932
306471
  for (let i3 = nodes.length - 1; i3 >= 0; i3--) {
305933
306472
  const node = nodes[i3];
306473
+ const priorTokens = rollingTokens;
305934
306474
  const nodeTokens = env2.tokenCalculator.calculateConcreteListTokens([node]);
305935
306475
  rollingTokens += nodeTokens;
305936
- if (rollingTokens > sidecar.config.budget.retainedTokens) {
306476
+ if (priorTokens > sidecar.config.budget.retainedTokens) {
305937
306477
  agedOutNodes.add(node.id);
305938
306478
  }
305939
306479
  }
@@ -305945,12 +306485,17 @@ async function render2(nodes, orchestrator, sidecar, tracer, env2, protectionRea
305945
306485
  skipList.add(id);
305946
306486
  }
305947
306487
  }
305948
- const visibleNodes = processedNodes.filter((n3) => !skipList.has(n3.id));
306488
+ const visibleNodes = processedNodes.filter((n3) => !skipList.has(n3.id) && !previewNodeIds.has(n3.id));
305949
306489
  const contents = env2.graphMapper.fromGraph(visibleNodes);
305950
306490
  tracer.logEvent("Render", "Render Sanitized Context for LLM", {
305951
306491
  renderedContextSanitized: contents
305952
306492
  });
305953
- return { history: contents, didApplyManagement: true };
306493
+ performCalibration(env2, visibleNodes, contents);
306494
+ return {
306495
+ history: contents,
306496
+ didApplyManagement: true,
306497
+ baseUnits: advancedTokenCalculator.getRawBaseUnits(visibleNodes) + headerBaseUnits
306498
+ };
305954
306499
  }
305955
306500
 
305956
306501
  // packages/core/dist/src/context/utils/invariantChecker.js
@@ -305983,6 +306528,7 @@ var ContextManager = class {
305983
306528
  sidecar;
305984
306529
  env;
305985
306530
  tracer;
306531
+ advancedTokenCalculator;
305986
306532
  headerProvider;
305987
306533
  // The master state containing the pristine graph and current active graph.
305988
306534
  buffer = ContextWorkingBufferImpl.initialize([]);
@@ -305990,24 +306536,23 @@ var ContextManager = class {
305990
306536
  // Internal sub-components
305991
306537
  orchestrator;
305992
306538
  historyObserver;
306539
+ // Hysteresis tracking to prevent utility call churn
306540
+ lastTriggeredDeficit = 0;
305993
306541
  // Cache for Anomaly 3 (Redundant Renders)
305994
306542
  lastRenderCache;
305995
- constructor(sidecar, env2, tracer, orchestrator, chatHistory, headerProvider) {
306543
+ hasPerformedHotStart = false;
306544
+ constructor(sidecar, env2, tracer, orchestrator, chatHistory, advancedTokenCalculator, headerProvider) {
305996
306545
  this.sidecar = sidecar;
305997
306546
  this.env = env2;
305998
306547
  this.tracer = tracer;
306548
+ this.advancedTokenCalculator = advancedTokenCalculator;
305999
306549
  this.headerProvider = headerProvider;
306000
306550
  this.eventBus = env2.eventBus;
306001
306551
  this.orchestrator = orchestrator;
306002
306552
  this.orchestrator.setNodeProvider(() => this.buffer.nodes);
306003
306553
  this.historyObserver = new HistoryObserver(chatHistory, this.env.eventBus, this.tracer, this.env.graphMapper);
306004
306554
  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
- }
306555
+ this.buffer = this.buffer.syncPristineHistory(event.nodes);
306011
306556
  this.evaluateTriggers(event.newNodes);
306012
306557
  });
306013
306558
  this.eventBus.onProcessorResult((event) => {
@@ -306051,10 +306596,11 @@ var ContextManager = class {
306051
306596
  }
306052
306597
  for (let i3 = this.buffer.nodes.length - 1; i3 >= 0; i3--) {
306053
306598
  const node = this.buffer.nodes[i3];
306599
+ const priorTokens = rollingTokens;
306054
306600
  rollingTokens += this.env.tokenCalculator.calculateConcreteListTokens([
306055
306601
  node
306056
306602
  ]);
306057
- if (rollingTokens > this.sidecar.config.budget.retainedTokens) {
306603
+ if (priorTokens > this.sidecar.config.budget.retainedTokens) {
306058
306604
  if (!protectedIds.has(node.id)) {
306059
306605
  agedOutNodes.add(node.id);
306060
306606
  }
@@ -306062,8 +306608,13 @@ var ContextManager = class {
306062
306608
  }
306063
306609
  if (agedOutNodes.size > 0) {
306064
306610
  const targetDeficit = currentTokens - this.sidecar.config.budget.retainedTokens;
306611
+ if (targetDeficit < this.lastTriggeredDeficit) {
306612
+ this.lastTriggeredDeficit = targetDeficit;
306613
+ }
306065
306614
  const threshold = this.sidecar.config.budget.coalescingThresholdTokens || 0;
306066
- if (targetDeficit >= threshold) {
306615
+ const growthSinceLast = targetDeficit - this.lastTriggeredDeficit;
306616
+ if (targetDeficit >= threshold && (growthSinceLast >= threshold || this.lastTriggeredDeficit === 0)) {
306617
+ this.lastTriggeredDeficit = targetDeficit;
306067
306618
  this.env.tokenCalculator.garbageCollectCache(new Set(this.buffer.nodes.map((n3) => n3.id)));
306068
306619
  this.eventBus.emitConsolidationNeeded({
306069
306620
  nodes: this.buffer.nodes,
@@ -306071,6 +306622,8 @@ var ContextManager = class {
306071
306622
  targetNodeIds: agedOutNodes
306072
306623
  });
306073
306624
  }
306625
+ } else {
306626
+ this.lastTriggeredDeficit = 0;
306074
306627
  }
306075
306628
  }
306076
306629
  }
@@ -306127,24 +306680,42 @@ var ContextManager = class {
306127
306680
  getNodes() {
306128
306681
  return [...this.buffer.nodes];
306129
306682
  }
306683
+ getEnvironment() {
306684
+ return this.env;
306685
+ }
306130
306686
  /**
306131
306687
  * Executes the final 'gc_backstop' pipeline if necessary, enforcing the token budget,
306132
306688
  * and maps the Episodic Context Graph back into a raw Gemini Content[] array for transmission.
306133
306689
  * This is the primary method called by the agent framework before sending a request.
306134
306690
  */
306135
- async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set()) {
306691
+ async renderHistory(pendingRequest, activeTaskIds = /* @__PURE__ */ new Set(), abortSignal) {
306136
306692
  this.tracer.logEvent("ContextManager", "Starting rendering of LLM context");
306137
- await this.orchestrator.waitForPipelines();
306138
- let nodes = this.buffer.nodes;
306693
+ let previewNodes = [];
306139
306694
  if (pendingRequest) {
306140
- const previewNodes = this.env.graphMapper.applyEvent({
306695
+ previewNodes = this.env.graphMapper.applyEvent({
306141
306696
  type: "PUSH",
306142
306697
  payload: [pendingRequest]
306143
306698
  });
306699
+ }
306700
+ const hotStartPromise = (async () => {
306701
+ if (!this.hasPerformedHotStart) {
306702
+ this.hasPerformedHotStart = true;
306703
+ if (this.buffer.nodes.length > 0) {
306704
+ const nodesForHotStart = [...this.buffer.nodes, ...previewNodes];
306705
+ await this.performHotStartCalibration(nodesForHotStart, abortSignal);
306706
+ }
306707
+ }
306708
+ })();
306709
+ await Promise.all([this.orchestrator.waitForPipelines(), hotStartPromise]);
306710
+ let nodes = this.buffer.nodes;
306711
+ const previewNodeIds = /* @__PURE__ */ new Set();
306712
+ if (previewNodes.length > 0) {
306713
+ for (const n3 of previewNodes) {
306714
+ previewNodeIds.add(n3.id);
306715
+ }
306144
306716
  nodes = [...nodes, ...previewNodes];
306145
306717
  }
306146
306718
  const header = this.headerProvider ? await this.headerProvider() : void 0;
306147
- const headerTokens = header ? this.env.tokenCalculator.calculateContentTokens(header) : 0;
306148
306719
  const graphHash = nodes.map((n3) => n3.id).join("|");
306149
306720
  const headerHash = header ? JSON.stringify(header.parts) : "no-header";
306150
306721
  const totalHash = `${graphHash}::${headerHash}`;
@@ -306153,7 +306724,7 @@ var ContextManager = class {
306153
306724
  return this.lastRenderCache.result;
306154
306725
  }
306155
306726
  const protectionReasons = this.getProtectedNodeIds(nodes, activeTaskIds);
306156
- const { history: renderedHistory, didApplyManagement } = await render2(nodes, this.orchestrator, this.sidecar, this.tracer, this.env, protectionReasons, headerTokens);
306727
+ const { history: renderedHistory, didApplyManagement, baseUnits } = await render2(nodes, this.orchestrator, this.sidecar, this.tracer, this.env, this.advancedTokenCalculator, protectionReasons, header, previewNodeIds);
306157
306728
  checkContextInvariants(this.buffer.nodes, "RenderHistory");
306158
306729
  this.tracer.logEvent("ContextManager", "Finished rendering");
306159
306730
  const combinedHistory = header ? [header, ...renderedHistory] : renderedHistory;
@@ -306161,11 +306732,35 @@ var ContextManager = class {
306161
306732
  history: hardenHistory(combinedHistory, {
306162
306733
  sentinels: this.sidecar.sentinels
306163
306734
  }),
306164
- didApplyManagement
306735
+ didApplyManagement,
306736
+ baseUnits
306165
306737
  };
306166
306738
  this.lastRenderCache = { nodesHash: totalHash, result: result2 };
306167
306739
  return result2;
306168
306740
  }
306741
+ async performHotStartCalibration(nodes, abortSignal) {
306742
+ try {
306743
+ this.tracer.logEvent("ContextManager", "Performing Hot Start Token Calibration");
306744
+ const contents = this.env.graphMapper.fromGraph(nodes);
306745
+ const header = this.headerProvider ? await this.headerProvider() : void 0;
306746
+ const combinedHistory = header ? [header, ...contents] : contents;
306747
+ const baseUnits = this.advancedTokenCalculator.getRawBaseUnits(nodes) + (header ? this.advancedTokenCalculator.getRawBaseUnitsForContent(header) : 0);
306748
+ if (combinedHistory.length > 0) {
306749
+ const result2 = await this.env.llmClient.countTokens({
306750
+ contents: combinedHistory,
306751
+ abortSignal
306752
+ });
306753
+ if (result2.totalTokens > 0) {
306754
+ this.env.eventBus.emitTokenGroundTruth({
306755
+ actualTokens: result2.totalTokens,
306756
+ promptBaseUnits: baseUnits
306757
+ });
306758
+ }
306759
+ }
306760
+ } catch (error40) {
306761
+ this.tracer.logEvent("ContextManager", "Hot Start Token Calibration Failed (Ignored)", { error: error40 });
306762
+ }
306763
+ }
306169
306764
  };
306170
306765
 
306171
306766
  // packages/core/dist/src/context/processors/historyTruncationProcessor.js
@@ -306198,6 +306793,337 @@ var RollingSummaryProcessorOptionsSchema = {
306198
306793
  required: []
306199
306794
  };
306200
306795
 
306796
+ // packages/core/dist/src/context/utils/contextTokenCalculator.js
306797
+ var StaticTokenCalculator = class {
306798
+ charsPerToken;
306799
+ registry;
306800
+ tokenCache = /* @__PURE__ */ new Map();
306801
+ constructor(charsPerToken, registry2) {
306802
+ this.charsPerToken = charsPerToken;
306803
+ this.registry = registry2;
306804
+ }
306805
+ /**
306806
+ * Estimates tokens for a simple string based on character count.
306807
+ * Fast, but inherently inaccurate compared to real model tokenization.
306808
+ */
306809
+ estimateTokensForString(text) {
306810
+ return Math.ceil(text.length / this.charsPerToken);
306811
+ }
306812
+ /**
306813
+ * Fast, simple heuristic conversion from tokens to expected character length.
306814
+ * Useful for calculating truncation thresholds.
306815
+ */
306816
+ tokensToChars(tokens) {
306817
+ return tokens * this.charsPerToken;
306818
+ }
306819
+ /**
306820
+ * Pre-calculates and caches the token cost of a newly minted node.
306821
+ * Because nodes are immutable, this cost never changes for this node ID.
306822
+ */
306823
+ /**
306824
+ * Removes cached token counts for any nodes that are no longer in the given live set.
306825
+ * This prevents unbounded memory growth during long sessions.
306826
+ */
306827
+ garbageCollectCache(liveNodeIds) {
306828
+ for (const [id] of this.tokenCache) {
306829
+ if (!liveNodeIds.has(id)) {
306830
+ this.tokenCache.delete(id);
306831
+ }
306832
+ }
306833
+ }
306834
+ cacheNodeTokens(node) {
306835
+ const behavior = this.registry.get(node.type);
306836
+ const parts2 = behavior.getEstimatableParts(node);
306837
+ const tokens = this.estimateTokensForParts(parts2);
306838
+ this.tokenCache.set(node.id, tokens);
306839
+ return tokens;
306840
+ }
306841
+ /**
306842
+ * Retrieves the token cost of a single node from the cache.
306843
+ * If it misses the cache, it computes it and caches it.
306844
+ */
306845
+ getTokenCost(node) {
306846
+ const cached2 = this.tokenCache.get(node.id);
306847
+ if (cached2 !== void 0)
306848
+ return cached2;
306849
+ return this.cacheNodeTokens(node);
306850
+ }
306851
+ /**
306852
+ * Calculates a detailed breakdown of tokens by category for a list of nodes.
306853
+ * Useful for calibration tracing and debugging overestimation.
306854
+ */
306855
+ calculateTokenBreakdown(nodes) {
306856
+ const breakdown = { total: 0, text: 0, media: 0, tool: 0, overhead: 0 };
306857
+ const seenIds = /* @__PURE__ */ new Set();
306858
+ const seenTurnIds = /* @__PURE__ */ new Set();
306859
+ for (const node of nodes) {
306860
+ if (seenIds.has(node.id))
306861
+ continue;
306862
+ seenIds.add(node.id);
306863
+ if (node.turnId) {
306864
+ if (!seenTurnIds.has(node.turnId)) {
306865
+ seenTurnIds.add(node.turnId);
306866
+ breakdown.overhead += MSG_OVERHEAD_TOKENS;
306867
+ breakdown.total += MSG_OVERHEAD_TOKENS;
306868
+ }
306869
+ }
306870
+ const cost = this.getTokenCost(node);
306871
+ breakdown.total += cost;
306872
+ const behavior = this.registry.get(node.type);
306873
+ const parts2 = behavior.getEstimatableParts(node);
306874
+ for (const part of parts2) {
306875
+ if (typeof part.text === "string") {
306876
+ breakdown.text += estimateTokenCountSync([part], 0, this.charsPerToken);
306877
+ } else if (part.inlineData?.mimeType?.startsWith("image/") || part.fileData?.mimeType?.startsWith("image/")) {
306878
+ breakdown.media += estimateTokenCountSync([part], 0, this.charsPerToken);
306879
+ } else if (part.functionCall || part.functionResponse) {
306880
+ breakdown.tool += estimateTokenCountSync([part], 0, this.charsPerToken);
306881
+ } else {
306882
+ breakdown.overhead += estimateTokenCountSync([part], 0, this.charsPerToken);
306883
+ }
306884
+ }
306885
+ }
306886
+ return breakdown;
306887
+ }
306888
+ /**
306889
+ * For the static calculator, Raw Base Units are exactly the same as the final tokens,
306890
+ * because there is no dynamic learned weight (the multiplier is effectively 1.0).
306891
+ */
306892
+ getRawBaseUnits(nodes) {
306893
+ return this.calculateConcreteListTokens(nodes);
306894
+ }
306895
+ getRawBaseUnitsForContent(content) {
306896
+ return this.calculateContentTokens(content);
306897
+ }
306898
+ calculateTokensAndBaseUnits(nodes) {
306899
+ const baseUnits = this.calculateConcreteListTokens(nodes);
306900
+ return { tokens: baseUnits, baseUnits };
306901
+ }
306902
+ calculateContentTokensAndBaseUnits(content) {
306903
+ const baseUnits = this.calculateContentTokens(content);
306904
+ return { tokens: baseUnits, baseUnits };
306905
+ }
306906
+ /**
306907
+ * Fast calculation for a flat array of ConcreteNodes (The Nodes).
306908
+ * It relies entirely on the O(1) sidecar token cache.
306909
+ */
306910
+ calculateConcreteListTokens(nodes) {
306911
+ let tokens = 0;
306912
+ const seenIds = /* @__PURE__ */ new Set();
306913
+ const seenTurnIds = /* @__PURE__ */ new Set();
306914
+ for (const node of nodes) {
306915
+ if (!seenIds.has(node.id)) {
306916
+ seenIds.add(node.id);
306917
+ tokens += this.getTokenCost(node);
306918
+ if (node.turnId) {
306919
+ if (!seenTurnIds.has(node.turnId)) {
306920
+ seenTurnIds.add(node.turnId);
306921
+ tokens += MSG_OVERHEAD_TOKENS;
306922
+ }
306923
+ }
306924
+ }
306925
+ }
306926
+ return tokens;
306927
+ }
306928
+ /**
306929
+ * Calculates the token cost for a single Gemini Content object.
306930
+ */
306931
+ calculateContentTokens(content) {
306932
+ return this.estimateTokensForParts(content.parts || []) + MSG_OVERHEAD_TOKENS;
306933
+ }
306934
+ /**
306935
+ * Slower, precise estimation for a Gemini Content/Part graph.
306936
+ * Deeply inspects the nested structure and uses the base tokenization math.
306937
+ */
306938
+ partTokenCache = /* @__PURE__ */ new WeakMap();
306939
+ estimateTokensForParts(parts2) {
306940
+ let total = 0;
306941
+ for (const part of parts2) {
306942
+ if (part !== null && typeof part === "object") {
306943
+ let cost = this.partTokenCache.get(part);
306944
+ if (cost === void 0) {
306945
+ cost = estimateTokenCountSync([part], 0, this.charsPerToken);
306946
+ this.partTokenCache.set(part, cost);
306947
+ }
306948
+ total += cost;
306949
+ } else {
306950
+ total += estimateTokenCountSync([part], 0, this.charsPerToken);
306951
+ }
306952
+ }
306953
+ return total;
306954
+ }
306955
+ };
306956
+
306957
+ // packages/core/dist/src/context/utils/adaptiveTokenCalculator.js
306958
+ var AdaptiveTokenCalculator = class {
306959
+ learnedWeight = 1;
306960
+ baseCalculator;
306961
+ constructor(charsPerToken, registry2, eventBus) {
306962
+ this.baseCalculator = new StaticTokenCalculator(charsPerToken, registry2);
306963
+ eventBus.onTokenGroundTruth((event) => {
306964
+ this.handleGroundTruth(event.actualTokens, event.promptBaseUnits);
306965
+ });
306966
+ }
306967
+ handleGroundTruth(actualTokens, promptBaseUnits) {
306968
+ if (promptBaseUnits <= 0)
306969
+ return;
306970
+ const targetWeight = actualTokens / promptBaseUnits;
306971
+ const oldWeight = this.learnedWeight;
306972
+ const learningRate = 0.2;
306973
+ const newWeight = oldWeight * (1 - learningRate) + targetWeight * learningRate;
306974
+ this.learnedWeight = Math.max(0.5, Math.min(newWeight, 2));
306975
+ debugLogger.log(`[AdaptiveTokenCalculator] Learned weight updated to ${this.learnedWeight.toFixed(3)} (API Tokens: ${actualTokens}, Base Units: ${promptBaseUnits}, Target Ratio: ${targetWeight.toFixed(3)})`);
306976
+ }
306977
+ /**
306978
+ * Retrieves the current learned weight multiplier.
306979
+ */
306980
+ getLearnedWeight() {
306981
+ return this.learnedWeight;
306982
+ }
306983
+ /**
306984
+ * Returns the exact, unweighted Base Heuristic Units for the graph.
306985
+ * This is used exactly once per interaction to capture the baseline sent to the API.
306986
+ */
306987
+ getRawBaseUnits(nodes) {
306988
+ return this.baseCalculator.calculateConcreteListTokens(nodes);
306989
+ }
306990
+ /**
306991
+ * Returns the exact, unweighted Base Heuristic Units for a raw content chunk.
306992
+ */
306993
+ getRawBaseUnitsForContent(content) {
306994
+ return this.baseCalculator.calculateContentTokens(content);
306995
+ }
306996
+ calculateTokensAndBaseUnits(nodes) {
306997
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
306998
+ return {
306999
+ tokens: Math.round(baseUnits * this.learnedWeight),
307000
+ baseUnits
307001
+ };
307002
+ }
307003
+ calculateContentTokensAndBaseUnits(content) {
307004
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
307005
+ return {
307006
+ tokens: Math.round(baseUnits * this.learnedWeight),
307007
+ baseUnits
307008
+ };
307009
+ }
307010
+ // --- Delegation and Weighting ---
307011
+ garbageCollectCache(liveNodeIds) {
307012
+ this.baseCalculator.garbageCollectCache(liveNodeIds);
307013
+ }
307014
+ cacheNodeTokens(node) {
307015
+ return this.baseCalculator.cacheNodeTokens(node);
307016
+ }
307017
+ calculateTokenBreakdown(nodes) {
307018
+ const raw = this.baseCalculator.calculateTokenBreakdown(nodes);
307019
+ return {
307020
+ text: Math.round(raw.text * this.learnedWeight),
307021
+ media: Math.round(raw.media * this.learnedWeight),
307022
+ tool: Math.round(raw.tool * this.learnedWeight),
307023
+ overhead: Math.round(raw.overhead * this.learnedWeight),
307024
+ total: Math.round(raw.total * this.learnedWeight)
307025
+ };
307026
+ }
307027
+ estimateTokensForParts(parts2) {
307028
+ const baseUnits = this.baseCalculator.estimateTokensForParts(parts2);
307029
+ return Math.round(baseUnits * this.learnedWeight);
307030
+ }
307031
+ getTokenCost(node) {
307032
+ const baseUnits = this.baseCalculator.getTokenCost(node);
307033
+ return Math.round(baseUnits * this.learnedWeight);
307034
+ }
307035
+ calculateConcreteListTokens(nodes) {
307036
+ const baseUnits = this.baseCalculator.calculateConcreteListTokens(nodes);
307037
+ return Math.round(baseUnits * this.learnedWeight);
307038
+ }
307039
+ calculateContentTokens(content) {
307040
+ const baseUnits = this.baseCalculator.calculateContentTokens(content);
307041
+ return Math.round(baseUnits * this.learnedWeight);
307042
+ }
307043
+ estimateTokensForString(text) {
307044
+ const baseUnits = this.baseCalculator.estimateTokensForString(text);
307045
+ return Math.round(baseUnits * this.learnedWeight);
307046
+ }
307047
+ tokensToChars(tokens) {
307048
+ return this.baseCalculator.tokensToChars(tokens / this.learnedWeight);
307049
+ }
307050
+ };
307051
+
307052
+ // packages/core/dist/src/context/graph/behaviorRegistry.js
307053
+ var NodeBehaviorRegistry = class {
307054
+ behaviors = /* @__PURE__ */ new Map();
307055
+ register(behavior) {
307056
+ this.behaviors.set(behavior.type, behavior);
307057
+ }
307058
+ get(type2) {
307059
+ const behavior = this.behaviors.get(type2);
307060
+ if (!behavior) {
307061
+ throw new Error(`Unregistered Node type: ${type2}`);
307062
+ }
307063
+ return behavior;
307064
+ }
307065
+ };
307066
+
307067
+ // packages/core/dist/src/context/graph/builtinBehaviors.js
307068
+ var UserPromptBehavior = {
307069
+ type: NodeType.USER_PROMPT,
307070
+ getEstimatableParts(node) {
307071
+ return [node.payload];
307072
+ }
307073
+ };
307074
+ var AgentThoughtBehavior = {
307075
+ type: NodeType.AGENT_THOUGHT,
307076
+ getEstimatableParts(node) {
307077
+ return [node.payload];
307078
+ }
307079
+ };
307080
+ var ToolExecutionBehavior = {
307081
+ type: NodeType.TOOL_EXECUTION,
307082
+ getEstimatableParts(node) {
307083
+ return [node.payload];
307084
+ }
307085
+ };
307086
+ var MaskedToolBehavior = {
307087
+ type: NodeType.MASKED_TOOL,
307088
+ getEstimatableParts(node) {
307089
+ return [node.payload];
307090
+ }
307091
+ };
307092
+ var AgentYieldBehavior = {
307093
+ type: NodeType.AGENT_YIELD,
307094
+ getEstimatableParts() {
307095
+ return [];
307096
+ }
307097
+ };
307098
+ var SystemEventBehavior = {
307099
+ type: NodeType.SYSTEM_EVENT,
307100
+ getEstimatableParts(node) {
307101
+ return [node.payload];
307102
+ }
307103
+ };
307104
+ var SnapshotBehavior = {
307105
+ type: NodeType.SNAPSHOT,
307106
+ getEstimatableParts(node) {
307107
+ return [node.payload];
307108
+ }
307109
+ };
307110
+ var RollingSummaryBehavior = {
307111
+ type: NodeType.ROLLING_SUMMARY,
307112
+ getEstimatableParts(node) {
307113
+ return [node.payload];
307114
+ }
307115
+ };
307116
+ function registerBuiltInBehaviors(registry2) {
307117
+ registry2.register(UserPromptBehavior);
307118
+ registry2.register(AgentThoughtBehavior);
307119
+ registry2.register(ToolExecutionBehavior);
307120
+ registry2.register(MaskedToolBehavior);
307121
+ registry2.register(AgentYieldBehavior);
307122
+ registry2.register(SystemEventBehavior);
307123
+ registry2.register(SnapshotBehavior);
307124
+ registry2.register(RollingSummaryBehavior);
307125
+ }
307126
+
306201
307127
  // packages/core/dist/src/context/initializer.js
306202
307128
  async function initializeContextManager(config2, chat, lastPromptId) {
306203
307129
  const isV1Enabled = config2.getContextManagementConfig().enabled;
@@ -306247,9 +307173,15 @@ async function initializeContextManager(config2, chat, lastPromptId) {
306247
307173
  sessionId: lastPromptId
306248
307174
  });
306249
307175
  const eventBus = new ContextEventBus();
306250
- const env2 = new ContextEnvironmentImpl(() => config2.getBaseLlmClient(), config2.getSessionId(), lastPromptId, logDir, projectTempDir, tracer, 4, eventBus);
307176
+ const charsPerToken = 3;
307177
+ const behaviorRegistry = new NodeBehaviorRegistry();
307178
+ registerBuiltInBehaviors(behaviorRegistry);
307179
+ const calculator = new AdaptiveTokenCalculator(charsPerToken, behaviorRegistry, eventBus);
307180
+ const env2 = new ContextEnvironmentImpl(() => config2.getBaseLlmClient(), config2.getSessionId(), lastPromptId, logDir, projectTempDir, tracer, charsPerToken, eventBus, calculator, behaviorRegistry, {
307181
+ calibrateTokenCalculation: !!process.env["GEMINI_CONTEXT_CALIBRATE_TOKEN_CALCULATIONS"]
307182
+ });
306251
307183
  const orchestrator = new PipelineOrchestrator(sidecarProfile.buildPipelines(env2), sidecarProfile.buildAsyncPipelines(env2), env2, eventBus, tracer);
306252
- return new ContextManager(sidecarProfile, env2, tracer, orchestrator, chat.agentHistory, async () => {
307184
+ return new ContextManager(sidecarProfile, env2, tracer, orchestrator, chat.agentHistory, calculator, async () => {
306253
307185
  const parts2 = await getEnvironmentContext(config2);
306254
307186
  return { role: "user", parts: parts2 };
306255
307187
  });
@@ -306619,10 +307551,12 @@ var GeminiClient = class {
306619
307551
  return turn;
306620
307552
  }
306621
307553
  const modelForLimitCheck = this._getActiveModelForCurrentTurn();
307554
+ let currentBaseUnits = 0;
306622
307555
  if (this.config.getContextManagementConfig().enabled) {
306623
307556
  if (this.contextManager) {
306624
307557
  const pendingRequest = createUserContent(request);
306625
- const { history: newHistory, didApplyManagement } = await this.contextManager.renderHistory(pendingRequest);
307558
+ const { history: newHistory, didApplyManagement, baseUnits } = await this.contextManager.renderHistory(pendingRequest, void 0, signal);
307559
+ currentBaseUnits = baseUnits;
306626
307560
  if (didApplyManagement) {
306627
307561
  this.getChat().setHistory(newHistory, { silent: true });
306628
307562
  }
@@ -306722,6 +307656,15 @@ var GeminiClient = class {
306722
307656
  break;
306723
307657
  }
306724
307658
  yield event;
307659
+ if (event.type === GeminiEventType.Finished && this.contextManager) {
307660
+ const usageMetadata = event.value.usageMetadata;
307661
+ if (usageMetadata && usageMetadata.promptTokenCount !== void 0) {
307662
+ this.contextManager.getEnvironment().eventBus.emitTokenGroundTruth({
307663
+ actualTokens: usageMetadata.promptTokenCount,
307664
+ promptBaseUnits: currentBaseUnits
307665
+ });
307666
+ }
307667
+ }
306725
307668
  this.updateTelemetryTokenCount();
306726
307669
  if (event.type === GeminiEventType.Error) {
306727
307670
  isError = true;
@@ -307215,7 +308158,7 @@ var ToolExecutor = class {
307215
308158
  completedToolCall = await this.createSuccessResult(call, toolResult);
307216
308159
  } else {
307217
308160
  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);
308161
+ completedToolCall = this.createErrorResult(call, new Error(toolResult.error.message), toolResult.error.type, displayText, toolResult.tailToolCallRequest, toolResult.display);
307219
308162
  }
307220
308163
  } catch (executionError) {
307221
308164
  spanMetadata.error = executionError;
@@ -307313,6 +308256,7 @@ var ToolExecutor = class {
307313
308256
  response: {
307314
308257
  callId: call.request.callId,
307315
308258
  responseParts,
308259
+ display: toolResult?.display,
307316
308260
  resultDisplay: toolResult?.returnDisplay,
307317
308261
  error: void 0,
307318
308262
  errorType: void 0,
@@ -307335,6 +308279,7 @@ var ToolExecutor = class {
307335
308279
  const successResponse = {
307336
308280
  callId,
307337
308281
  responseParts: response,
308282
+ display: toolResult.display,
307338
308283
  resultDisplay: toolResult.returnDisplay,
307339
308284
  error: void 0,
307340
308285
  errorType: void 0,
@@ -307359,8 +308304,8 @@ var ToolExecutor = class {
307359
308304
  tailToolCallRequest: toolResult.tailToolCallRequest
307360
308305
  };
307361
308306
  }
307362
- createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest) {
307363
- const response = this.createErrorResponse(call.request, error40, errorType, returnDisplay);
308307
+ createErrorResult(call, error40, errorType, returnDisplay, tailToolCallRequest, display) {
308308
+ const response = this.createErrorResponse(call.request, error40, errorType, returnDisplay, display);
307364
308309
  const startTime = "startTime" in call ? call.startTime : void 0;
307365
308310
  return {
307366
308311
  status: CoreToolCallStatus.Error,
@@ -307374,11 +308319,12 @@ var ToolExecutor = class {
307374
308319
  tailToolCallRequest
307375
308320
  };
307376
308321
  }
307377
- createErrorResponse(request, error40, errorType, returnDisplay) {
308322
+ createErrorResponse(request, error40, errorType, returnDisplay, display) {
307378
308323
  const displayText = returnDisplay ?? error40.message;
307379
308324
  return {
307380
308325
  callId: request.callId,
307381
308326
  error: error40,
308327
+ display,
307382
308328
  responseParts: [
307383
308329
  {
307384
308330
  functionResponse: {
@@ -307650,6 +308596,16 @@ var Scheduler = class {
307650
308596
  }, () => {
307651
308597
  try {
307652
308598
  const invocation = tool.build(request.args);
308599
+ if (!request.display) {
308600
+ request.display = populateToolDisplay({
308601
+ name: tool.name,
308602
+ invocation,
308603
+ displayName: tool.displayName
308604
+ });
308605
+ if (!request.display.description) {
308606
+ request.display.description = tool.description;
308607
+ }
308608
+ }
307653
308609
  return {
307654
308610
  status: CoreToolCallStatus.Validating,
307655
308611
  request,
@@ -308376,8 +309332,8 @@ var WorkspaceContext = class {
308376
309332
  * @returns True if the path is within the root directory, false otherwise
308377
309333
  */
308378
309334
  isPathWithinRoot(pathToCheck, rootDirectory) {
308379
- const relative12 = path61.relative(rootDirectory, pathToCheck);
308380
- return !relative12.startsWith(`..${path61.sep}`) && relative12 !== ".." && !path61.isAbsolute(relative12);
309335
+ const relative11 = path61.relative(rootDirectory, pathToCheck);
309336
+ return !relative11.startsWith(`..${path61.sep}`) && relative11 !== ".." && !path61.isAbsolute(relative11);
308381
309337
  }
308382
309338
  };
308383
309339
 
@@ -308702,6 +309658,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
308702
309658
  compressionService;
308703
309659
  parentCallId;
308704
309660
  hasFailedCompressionAttempt = false;
309661
+ cache;
308705
309662
  get executionContext() {
308706
309663
  return {
308707
309664
  config: this.context.config,
@@ -308819,6 +309776,7 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
308819
309776
  this.onActivity = onActivity;
308820
309777
  this.compressionService = new ChatCompressionService();
308821
309778
  this.parentCallId = parentCallId;
309779
+ this.cache = new import_lru_cache.default(10);
308822
309780
  this.agentId = Math.random().toString(36).slice(2, 8);
308823
309781
  }
308824
309782
  /**
@@ -309019,7 +309977,14 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309019
309977
  try {
309020
309978
  const initialHints = this.context.config.injectionService.getInjectionsAfter(startIndex, "user_steering");
309021
309979
  const formattedInitialHints = formatUserHintsForModel(initialHints);
309022
- const environmentMemory = this.context.config.isJitContextEnabled?.() ? this.context.config.getSessionMemory() : this.context.config.getEnvironmentMemory();
309980
+ let environmentMemory;
309981
+ if (this.context.config.isJitContextEnabled?.()) {
309982
+ environmentMemory = this.definition.includeExtensionContext === false ? this.context.config.getSessionMemory({
309983
+ includeExtensionContext: false
309984
+ }) : this.context.config.getSessionMemory();
309985
+ } else {
309986
+ environmentMemory = this.context.config.getEnvironmentMemory();
309987
+ }
309023
309988
  const initialParts = [];
309024
309989
  if (environmentMemory) {
309025
309990
  initialParts.push({ text: environmentMemory });
@@ -309222,22 +310187,26 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309222
310187
  const requestedModel = resolvedConfig.model;
309223
310188
  let modelToUse;
309224
310189
  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;
310190
+ modelToUse = this.cache.get("modelToUse");
310191
+ if (!modelToUse) {
310192
+ try {
310193
+ const routingContext = {
310194
+ history: chat.getHistory(
310195
+ /*curated=*/
310196
+ true
310197
+ ),
310198
+ request: message.parts || [],
310199
+ signal,
310200
+ requestedModel
310201
+ };
310202
+ const router = this.context.config.getModelRouterService();
310203
+ const decision = await router.route(routingContext);
310204
+ modelToUse = decision.model;
310205
+ } catch (error40) {
310206
+ debugLogger.warn(`Error during model routing: ${error40}`);
310207
+ modelToUse = DEFAULT_GEMINI_MODEL;
310208
+ }
310209
+ this.cache.set("modelToUse", modelToUse);
309241
310210
  }
309242
310211
  } else {
309243
310212
  modelToUse = requestedModel;
@@ -309446,12 +310415,14 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
309446
310415
  const part = syncResults.get(callId);
309447
310416
  if (part) {
309448
310417
  toolResponseParts.push(part);
310418
+ continue;
309449
310419
  }
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
- });
310420
+ const isAborted = signal.aborted;
310421
+ const isTaskComplete = functionCall.name === COMPLETE_TASK_TOOL_NAME && taskCompleted;
310422
+ if (isAborted || isTaskComplete) {
310423
+ continue;
310424
+ }
310425
+ 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
310426
  }
309456
310427
  return {
309457
310428
  nextMessage: { role: "user", parts: toolResponseParts },
@@ -309760,7 +310731,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309760
310731
  isSubagentProgress: true,
309761
310732
  agentName: this.definition.name,
309762
310733
  recentActivity: [],
309763
- state: "running"
310734
+ state: SubagentState.RUNNING
309764
310735
  };
309765
310736
  updateOutput(initialProgress);
309766
310737
  }
@@ -309772,14 +310743,14 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309772
310743
  case "THOUGHT_CHUNK": {
309773
310744
  const text = String(activity.data["text"]);
309774
310745
  const lastItem = recentActivity[recentActivity.length - 1];
309775
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
310746
+ if (lastItem && lastItem.type === "thought" && lastItem.status === SubagentState.RUNNING) {
309776
310747
  lastItem.content = sanitizeThoughtContent(text);
309777
310748
  } else {
309778
310749
  recentActivity.push({
309779
310750
  id: randomUUID14(),
309780
310751
  type: "thought",
309781
310752
  content: sanitizeThoughtContent(text),
309782
- status: "running"
310753
+ status: SubagentState.RUNNING
309783
310754
  });
309784
310755
  }
309785
310756
  updated = true;
@@ -309801,7 +310772,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309801
310772
  displayName,
309802
310773
  description,
309803
310774
  args: args2,
309804
- status: "running"
310775
+ status: SubagentState.RUNNING
309805
310776
  });
309806
310777
  updated = true;
309807
310778
  const latestTool = recentActivity[recentActivity.length - 1];
@@ -309815,8 +310786,8 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309815
310786
  const data = activity.data["data"];
309816
310787
  const isError = isToolActivityError(data);
309817
310788
  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";
310789
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === name3 && recentActivity[i3].status === SubagentState.RUNNING) {
310790
+ recentActivity[i3].status = isError ? SubagentState.ERROR : SubagentState.COMPLETED;
309820
310791
  updated = true;
309821
310792
  this.publishActivity(recentActivity[i3]);
309822
310793
  break;
@@ -309833,16 +310804,16 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309833
310804
  const toolName = activity.data["name"] ? String(activity.data["name"]) : void 0;
309834
310805
  if (toolName && (isCancellation || isRejection)) {
309835
310806
  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";
310807
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === SubagentState.RUNNING) {
310808
+ recentActivity[i3].status = SubagentState.CANCELLED;
309838
310809
  updated = true;
309839
310810
  break;
309840
310811
  }
309841
310812
  }
309842
310813
  } else if (toolName) {
309843
310814
  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";
310815
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].content === toolName && recentActivity[i3].status === SubagentState.RUNNING) {
310816
+ recentActivity[i3].status = SubagentState.ERROR;
309846
310817
  updated = true;
309847
310818
  break;
309848
310819
  }
@@ -309852,7 +310823,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309852
310823
  id: randomUUID14(),
309853
310824
  type: "thought",
309854
310825
  content: isCancellation || isRejection ? sanitizedError : `Error: ${sanitizedError}`,
309855
- status: isCancellation || isRejection ? "cancelled" : "error"
310826
+ status: isCancellation || isRejection ? SubagentState.CANCELLED : SubagentState.ERROR
309856
310827
  });
309857
310828
  updated = true;
309858
310829
  break;
@@ -309866,7 +310837,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309866
310837
  agentName: this.definition.name,
309867
310838
  recentActivity: [...recentActivity],
309868
310839
  // Copy to avoid mutation issues
309869
- state: "running"
310840
+ state: SubagentState.RUNNING
309870
310841
  };
309871
310842
  updateOutput(progress2);
309872
310843
  }
@@ -309878,7 +310849,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309878
310849
  isSubagentProgress: true,
309879
310850
  agentName: this.definition.name,
309880
310851
  recentActivity: [...recentActivity],
309881
- state: "cancelled"
310852
+ state: SubagentState.CANCELLED
309882
310853
  };
309883
310854
  if (updateOutput) {
309884
310855
  updateOutput(progress2);
@@ -309891,7 +310862,7 @@ var LocalSubagentInvocation = class extends BaseToolInvocation {
309891
310862
  isSubagentProgress: true,
309892
310863
  agentName: this.definition.name,
309893
310864
  recentActivity: [...recentActivity],
309894
- state: "completed",
310865
+ state: SubagentState.COMPLETED,
309895
310866
  result: output.result,
309896
310867
  terminateReason: output.terminate_reason
309897
310868
  };
@@ -309912,18 +310883,18 @@ ${output.result}`;
309912
310883
  debugLogger.error(`Subagent '${this.definition.name}' failed:`, error40);
309913
310884
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || errorMessage.includes("Aborted");
309914
310885
  for (const item of recentActivity) {
309915
- if (item.status === "running") {
309916
- item.status = isAbort ? "cancelled" : "error";
310886
+ if (item.status === SubagentState.RUNNING) {
310887
+ item.status = isAbort ? SubagentState.CANCELLED : SubagentState.ERROR;
309917
310888
  }
309918
310889
  }
309919
310890
  if (!isAbort) {
309920
310891
  const lastActivity = recentActivity[recentActivity.length - 1];
309921
- if (!lastActivity || lastActivity.status !== "error") {
310892
+ if (!lastActivity || lastActivity.status !== SubagentState.ERROR) {
309922
310893
  recentActivity.push({
309923
310894
  id: randomUUID14(),
309924
310895
  type: "thought",
309925
310896
  content: `Error: ${errorMessage}`,
309926
- status: "error"
310897
+ status: SubagentState.ERROR
309927
310898
  });
309928
310899
  }
309929
310900
  }
@@ -309931,7 +310902,7 @@ ${output.result}`;
309931
310902
  isSubagentProgress: true,
309932
310903
  agentName: this.definition.name,
309933
310904
  recentActivity: [...recentActivity],
309934
- state: isAbort ? "cancelled" : "error"
310905
+ state: isAbort ? SubagentState.CANCELLED : SubagentState.ERROR
309935
310906
  };
309936
310907
  if (updateOutput) {
309937
310908
  updateOutput(progress);
@@ -310046,7 +311017,7 @@ var A2AResultReassembler = class {
310046
311017
  id: "auth-required",
310047
311018
  type: "thought",
310048
311019
  content: AUTH_REQUIRED_MSG,
310049
- status: "running"
311020
+ status: SubagentState.RUNNING
310050
311021
  });
310051
311022
  }
310052
311023
  this.messageLog.forEach((msg, index) => {
@@ -310054,7 +311025,7 @@ var A2AResultReassembler = class {
310054
311025
  id: `msg-${index}`,
310055
311026
  type: "thought",
310056
311027
  content: msg.trim(),
310057
- status: "completed"
311028
+ status: SubagentState.COMPLETED
310058
311029
  });
310059
311030
  });
310060
311031
  if (items.length === 0 && !isAuthRequired) {
@@ -310062,7 +311033,7 @@ var A2AResultReassembler = class {
310062
311033
  id: "pending",
310063
311034
  type: "thought",
310064
311035
  content: "Working...",
310065
- status: "running"
311036
+ status: SubagentState.RUNNING
310066
311037
  });
310067
311038
  }
310068
311039
  return items;
@@ -310247,13 +311218,13 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
310247
311218
  updateOutput({
310248
311219
  isSubagentProgress: true,
310249
311220
  agentName,
310250
- state: "running",
311221
+ state: SubagentState.RUNNING,
310251
311222
  recentActivity: [
310252
311223
  {
310253
311224
  id: "pending",
310254
311225
  type: "thought",
310255
311226
  content: "Working...",
310256
- status: "running"
311227
+ status: SubagentState.RUNNING
310257
311228
  }
310258
311229
  ]
310259
311230
  });
@@ -310284,7 +311255,7 @@ var RemoteAgentInvocation = class _RemoteAgentInvocation extends BaseToolInvocat
310284
311255
  updateOutput({
310285
311256
  isSubagentProgress: true,
310286
311257
  agentName,
310287
- state: "running",
311258
+ state: SubagentState.RUNNING,
310288
311259
  recentActivity: reassembler.toActivityItems(),
310289
311260
  result: reassembler.toString()
310290
311261
  });
@@ -310304,7 +311275,7 @@ ${JSON.stringify(finalResponse, null, 2)}`);
310304
311275
  const finalProgress = {
310305
311276
  isSubagentProgress: true,
310306
311277
  agentName,
310307
- state: "completed",
311278
+ state: SubagentState.COMPLETED,
310308
311279
  result: finalOutput,
310309
311280
  recentActivity: reassembler.toActivityItems()
310310
311281
  };
@@ -310324,7 +311295,7 @@ ${errorMessage}` : errorMessage;
310324
311295
  const errorProgress = {
310325
311296
  isSubagentProgress: true,
310326
311297
  agentName,
310327
- state: "error",
311298
+ state: SubagentState.ERROR,
310328
311299
  result: fullDisplay,
310329
311300
  recentActivity: reassembler.toActivityItems()
310330
311301
  };
@@ -311834,7 +312805,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311834
312805
  isSubagentProgress: true,
311835
312806
  agentName: this.agentName,
311836
312807
  recentActivity: [],
311837
- state: "running"
312808
+ state: SubagentState.RUNNING
311838
312809
  };
311839
312810
  updateOutput(initialProgress);
311840
312811
  }
@@ -311844,7 +312815,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311844
312815
  id: randomUUID15(),
311845
312816
  type: "thought",
311846
312817
  content: sanitizedMsg,
311847
- status: "completed"
312818
+ status: SubagentState.COMPLETED
311848
312819
  });
311849
312820
  if (recentActivity.length > MAX_RECENT_ACTIVITY) {
311850
312821
  recentActivity = recentActivity.slice(-MAX_RECENT_ACTIVITY);
@@ -311853,7 +312824,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311853
312824
  isSubagentProgress: true,
311854
312825
  agentName: this.agentName,
311855
312826
  recentActivity: [...recentActivity],
311856
- state: "running"
312827
+ state: SubagentState.RUNNING
311857
312828
  });
311858
312829
  } : void 0;
311859
312830
  const result2 = await createBrowserAgentDefinition(this.config, this.messageBus, printOutput);
@@ -311869,14 +312840,14 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311869
312840
  case "THOUGHT_CHUNK": {
311870
312841
  const text = String(activity.data["text"]);
311871
312842
  const lastItem = recentActivity[recentActivity.length - 1];
311872
- if (lastItem && lastItem.type === "thought" && lastItem.status === "running") {
312843
+ if (lastItem && lastItem.type === "thought" && lastItem.status === SubagentState.RUNNING) {
311873
312844
  lastItem.content = sanitizeThoughtContent(text);
311874
312845
  } else {
311875
312846
  recentActivity.push({
311876
312847
  id: randomUUID15(),
311877
312848
  type: "thought",
311878
312849
  content: sanitizeThoughtContent(text),
311879
- status: "running"
312850
+ status: SubagentState.RUNNING
311880
312851
  });
311881
312852
  }
311882
312853
  updated = true;
@@ -311895,7 +312866,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311895
312866
  displayName,
311896
312867
  description,
311897
312868
  args: args2,
311898
- status: "running"
312869
+ status: SubagentState.RUNNING
311899
312870
  });
311900
312871
  updated = true;
311901
312872
  break;
@@ -311905,8 +312876,8 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311905
312876
  const data = activity.data["data"];
311906
312877
  const isError = isToolActivityError(data);
311907
312878
  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";
312879
+ if (recentActivity[i3].type === "tool_call" && callId != null && recentActivity[i3].id === callId && recentActivity[i3].status === SubagentState.RUNNING) {
312880
+ recentActivity[i3].status = isError ? SubagentState.ERROR : SubagentState.COMPLETED;
311910
312881
  updated = true;
311911
312882
  break;
311912
312883
  }
@@ -311917,10 +312888,10 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311917
312888
  const error40 = String(activity.data["error"]);
311918
312889
  const isCancellation = error40 === "Request cancelled.";
311919
312890
  const callId = activity.data["callId"] ? String(activity.data["callId"]) : void 0;
311920
- const newStatus = isCancellation ? "cancelled" : "error";
312891
+ const newStatus = isCancellation ? SubagentState.CANCELLED : SubagentState.ERROR;
311921
312892
  if (callId) {
311922
312893
  for (let i3 = recentActivity.length - 1; i3 >= 0; i3--) {
311923
- if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === "running") {
312894
+ if (recentActivity[i3].type === "tool_call" && recentActivity[i3].id === callId && recentActivity[i3].status === SubagentState.RUNNING) {
311924
312895
  recentActivity[i3].status = newStatus;
311925
312896
  updated = true;
311926
312897
  break;
@@ -311928,7 +312899,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311928
312899
  }
311929
312900
  } else {
311930
312901
  for (const item of recentActivity) {
311931
- if (item.type === "tool_call" && item.status === "running") {
312902
+ if (item.type === "tool_call" && item.status === SubagentState.RUNNING) {
311932
312903
  item.status = newStatus;
311933
312904
  updated = true;
311934
312905
  }
@@ -311955,7 +312926,7 @@ var BrowserAgentInvocation = class extends BaseToolInvocation {
311955
312926
  isSubagentProgress: true,
311956
312927
  agentName: this.agentName,
311957
312928
  recentActivity: [...recentActivity],
311958
- state: "running"
312929
+ state: SubagentState.RUNNING
311959
312930
  };
311960
312931
  updateOutput(progress2);
311961
312932
  }
@@ -311974,11 +312945,11 @@ Result:
311974
312945
  ${output.result}`;
311975
312946
  let progressState;
311976
312947
  if (output.terminate_reason === AgentTerminateMode.ABORTED) {
311977
- progressState = "cancelled";
312948
+ progressState = SubagentState.CANCELLED;
311978
312949
  } else if (output.terminate_reason === AgentTerminateMode.GOAL) {
311979
- progressState = "completed";
312950
+ progressState = SubagentState.COMPLETED;
311980
312951
  } else {
311981
- progressState = "error";
312952
+ progressState = SubagentState.ERROR;
311982
312953
  }
311983
312954
  const progress = {
311984
312955
  isSubagentProgress: true,
@@ -312000,15 +312971,15 @@ ${output.result}`;
312000
312971
  const isAbort = error40 instanceof Error && error40.name === "AbortError" || rawErrorMessage.includes("Aborted");
312001
312972
  const errorMessage = sanitizeErrorMessage(rawErrorMessage);
312002
312973
  for (const item of recentActivity) {
312003
- if (item.status === "running") {
312004
- item.status = isAbort ? "cancelled" : "error";
312974
+ if (item.status === SubagentState.RUNNING) {
312975
+ item.status = isAbort ? SubagentState.CANCELLED : SubagentState.ERROR;
312005
312976
  }
312006
312977
  }
312007
312978
  const progress = {
312008
312979
  isSubagentProgress: true,
312009
312980
  agentName: this.agentName,
312010
312981
  recentActivity: [...recentActivity],
312011
- state: isAbort ? "cancelled" : "error"
312982
+ state: isAbort ? SubagentState.CANCELLED : SubagentState.ERROR
312012
312983
  };
312013
312984
  if (updateOutput) {
312014
312985
  updateOutput(progress);
@@ -317289,9 +318260,15 @@ var GitService = class _GitService {
317289
318260
  const gitConfigPath = path66.join(repoDir, ".gitconfig");
317290
318261
  const systemConfigPath = path66.join(repoDir, ".gitconfig_system_empty");
317291
318262
  return {
318263
+ ...sanitizeEnvironment(process.env, getSecureSanitizationConfig({
318264
+ enableEnvironmentVariableRedaction: true
318265
+ })),
317292
318266
  // Prevent git from using the user's global git config.
317293
318267
  GIT_CONFIG_GLOBAL: gitConfigPath,
317294
318268
  GIT_CONFIG_SYSTEM: systemConfigPath,
318269
+ // Ensure we don't inherit isolation-breaking variables from the user environment.
318270
+ GIT_DIR: void 0,
318271
+ GIT_WORK_TREE: void 0,
317295
318272
  // Explicitly provide identity to prevent "Author identity unknown" errors
317296
318273
  // inside sandboxed environments like Docker where the gitconfig might not
317297
318274
  // be picked up properly.
@@ -317346,9 +318323,9 @@ var GitService = class _GitService {
317346
318323
  get shadowGitRepository() {
317347
318324
  const repoDir = this.getHistoryDir();
317348
318325
  return simpleGit(this.projectRoot).env({
318326
+ ...this.getShadowRepoEnv(repoDir),
317349
318327
  GIT_DIR: path66.join(repoDir, ".git"),
317350
- GIT_WORK_TREE: this.projectRoot,
317351
- ...this.getShadowRepoEnv(repoDir)
318328
+ GIT_WORK_TREE: this.projectRoot
317352
318329
  });
317353
318330
  }
317354
318331
  async getCurrentCommitHash() {
@@ -318195,16 +319172,19 @@ var TrackerVisualizeTool = class _TrackerVisualizeTool extends BaseDeclarativeTo
318195
319172
  // packages/core/dist/src/availability/modelAvailabilityService.js
318196
319173
  var ModelAvailabilityService = class {
318197
319174
  health = /* @__PURE__ */ new Map();
318198
- markTerminal(model, reason) {
319175
+ markTerminal(modelId, reason) {
319176
+ const model = normalizeModelId(modelId);
318199
319177
  this.setState(model, {
318200
319178
  status: "terminal",
318201
319179
  reason
318202
319180
  });
318203
319181
  }
318204
- markHealthy(model) {
319182
+ markHealthy(modelId) {
319183
+ const model = normalizeModelId(modelId);
318205
319184
  this.clearState(model);
318206
319185
  }
318207
- markRetryOncePerTurn(model, attempts = 1) {
319186
+ markRetryOncePerTurn(modelId, attempts = 1) {
319187
+ const model = normalizeModelId(modelId);
318208
319188
  const currentState = this.health.get(model);
318209
319189
  if (currentState?.status === "terminal") {
318210
319190
  return;
@@ -318220,13 +319200,15 @@ var ModelAvailabilityService = class {
318220
319200
  attempts
318221
319201
  });
318222
319202
  }
318223
- consumeStickyAttempt(model) {
319203
+ consumeStickyAttempt(modelId) {
319204
+ const model = normalizeModelId(modelId);
318224
319205
  const state = this.health.get(model);
318225
319206
  if (state?.status === "sticky_retry") {
318226
319207
  this.setState(model, { ...state, consumed: true });
318227
319208
  }
318228
319209
  }
318229
- snapshot(model) {
319210
+ snapshot(modelId) {
319211
+ const model = normalizeModelId(modelId);
318230
319212
  const state = this.health.get(model);
318231
319213
  if (!state) {
318232
319214
  return { available: true };
@@ -318239,9 +319221,10 @@ var ModelAvailabilityService = class {
318239
319221
  }
318240
319222
  return { available: true };
318241
319223
  }
318242
- selectFirstAvailable(models) {
319224
+ selectFirstAvailable(modelIds) {
318243
319225
  const skipped = [];
318244
- for (const model of models) {
319226
+ for (const modelId of modelIds) {
319227
+ const model = normalizeModelId(modelId);
318245
319228
  const snapshot = this.snapshot(model);
318246
319229
  if (snapshot.available) {
318247
319230
  const state = this.health.get(model);
@@ -318408,7 +319391,13 @@ ${formattedHistory}
318408
319391
  const routerResponse = ClassifierResponseSchema.parse(jsonResponse);
318409
319392
  const reasoning = routerResponse.reasoning;
318410
319393
  const latencyMs = Date.now() - startTime;
318411
- const selectedModel = resolveClassifierModel(context2.requestedModel ?? config2.getModel(), routerResponse.model_choice);
319394
+ const [useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview] = await Promise.all([
319395
+ config2.getGemini31Launched(),
319396
+ config2.getGemini31FlashLiteLaunched(),
319397
+ config2.getUseCustomToolModel(),
319398
+ config2.getHasAccessToPreviewModel?.() ?? true
319399
+ ]);
319400
+ const selectedModel = resolveClassifierModel(context2.requestedModel ?? config2.getModel(), routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318412
319401
  return {
318413
319402
  model: selectedModel,
318414
319403
  metadata: {
@@ -318566,7 +319555,13 @@ var ClassifierStrategy = class {
318566
319555
  config2.getGemini31FlashLiteLaunched(),
318567
319556
  config2.getUseCustomToolModel()
318568
319557
  ]);
318569
- const selectedModel = resolveClassifierModel(model, routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2);
319558
+ const selectedModel = normalizeModelId(resolveClassifierModel(normalizeModelId(model), routerResponse.model_choice, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2));
319559
+ const service = config2.getModelAvailabilityService();
319560
+ const snapshot = service.snapshot(selectedModel);
319561
+ if (!snapshot.available) {
319562
+ debugLogger.warn(`[Routing] Classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`);
319563
+ return null;
319564
+ }
318570
319565
  return {
318571
319566
  model: selectedModel,
318572
319567
  metadata: {
@@ -318664,7 +319659,15 @@ var NumericalClassifierStrategy = class {
318664
319659
  return null;
318665
319660
  }
318666
319661
  const promptId = getPromptIdWithFallback("classifier-router");
318667
- const finalHistory = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
319662
+ const candidateSlice = context2.history.slice(-HISTORY_TURNS_FOR_CONTEXT3);
319663
+ let firstTextIndex = -1;
319664
+ for (let i3 = 0; i3 < candidateSlice.length; i3++) {
319665
+ if (!isFunctionCall(candidateSlice[i3]) && !isFunctionResponse(candidateSlice[i3])) {
319666
+ firstTextIndex = i3;
319667
+ break;
319668
+ }
319669
+ }
319670
+ const finalHistory = firstTextIndex === -1 ? [] : candidateSlice.slice(firstTextIndex);
318668
319671
  const requestParts = Array.isArray(context2.request) ? context2.request : [context2.request];
318669
319672
  const sanitizedRequest = requestParts.map((part) => {
318670
319673
  if (typeof part === "string") {
@@ -318692,7 +319695,13 @@ var NumericalClassifierStrategy = class {
318692
319695
  config2.getGemini31FlashLiteLaunched(),
318693
319696
  config2.getUseCustomToolModel()
318694
319697
  ]);
318695
- const selectedModel = resolveClassifierModel(model, modelAlias, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2);
319698
+ const selectedModel = normalizeModelId(resolveClassifierModel(normalizeModelId(model), modelAlias, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, config2.getHasAccessToPreviewModel?.() ?? true, config2));
319699
+ const service = config2.getModelAvailabilityService();
319700
+ const snapshot = service.snapshot(selectedModel);
319701
+ if (!snapshot.available) {
319702
+ debugLogger.warn(`[Routing] Numerical classifier selected unavailable model ${selectedModel} (${snapshot.reason}). Bypassing.`);
319703
+ return null;
319704
+ }
318696
319705
  const latencyMs = Date.now() - startTime;
318697
319706
  return {
318698
319707
  model: selectedModel,
@@ -318834,12 +319843,14 @@ var ApprovalModeStrategy = class {
318834
319843
  const startTime = Date.now();
318835
319844
  const approvalMode = config2.getApprovalMode();
318836
319845
  const approvedPlanPath = config2.getApprovedPlanPath();
318837
- const [useGemini3_1, useCustomToolModel] = await Promise.all([
319846
+ const [useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview] = await Promise.all([
318838
319847
  config2.getGemini31Launched(),
318839
- config2.getUseCustomToolModel()
319848
+ config2.getGemini31FlashLiteLaunched(),
319849
+ config2.getUseCustomToolModel(),
319850
+ config2.getHasAccessToPreviewModel()
318840
319851
  ]);
318841
319852
  if (approvalMode === ApprovalMode.PLAN) {
318842
- const proModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_PRO, useGemini3_1, useCustomToolModel);
319853
+ const proModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_PRO, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318843
319854
  return {
318844
319855
  model: proModel,
318845
319856
  metadata: {
@@ -318849,7 +319860,7 @@ var ApprovalModeStrategy = class {
318849
319860
  }
318850
319861
  };
318851
319862
  } else if (approvedPlanPath) {
318852
- const flashModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_FLASH, useGemini3_1, useCustomToolModel);
319863
+ const flashModel = resolveClassifierModel(model, GEMINI_MODEL_ALIAS_FLASH, useGemini3_1, useGemini3_1FlashLite, useCustomToolModel, hasAccessToPreview, config2);
318853
319864
  return {
318854
319865
  model: flashModel,
318855
319866
  metadata: {
@@ -319153,6 +320164,19 @@ var DEFAULT_MODEL_CONFIGS = {
319153
320164
  extends: "gemini-3-flash-base",
319154
320165
  modelConfig: {}
319155
320166
  },
320167
+ "context-snapshotter": {
320168
+ extends: "gemini-3-flash-base",
320169
+ modelConfig: {
320170
+ generateContentConfig: {
320171
+ thinkingConfig: {
320172
+ thinkingLevel: ThinkingLevel.HIGH
320173
+ },
320174
+ temperature: 1,
320175
+ topP: 0.95,
320176
+ topK: 64
320177
+ }
320178
+ }
320179
+ },
319156
320180
  "chat-compression-3-pro": {
319157
320181
  modelConfig: {
319158
320182
  model: "gemini-3-pro-preview"
@@ -321786,7 +322810,7 @@ var HookEventHandler = class {
321786
322810
  const hookType = this.getHookTypeFromResult(result2);
321787
322811
  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
322812
  logHookCall(this.context.config, hookCallEvent);
321789
- if (result2.output?.systemMessage && result2.outputFormat === "json") {
322813
+ if (result2.output?.systemMessage) {
321790
322814
  coreEvents.emitHookSystemMessage({
321791
322815
  hookName,
321792
322816
  eventName,
@@ -323839,8 +324863,8 @@ var AllowedPathChecker = class {
323839
324863
  while (current && current !== path73.dirname(current)) {
323840
324864
  if (fs65.existsSync(current)) {
323841
324865
  const canonical = fs65.realpathSync(current);
323842
- const relative12 = path73.relative(current, resolved);
323843
- return path73.join(canonical, relative12);
324866
+ const relative11 = path73.relative(current, resolved);
324867
+ return path73.join(canonical, relative11);
323844
324868
  }
323845
324869
  current = path73.dirname(current);
323846
324870
  }
@@ -323850,8 +324874,8 @@ var AllowedPathChecker = class {
323850
324874
  }
323851
324875
  }
323852
324876
  isPathAllowed(targetPath, allowedDir) {
323853
- const relative12 = path73.relative(allowedDir, targetPath);
323854
- return relative12 === "" || !relative12.startsWith("..") && !path73.isAbsolute(relative12);
324877
+ const relative11 = path73.relative(allowedDir, targetPath);
324878
+ return relative11 === "" || !relative11.startsWith("..") && !path73.isAbsolute(relative11);
323855
324879
  }
323856
324880
  collectPathsToCheck(args2, includedArgs, excludedArgs, prefix = "") {
323857
324881
  const paths = [];
@@ -327069,21 +328093,29 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
327069
328093
  }
327070
328094
  }
327071
328095
  function createUrlTransport(mcpServerName, mcpServerConfig, transportOptions) {
328096
+ const baseFetch = transportOptions.fetch ?? globalThis.fetch;
328097
+ const httpOptions = {
328098
+ ...transportOptions,
328099
+ fetch: async (url3, init2) => {
328100
+ const res = await baseFetch(url3, init2);
328101
+ return init2?.method === "GET" && res.status === 404 ? new Response(null, { status: 405, statusText: "Method Not Allowed" }) : res;
328102
+ }
328103
+ };
327072
328104
  if (mcpServerConfig.httpUrl) {
327073
328105
  if (mcpServerConfig.url) {
327074
328106
  debugLogger.warn(`MCP server '${mcpServerName}': Both 'httpUrl' and 'url' are configured. Using deprecated 'httpUrl'. Please migrate to 'url' with 'type: "http"'.`);
327075
328107
  }
327076
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), transportOptions);
328108
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.httpUrl), httpOptions);
327077
328109
  }
327078
328110
  if (mcpServerConfig.url && mcpServerConfig.type) {
327079
328111
  if (mcpServerConfig.type === "http") {
327080
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
328112
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), httpOptions);
327081
328113
  } else if (mcpServerConfig.type === "sse") {
327082
328114
  return new SSEClientTransport(new URL(mcpServerConfig.url), transportOptions);
327083
328115
  }
327084
328116
  }
327085
328117
  if (mcpServerConfig.url) {
327086
- return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), transportOptions);
328118
+ return new StreamableHTTPClientTransport(new URL(mcpServerConfig.url), httpOptions);
327087
328119
  }
327088
328120
  throw new Error(`No URL configured for MCP server '${mcpServerName}'`);
327089
328121
  }
@@ -336035,7 +337067,15 @@ var Config = class {
336035
337067
  this.workspaceContext.addDirectory(dir);
336036
337068
  }
336037
337069
  if (this.planEnabled) {
336038
- const plansDir = this.storage.getPlansDir();
337070
+ let plansDir;
337071
+ try {
337072
+ plansDir = this.storage.getPlansDir();
337073
+ } catch (error40) {
337074
+ const errorMessage = error40 instanceof Error ? error40.message : String(error40);
337075
+ coreEvents.emitFeedback("warning", "Invalid custom plans directory: " + errorMessage + ". Falling back to default project temp directory.", error40);
337076
+ this.storage.setCustomPlansDir(void 0);
337077
+ plansDir = this.storage.getPlansDir();
337078
+ }
336039
337079
  try {
336040
337080
  await fs68.promises.access(plansDir);
336041
337081
  this.workspaceContext.addDirectory(plansDir);
@@ -336720,7 +337760,7 @@ var Config = class {
336720
337760
  if (this.experimentalJitContext && this.memoryContextManager) {
336721
337761
  await this.memoryContextManager.refresh();
336722
337762
  } else {
336723
- const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-KSYZVCWF.js");
337763
+ const { refreshServerHierarchicalMemory: refreshServerHierarchicalMemory2 } = await import("./memoryDiscovery-LLSKN6HL.js");
336724
337764
  await refreshServerHierarchicalMemory2(this);
336725
337765
  }
336726
337766
  if (this._geminiClient?.isInitialized()) {
@@ -336755,12 +337795,13 @@ var Config = class {
336755
337795
  * user message when JIT is enabled. Returns empty string when JIT is
336756
337796
  * disabled (Tier 2 memory is already in the system instruction).
336757
337797
  */
336758
- getSessionMemory() {
337798
+ getSessionMemory(options) {
336759
337799
  if (!this.experimentalJitContext || !this.memoryContextManager) {
336760
337800
  return "";
336761
337801
  }
336762
337802
  const sections = [];
336763
- const extension = this.memoryContextManager.getExtensionMemory();
337803
+ const includeExtensionContext = options?.includeExtensionContext ?? true;
337804
+ const extension = includeExtensionContext ? this.memoryContextManager.getExtensionMemory() : "";
336764
337805
  const project = this.memoryContextManager.getEnvironmentMemory();
336765
337806
  if (extension?.trim()) {
336766
337807
  sections.push(`<extension_context>
@@ -337175,16 +338216,32 @@ ${sections.join("\n")}
337175
338216
  setIdeMode(value) {
337176
338217
  this.ideMode = value;
337177
338218
  }
337178
- isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot) {
338219
+ isScopedMemoryInboxPatchPathAllowed(absolutePath, resolvedPath, inboxRoot, checkType = "write") {
337179
338220
  if (!hasScopedMemoryInboxAccess()) {
337180
338221
  return false;
337181
338222
  }
337182
338223
  const normalizedPath = path76.resolve(absolutePath);
338224
+ const resolvedMemoryRoot = resolveToRealPath(this.storage.getProjectMemoryTempDir());
338225
+ if (checkType === "read") {
338226
+ const resolvedInboxRoot = resolveToRealPath(inboxRoot);
338227
+ const normalizedInboxRoot = path76.resolve(inboxRoot);
338228
+ if (resolvedPath === resolvedInboxRoot || normalizedPath === normalizedInboxRoot) {
338229
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
338230
+ }
338231
+ for (const kind of ["private", "global"]) {
338232
+ const kindRoot = path76.join(inboxRoot, kind);
338233
+ const resolvedKindRoot = resolveToRealPath(kindRoot);
338234
+ const normalizedKindRoot = path76.resolve(kindRoot);
338235
+ if (resolvedPath === resolvedKindRoot || normalizedPath === normalizedKindRoot || isSubpath(resolvedKindRoot, resolvedPath) || isSubpath(normalizedKindRoot, normalizedPath)) {
338236
+ return isSubpath(resolvedMemoryRoot, resolvedPath);
338237
+ }
338238
+ }
338239
+ return false;
338240
+ }
337183
338241
  const isCanonicalPatchPath = ["private", "global"].some((kind) => normalizedPath === path76.resolve(inboxRoot, kind, "extraction.patch"));
337184
338242
  if (!isCanonicalPatchPath) {
337185
338243
  return false;
337186
338244
  }
337187
- const resolvedMemoryRoot = resolveToRealPath(this.storage.getProjectMemoryTempDir());
337188
338245
  return isSubpath(resolvedMemoryRoot, resolvedPath);
337189
338246
  }
337190
338247
  isScopedAutoMemoryExtractionWritePathAllowed(absolutePath, resolvedPath) {
@@ -337214,7 +338271,9 @@ ${sections.join("\n")}
337214
338271
  * the auto-memory extraction agent and the `/memory inbox` review flow. The
337215
338272
  * main agent is denied access to it even though it falls inside the project
337216
338273
  * temp dir; the extraction agent receives a narrow execution-scoped exception
337217
- * for `.inbox/{private,global}/extraction.patch`.
338274
+ * for *writes* to `.inbox/{private,global}/extraction.patch`. Scoped *read*
338275
+ * access to the wider `.inbox/{private,global}/` subtree is granted in
338276
+ * `validatePathAccess` so the extractor can enumerate prior patches.
337218
338277
  *
337219
338278
  * @param absolutePath The absolute path to check.
337220
338279
  * @returns true if the path is allowed, false otherwise.
@@ -337266,6 +338325,12 @@ ${sections.join("\n")}
337266
338325
  if (this.getWorkspaceContext().isPathReadable(absolutePath)) {
337267
338326
  return null;
337268
338327
  }
338328
+ if (hasScopedMemoryInboxAccess()) {
338329
+ const inboxRoot = path76.join(this.storage.getProjectMemoryTempDir(), ".inbox");
338330
+ if (this.isScopedMemoryInboxPatchPathAllowed(absolutePath, resolveToRealPath(absolutePath), inboxRoot, "read")) {
338331
+ return null;
338332
+ }
338333
+ }
337269
338334
  }
337270
338335
  if (this.isPathAllowed(absolutePath)) {
337271
338336
  return null;
@@ -337592,10 +338657,10 @@ ${sections.join("\n")}
337592
338657
  return this.gemmaModelRouter;
337593
338658
  }
337594
338659
  getAgentSessionNoninteractiveEnabled() {
337595
- return this.agentSessionNoninteractiveEnabled;
338660
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionNoninteractiveEnabled;
337596
338661
  }
337597
338662
  getAgentSessionInteractiveEnabled() {
337598
- return this.agentSessionInteractiveEnabled;
338663
+ return process15.env["GEMINI_CLI_EXP_AGENT"] === "true" || this.agentSessionInteractiveEnabled;
337599
338664
  }
337600
338665
  /**
337601
338666
  * Get override settings for a specific agent.
@@ -338560,11 +339625,228 @@ async function isProjectSkillPatchTarget(targetPath, config2) {
338560
339625
  function hasParsedPatchHunks(parsedPatches) {
338561
339626
  return parsedPatches.length > 0 && parsedPatches.every((patch) => patch.hunks.length > 0);
338562
339627
  }
339628
+ function getMemoryPatchRoot(memoryDir, kind) {
339629
+ return path80.join(memoryDir, ".inbox", kind);
339630
+ }
339631
+ function isSubpathOrSame(childPath, parentPath) {
339632
+ return isSubpath(parentPath, childPath);
339633
+ }
339634
+ function normalizeInboxMemoryPatchPath(relativePath) {
339635
+ if (relativePath.length === 0 || path80.isAbsolute(relativePath) || relativePath.includes("\\")) {
339636
+ return void 0;
339637
+ }
339638
+ const normalizedPath = path80.posix.normalize(relativePath);
339639
+ if (normalizedPath === "." || normalizedPath.startsWith("../") || normalizedPath === ".." || !normalizedPath.endsWith(".patch")) {
339640
+ return void 0;
339641
+ }
339642
+ return normalizedPath;
339643
+ }
339644
+ function getAllowedMemoryPatchRoots(config2, kind) {
339645
+ switch (kind) {
339646
+ case "private":
339647
+ return [path80.resolve(config2.storage.getProjectMemoryTempDir())];
339648
+ case "global":
339649
+ return [path80.resolve(getGlobalMemoryFilePath())];
339650
+ default:
339651
+ throw new Error(`Unknown memory patch kind: ${kind}`);
339652
+ }
339653
+ }
339654
+ function hasMarkdownExtension(fileName) {
339655
+ return fileName.toLowerCase().endsWith(".md");
339656
+ }
339657
+ function isAllowedPrivateMemoryFileName(fileName) {
339658
+ if (fileName === PROJECT_MEMORY_INDEX_FILENAME) {
339659
+ return true;
339660
+ }
339661
+ return !fileName.startsWith(".") && hasMarkdownExtension(fileName);
339662
+ }
339663
+ function uniqueResolvedPaths(paths) {
339664
+ return Array.from(new Set(paths.map((filePath) => path80.resolve(filePath))));
339665
+ }
339666
+ function isSamePath(leftPath, rightPath) {
339667
+ return isSubpath(leftPath, rightPath) && isSubpath(rightPath, leftPath);
339668
+ }
339669
+ function includesSamePath(paths, targetPath) {
339670
+ return paths.some((candidate) => isSamePath(candidate, targetPath));
339671
+ }
339672
+ function isAllowedPrivateMemoryDocumentPath(targetPath, memoryDirs) {
339673
+ const resolvedTargetPath = path80.resolve(targetPath);
339674
+ const targetDir = path80.dirname(resolvedTargetPath);
339675
+ if (!includesSamePath(memoryDirs, targetDir)) {
339676
+ return false;
339677
+ }
339678
+ return isAllowedPrivateMemoryFileName(path80.basename(resolvedTargetPath));
339679
+ }
339680
+ function isAllowedGlobalMemoryDocumentPath(targetPath, globalMemoryFiles) {
339681
+ const resolvedTargetPath = path80.resolve(targetPath);
339682
+ return includesSamePath(globalMemoryFiles, resolvedTargetPath);
339683
+ }
339684
+ async function getMemoryPatchTargetValidationContext(config2, kind) {
339685
+ const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
339686
+ if (kind === "global") {
339687
+ const rawGlobalMemoryFile = path80.resolve(getGlobalMemoryFilePath());
339688
+ const canonicalGlobalMemoryFiles = await canonicalizeAllowedPatchRoots([
339689
+ rawGlobalMemoryFile
339690
+ ]);
339691
+ return {
339692
+ kind,
339693
+ allowedRoots,
339694
+ privateMemoryDirs: [],
339695
+ globalMemoryFiles: uniqueResolvedPaths([
339696
+ rawGlobalMemoryFile,
339697
+ ...canonicalGlobalMemoryFiles
339698
+ ])
339699
+ };
339700
+ }
339701
+ const rawPrivateMemoryDir = path80.resolve(config2.storage.getProjectMemoryTempDir());
339702
+ const canonicalPrivateMemoryDirs = await canonicalizeAllowedPatchRoots([
339703
+ rawPrivateMemoryDir
339704
+ ]);
339705
+ const privateMemoryDirs = uniqueResolvedPaths([
339706
+ rawPrivateMemoryDir,
339707
+ ...canonicalPrivateMemoryDirs
339708
+ ]);
339709
+ return { kind, allowedRoots, privateMemoryDirs, globalMemoryFiles: [] };
339710
+ }
339711
+ function isResolvedMemoryPatchTargetAllowed(resolvedTargetPath, context2) {
339712
+ if (context2.kind === "global") {
339713
+ return isAllowedGlobalMemoryDocumentPath(resolvedTargetPath, context2.globalMemoryFiles);
339714
+ }
339715
+ if (context2.kind === "private") {
339716
+ return isAllowedPrivateMemoryDocumentPath(resolvedTargetPath, context2.privateMemoryDirs);
339717
+ }
339718
+ return true;
339719
+ }
339720
+ async function resolveMemoryPatchTargetWithinAllowedSet(targetPath, context2) {
339721
+ const resolvedTargetPath = await resolveTargetWithinAllowedRoots(targetPath, context2.allowedRoots);
339722
+ if (!resolvedTargetPath) {
339723
+ return void 0;
339724
+ }
339725
+ if (context2.kind === "private" && (!isAllowedPrivateMemoryDocumentPath(targetPath, context2.privateMemoryDirs) || !isAllowedPrivateMemoryDocumentPath(resolvedTargetPath, context2.privateMemoryDirs))) {
339726
+ return void 0;
339727
+ }
339728
+ if (context2.kind === "global" && (!isAllowedGlobalMemoryDocumentPath(targetPath, context2.globalMemoryFiles) || !isAllowedGlobalMemoryDocumentPath(resolvedTargetPath, context2.globalMemoryFiles))) {
339729
+ return void 0;
339730
+ }
339731
+ return resolvedTargetPath;
339732
+ }
339733
+ async function findDisallowedMemoryPatchTarget(parsedPatches, context2) {
339734
+ const validated = validateParsedSkillPatchHeaders(parsedPatches);
339735
+ if (!validated.success) {
339736
+ return void 0;
339737
+ }
339738
+ for (const header of validated.patches) {
339739
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, context2)) {
339740
+ return header.targetPath;
339741
+ }
339742
+ }
339743
+ return void 0;
339744
+ }
339745
+ async function getInboxMemoryPatchSourcePath(config2, kind, relativePath) {
339746
+ const normalizedPath = normalizeInboxMemoryPatchPath(relativePath);
339747
+ if (!normalizedPath) {
339748
+ return void 0;
339749
+ }
339750
+ const patchRoot = path80.resolve(getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind));
339751
+ const sourcePath = path80.resolve(patchRoot, ...normalizedPath.split("/"));
339752
+ if (!isSubpathOrSame(sourcePath, patchRoot)) {
339753
+ return void 0;
339754
+ }
339755
+ return sourcePath;
339756
+ }
339757
+ async function listInboxPatchFiles(config2, kind) {
339758
+ const patchRoot = getMemoryPatchRoot(config2.storage.getProjectMemoryTempDir(), kind);
339759
+ const found = [];
339760
+ async function walk(currentDir) {
339761
+ let dirEntries;
339762
+ try {
339763
+ dirEntries = await fs71.readdir(currentDir, { withFileTypes: true });
339764
+ } catch {
339765
+ return;
339766
+ }
339767
+ for (const entry of dirEntries) {
339768
+ const entryPath = path80.join(currentDir, entry.name);
339769
+ if (entry.isDirectory()) {
339770
+ await walk(entryPath);
339771
+ continue;
339772
+ }
339773
+ if (entry.isFile() && entry.name.endsWith(".patch")) {
339774
+ found.push(entryPath);
339775
+ }
339776
+ }
339777
+ }
339778
+ await walk(patchRoot);
339779
+ return found.sort();
339780
+ }
339781
+ async function validateInboxMemoryPatchFile(config2, kind, sourcePath) {
339782
+ let content;
339783
+ try {
339784
+ content = await fs71.readFile(sourcePath, "utf-8");
339785
+ } catch (error40) {
339786
+ return {
339787
+ valid: false,
339788
+ reason: `failed to read patch: ${error40 instanceof Error ? error40.message : String(error40)}`
339789
+ };
339790
+ }
339791
+ let parsed;
339792
+ try {
339793
+ parsed = parsePatch(content);
339794
+ } catch (error40) {
339795
+ return {
339796
+ valid: false,
339797
+ reason: `failed to parse patch: ${error40 instanceof Error ? error40.message : String(error40)}`
339798
+ };
339799
+ }
339800
+ if (!hasParsedPatchHunks(parsed)) {
339801
+ return { valid: false, reason: "no hunks found in patch" };
339802
+ }
339803
+ const validated = validateParsedSkillPatchHeaders(parsed);
339804
+ if (!validated.success) {
339805
+ switch (validated.reason) {
339806
+ case "missingTargetPath":
339807
+ return {
339808
+ valid: false,
339809
+ reason: "missing target file path in patch header"
339810
+ };
339811
+ case "invalidPatchHeaders":
339812
+ return {
339813
+ valid: false,
339814
+ reason: `invalid diff headers${validated.targetPath ? `: ${validated.targetPath}` : ""}`
339815
+ };
339816
+ default:
339817
+ return { valid: false, reason: "invalid patch headers" };
339818
+ }
339819
+ }
339820
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
339821
+ for (const header of validated.patches) {
339822
+ if (!await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, validationContext)) {
339823
+ return {
339824
+ valid: false,
339825
+ reason: `target file is outside ${kind} memory roots: ${header.targetPath}`
339826
+ };
339827
+ }
339828
+ }
339829
+ return { valid: true };
339830
+ }
339831
+ async function listValidInboxPatchFiles(config2, kind) {
339832
+ const patchFiles = await listInboxPatchFiles(config2, kind);
339833
+ if (patchFiles.length === 0) {
339834
+ return [];
339835
+ }
339836
+ const valid = [];
339837
+ for (const sourcePath of patchFiles) {
339838
+ const validation = await validateInboxMemoryPatchFile(config2, kind, sourcePath);
339839
+ if (validation.valid) {
339840
+ valid.push(sourcePath);
339841
+ }
339842
+ }
339843
+ return valid;
339844
+ }
338563
339845
  async function applyParsedSkillPatches(parsedPatches, config2) {
338564
339846
  const allowedRoots = await getCanonicalAllowedSkillPatchRoots(config2);
338565
339847
  return applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots);
338566
339848
  }
338567
- async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
339849
+ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots, options = {}) {
338568
339850
  const results = /* @__PURE__ */ new Map();
338569
339851
  const patchedContentByTarget = /* @__PURE__ */ new Map();
338570
339852
  const originalContentByTarget = /* @__PURE__ */ new Map();
@@ -338575,7 +339857,7 @@ async function applyParsedPatchesWithAllowedRoots(parsedPatches, allowedRoots) {
338575
339857
  for (const [index, patch] of parsedPatches.entries()) {
338576
339858
  const { targetPath, isNewFile } = validatedHeaders.patches[index];
338577
339859
  const resolvedTargetPath = await resolveTargetWithinAllowedRoots(targetPath, allowedRoots);
338578
- if (!resolvedTargetPath) {
339860
+ if (!resolvedTargetPath || options.isResolvedTargetAllowed && !options.isResolvedTargetAllowed(resolvedTargetPath)) {
338579
339861
  return {
338580
339862
  success: false,
338581
339863
  reason: "outsideAllowedRoots",
@@ -339031,6 +340313,7 @@ var SkillExtractionAgent = (skillsDir, sessionIndex, existingSkillsSummary, memo
339031
340313
  },
339032
340314
  memoryInboxAccess: true,
339033
340315
  autoMemoryExtractionWriteAccess: true,
340316
+ includeExtensionContext: false,
339034
340317
  toolConfig: {
339035
340318
  tools: [
339036
340319
  ACTIVATE_SKILL_TOOL_NAME,
@@ -339756,6 +341039,28 @@ async function snapshotFiles(rootDir, shouldIncludeFile = () => true, shouldDesc
339756
341039
  async function snapshotInboxCandidates(memoryDir) {
339757
341040
  return snapshotFiles(path81.join(memoryDir, ".inbox"));
339758
341041
  }
341042
+ var MEMORY_INBOX_PATCH_KINDS = [
341043
+ "private",
341044
+ "global"
341045
+ ];
341046
+ async function validateMemoryInboxPatches(config2) {
341047
+ for (const kind of MEMORY_INBOX_PATCH_KINDS) {
341048
+ const patchFiles = await listInboxPatchFiles(config2, kind);
341049
+ for (const patchFile of patchFiles) {
341050
+ const validation = await validateInboxMemoryPatchFile(config2, kind, patchFile);
341051
+ if (validation.valid) {
341052
+ continue;
341053
+ }
341054
+ try {
341055
+ await fs72.unlink(patchFile);
341056
+ debugLogger.warn(`[MemoryService] Dropped invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}`);
341057
+ } catch (error40) {
341058
+ const message = error40 instanceof Error ? error40.message : String(error40);
341059
+ debugLogger.warn(`[MemoryService] Failed to drop invalid ${kind} memory inbox patch ${patchFile}: ${validation.reason}; unlink failed: ${message}`);
341060
+ }
341061
+ }
341062
+ }
341063
+ }
339759
341064
  async function buildPendingInboxSummary(memoryDir) {
339760
341065
  const sections = [];
339761
341066
  for (const kind of ["private", "global"]) {
@@ -339964,6 +341269,7 @@ ${pendingInboxSummary}`);
339964
341269
  if (validPatches.length > 0) {
339965
341270
  debugLogger.log(`[MemoryService] ${validPatches.length} valid patch(es) currently in inbox; ${patchesCreatedThisRun.length} created or updated this run`);
339966
341271
  }
341272
+ await validateMemoryInboxPatches(config2);
339967
341273
  const memoryFilesUpdated = [];
339968
341274
  const memoryCandidatesCreated = prefixRelativePaths(".inbox", getChangedSnapshotPaths(diffFileSnapshots(inboxCandidatesBefore, await snapshotInboxCandidates(memoryDir))));
339969
341275
  const processedSessions = candidateSessions.filter((session) => processedSessionKeys.has(getSessionVersionKey(session))).map((session) => ({
@@ -340249,33 +341555,6 @@ function formatParsedDiff(parsed) {
340249
341555
  function getErrorMessage4(error40) {
340250
341556
  return error40 instanceof Error ? error40.message : String(error40);
340251
341557
  }
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
341558
  async function getFileMtimeIso(filePath) {
340280
341559
  try {
340281
341560
  const stats = await fs73.stat(filePath);
@@ -340284,18 +341563,6 @@ async function getFileMtimeIso(filePath) {
340284
341563
  return void 0;
340285
341564
  }
340286
341565
  }
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
341566
  async function patchTargetsProjectSkills(targetPaths, config2) {
340300
341567
  for (const targetPath of targetPaths) {
340301
341568
  if (await isProjectSkillPatchTarget(targetPath, config2)) {
@@ -340322,70 +341589,11 @@ function formatMemoryKindLabel(kind) {
340322
341589
  return kind;
340323
341590
  }
340324
341591
  }
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
341592
  async function listInboxMemoryPatches(config2) {
340385
341593
  const kinds = ["private", "global"];
340386
341594
  const aggregated = [];
340387
341595
  for (const kind of kinds) {
340388
- const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
341596
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
340389
341597
  const patchFiles = await listInboxPatchFiles(config2, kind);
340390
341598
  const aggregatedEntries = [];
340391
341599
  const sourceFiles = [];
@@ -340410,7 +341618,7 @@ async function listInboxMemoryPatches(config2) {
340410
341618
  if (!validated.success) {
340411
341619
  continue;
340412
341620
  }
340413
- const targetsAllAllowed = await Promise.all(validated.patches.map(async (header) => await resolveTargetWithinAllowedRoots(header.targetPath, allowedRoots) !== void 0));
341621
+ const targetsAllAllowed = await Promise.all(validated.patches.map(async (header) => await resolveMemoryPatchTargetWithinAllowedSet(header.targetPath, validationContext) !== void 0));
340414
341622
  if (!targetsAllAllowed.every(Boolean)) {
340415
341623
  continue;
340416
341624
  }
@@ -340591,8 +341799,17 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
340591
341799
  message: `Memory patch "${displayName}" contains no valid hunks.`
340592
341800
  };
340593
341801
  }
340594
- const allowedRoots = await canonicalizeAllowedPatchRoots(getAllowedMemoryPatchRoots(config2, kind));
340595
- const applied = await applyParsedPatchesWithAllowedRoots(parsed, allowedRoots);
341802
+ const validationContext = await getMemoryPatchTargetValidationContext(config2, kind);
341803
+ const disallowedTargetPath = await findDisallowedMemoryPatchTarget(parsed, validationContext);
341804
+ if (disallowedTargetPath) {
341805
+ return {
341806
+ success: false,
341807
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${disallowedTargetPath}`
341808
+ };
341809
+ }
341810
+ const applied = await applyParsedPatchesWithAllowedRoots(parsed, validationContext.allowedRoots, {
341811
+ isResolvedTargetAllowed: (resolvedTargetPath) => isResolvedMemoryPatchTargetAllowed(resolvedTargetPath, validationContext)
341812
+ });
340596
341813
  if (!applied.success) {
340597
341814
  switch (applied.reason) {
340598
341815
  case "missingTargetPath":
@@ -340608,7 +341825,7 @@ async function applyMemoryPatchFile(config2, kind, patchPath, displayName) {
340608
341825
  case "outsideAllowedRoots":
340609
341826
  return {
340610
341827
  success: false,
340611
- message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root: ${applied.targetPath}`
341828
+ message: `Memory patch "${displayName}" targets a file outside the ${kind} memory root or target allowlist: ${applied.targetPath}`
340612
341829
  };
340613
341830
  case "newFileAlreadyExists":
340614
341831
  return {
@@ -341482,8 +342699,9 @@ function loadIgnoreRules(service, ignoreDirs = []) {
341482
342699
  const ignorer = new Ignore2();
341483
342700
  const ignoreFiles = service.getAllIgnoreFilePaths();
341484
342701
  for (const filePath of ignoreFiles) {
341485
- if (fs75.existsSync(filePath)) {
342702
+ try {
341486
342703
  ignorer.add(fs75.readFileSync(filePath, "utf8"));
342704
+ } catch {
341487
342705
  }
341488
342706
  }
341489
342707
  const allIgnoreDirs = [".git", ...ignoreDirs];
@@ -342641,11 +343859,11 @@ var AsyncFzf = class {
342641
343859
  // packages/core/node_modules/chokidar/index.js
342642
343860
  import { EventEmitter as EventEmitter8 } from "node:events";
342643
343861
  import { stat as statcb, Stats } from "node:fs";
342644
- import { readdir as readdir10, stat as stat7 } from "node:fs/promises";
343862
+ import { readdir as readdir11, stat as stat7 } from "node:fs/promises";
342645
343863
  import * as sp2 from "node:path";
342646
343864
 
342647
343865
  // 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";
343866
+ import { lstat as lstat3, readdir as readdir10, realpath as realpath4, stat as stat5 } from "node:fs/promises";
342649
343867
  import { join as pjoin, relative as prelative, resolve as presolve, sep as psep } from "node:path";
342650
343868
  import { Readable as Readable3 } from "node:stream";
342651
343869
  var EntryTypes = {
@@ -342797,7 +344015,7 @@ var ReaddirpStream = class extends Readable3 {
342797
344015
  async _exploreDir(path101, depth) {
342798
344016
  let files;
342799
344017
  try {
342800
- files = await readdir9(path101, this._rdOptions);
344018
+ files = await readdir10(path101, this._rdOptions);
342801
344019
  } catch (error40) {
342802
344020
  this._onError(error40);
342803
344021
  }
@@ -343662,11 +344880,11 @@ function createPattern(matcher) {
343662
344880
  if (matcher.path === string4)
343663
344881
  return true;
343664
344882
  if (matcher.recursive) {
343665
- const relative12 = sp2.relative(matcher.path, string4);
343666
- if (!relative12) {
344883
+ const relative11 = sp2.relative(matcher.path, string4);
344884
+ if (!relative11) {
343667
344885
  return false;
343668
344886
  }
343669
- return !relative12.startsWith("..") && !sp2.isAbsolute(relative12);
344887
+ return !relative11.startsWith("..") && !sp2.isAbsolute(relative11);
343670
344888
  }
343671
344889
  return false;
343672
344890
  };
@@ -343768,7 +344986,7 @@ var DirEntry = class {
343768
344986
  return;
343769
344987
  const dir = this.path;
343770
344988
  try {
343771
- await readdir10(dir);
344989
+ await readdir11(dir);
343772
344990
  } catch (err2) {
343773
344991
  if (this._removeWatcher) {
343774
344992
  this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
@@ -345224,8 +346442,8 @@ function normalizePathCandidate(candidate, projectRoot) {
345224
346442
  }
345225
346443
  let normalized2 = trimmed2.replace(/\\/g, "/");
345226
346444
  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);
346445
+ const relative11 = path88.relative(projectRoot, trimmed2);
346446
+ normalized2 = relative11 && !relative11.startsWith("..") && !path88.isAbsolute(relative11) ? relative11.replace(/\\/g, "/") : path88.basename(trimmed2);
345229
346447
  }
345230
346448
  if (normalized2.length > 120) {
345231
346449
  normalized2 = normalized2.split("/").slice(-3).join("/");
@@ -345940,6 +347158,7 @@ function contentPartsToGeminiParts(content) {
345940
347158
  result2.push({ text: part.text });
345941
347159
  break;
345942
347160
  default:
347161
+ debugLogger.warn(`Unhandled ContentPart type: ${JSON.stringify(part)} fallback to serialization`);
345943
347162
  result2.push({ text: JSON.stringify(part) });
345944
347163
  break;
345945
347164
  }
@@ -345959,50 +347178,6 @@ function buildToolResponseData(response) {
345959
347178
  return Object.keys(parts2).length > 0 ? parts2 : void 0;
345960
347179
  }
345961
347180
 
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
347181
  // packages/core/dist/src/agent/event-translator.js
346007
347182
  function createTranslationState(streamId) {
346008
347183
  return {
@@ -346130,15 +347305,16 @@ function translateEvent(event, state) {
346130
347305
  out2.push(makeEvent("tool_request", state, {
346131
347306
  requestId: event.value.callId,
346132
347307
  name: event.value.name,
346133
- args: event.value.args
347308
+ args: event.value.args,
347309
+ display: event.value.display
346134
347310
  }));
346135
347311
  break;
346136
347312
  case GeminiEventType.ToolCallResponse: {
346137
347313
  ensureStreamStart(state, out2);
346138
347314
  const data = buildToolResponseData(event.value);
346139
- const display = event.value.resultDisplay ? {
347315
+ const display = event.value.display ?? (event.value.resultDisplay ? {
346140
347316
  result: toolResultDisplayToDisplayContent(event.value.resultDisplay)
346141
- } : void 0;
347317
+ } : void 0);
346142
347318
  out2.push(makeEvent("tool_response", state, {
346143
347319
  requestId: event.value.callId,
346144
347320
  name: state.pendingToolNames.get(event.value.callId) ?? "unknown",
@@ -346160,7 +347336,6 @@ function translateEvent(event, state) {
346160
347336
  ((x) => {
346161
347337
  throw new Error(`Unhandled event type: ${JSON.stringify(x)}`);
346162
347338
  })(event);
346163
- break;
346164
347339
  }
346165
347340
  return out2;
346166
347341
  }
@@ -346360,6 +347535,7 @@ var LegacyAgentProtocol = class {
346360
347535
  } else {
346361
347536
  this._emitErrorAndAgentEnd(err2);
346362
347537
  }
347538
+ } finally {
346363
347539
  this._clearActiveStream();
346364
347540
  }
346365
347541
  }
@@ -346433,7 +347609,8 @@ var LegacyAgentProtocol = class {
346433
347609
  name: request.name,
346434
347610
  invocation: "invocation" in tc ? tc.invocation : void 0,
346435
347611
  resultDisplay: response.resultDisplay,
346436
- displayName: "tool" in tc ? tc.tool?.displayName : void 0
347612
+ displayName: "tool" in tc ? tc.tool?.displayName : void 0,
347613
+ display: response.display
346437
347614
  });
346438
347615
  const data = buildToolResponseData(response);
346439
347616
  this._emit([
@@ -346527,6 +347704,7 @@ var LegacyAgentProtocol = class {
346527
347704
  const meta = {};
346528
347705
  if (err2 instanceof Error) {
346529
347706
  meta["errorName"] = err2.constructor.name;
347707
+ meta["stack"] = err2.stack;
346530
347708
  if ("exitCode" in err2 && typeof err2.exitCode === "number") {
346531
347709
  meta["exitCode"] = err2.exitCode;
346532
347710
  }
@@ -349214,7 +350392,7 @@ var ENCODING_ALIASES = {
349214
350392
  var serializeEncoding = (encoding) => typeof encoding === "string" ? `"${encoding}"` : String(encoding);
349215
350393
 
349216
350394
  // node_modules/execa/lib/arguments/cwd.js
349217
- import { statSync as statSync3 } from "node:fs";
350395
+ import { statSync as statSync4 } from "node:fs";
349218
350396
  import path94 from "node:path";
349219
350397
  import process20 from "node:process";
349220
350398
  var normalizeCwd = (cwd = getDefaultCwd()) => {
@@ -349236,7 +350414,7 @@ var fixCwdError = (originalMessage, cwd) => {
349236
350414
  }
349237
350415
  let cwdStat;
349238
350416
  try {
349239
- cwdStat = statSync3(cwd);
350417
+ cwdStat = statSync4(cwd);
349240
350418
  } catch (error40) {
349241
350419
  return `The "cwd" option is invalid: ${cwd}.
349242
350420
  ${error40.message}
@@ -353892,8 +355070,8 @@ function isGeminiWorktree(dirPath, projectRoot) {
353892
355070
  const realDirPath = realpathSync4(dirPath);
353893
355071
  const realProjectRoot = realpathSync4(projectRoot);
353894
355072
  const worktreesBaseDir = path96.join(realProjectRoot, ".gemini", "worktrees");
353895
- const relative12 = path96.relative(worktreesBaseDir, realDirPath);
353896
- return !relative12.startsWith("..") && !path96.isAbsolute(relative12);
355073
+ const relative11 = path96.relative(worktreesBaseDir, realDirPath);
355074
+ return !relative11.startsWith("..") && !path96.isAbsolute(relative11);
353897
355075
  } catch {
353898
355076
  return false;
353899
355077
  }
@@ -355224,6 +356402,7 @@ export {
355224
356402
  CacheService,
355225
356403
  createCache,
355226
356404
  ProjectIdRequiredError,
356405
+ InvalidNumericProjectIdError,
355227
356406
  ValidationCancelledError,
355228
356407
  IneligibleTierError,
355229
356408
  resetUserDataCacheForTesting,
@@ -355311,6 +356490,11 @@ export {
355311
356490
  GeminiChat,
355312
356491
  isSchemaDepthError,
355313
356492
  isInvalidArgumentError,
356493
+ stripToolCallIdPrefixes,
356494
+ populateToolDisplay,
356495
+ toolResultDisplayToDisplayContent,
356496
+ renderDisplayDiff,
356497
+ displayContentToString,
355314
356498
  GeminiEventType,
355315
356499
  CompressionStatus,
355316
356500
  Turn,
@@ -355348,6 +356532,7 @@ export {
355348
356532
  SubagentActivityErrorType,
355349
356533
  SUBAGENT_REJECTED_ERROR_PREFIX,
355350
356534
  SUBAGENT_CANCELLED_ERROR_MESSAGE,
356535
+ SubagentState,
355351
356536
  isSubagentProgress,
355352
356537
  isToolActivityError,
355353
356538
  getAgentCardLoadOptions,
@@ -355377,6 +356562,16 @@ export {
355377
356562
  getPolicyDenialError,
355378
356563
  checkPolicy,
355379
356564
  updatePolicy,
356565
+ NodeType,
356566
+ isAgentThought,
356567
+ isAgentYield,
356568
+ isToolExecution,
356569
+ isMaskedTool,
356570
+ isUserPrompt,
356571
+ isSystemEvent,
356572
+ isSnapshot,
356573
+ isRollingSummary,
356574
+ SnapshotGenerator,
355380
356575
  generalistProfile,
355381
356576
  stressTestProfile,
355382
356577
  GeminiClient,
@@ -355522,6 +356717,7 @@ export {
355522
356717
  performRestore,
355523
356718
  performInit,
355524
356719
  isProjectSkillPatchTarget,
356720
+ getAllowedMemoryPatchRoots,
355525
356721
  validatePatches,
355526
356722
  startMemoryService,
355527
356723
  showMemory,
@@ -355531,7 +356727,6 @@ export {
355531
356727
  listInboxSkills,
355532
356728
  moveInboxSkill,
355533
356729
  dismissInboxSkill,
355534
- getAllowedMemoryPatchRoots,
355535
356730
  listInboxMemoryPatches,
355536
356731
  applyInboxMemoryPatch,
355537
356732
  dismissInboxMemoryPatch,
@@ -355567,10 +356762,6 @@ export {
355567
356762
  geminiPartsToContentParts,
355568
356763
  contentPartsToGeminiParts,
355569
356764
  buildToolResponseData,
355570
- populateToolDisplay,
355571
- toolResultDisplayToDisplayContent,
355572
- renderDisplayDiff,
355573
- displayContentToString,
355574
356765
  createTranslationState,
355575
356766
  translateEvent,
355576
356767
  mapFinishReason,