neuralos 2.9.1 → 2.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/gybackend.cjs CHANGED
@@ -9040,7 +9040,7 @@ var require_eventemitter3 = __commonJS({
9040
9040
  if (listeners.fn) return 1;
9041
9041
  return listeners.length;
9042
9042
  };
9043
- EventEmitter4.prototype.emit = function emit9(event, a1, a2, a3, a4, a5) {
9043
+ EventEmitter4.prototype.emit = function emit10(event, a1, a2, a3, a4, a5) {
9044
9044
  var evt = prefix ? prefix + event : event;
9045
9045
  if (!this._events[evt]) return false;
9046
9046
  var listeners = this._events[evt], len = arguments.length, args, i;
@@ -51648,7 +51648,7 @@ var require_pdf_worker = __commonJS({
51648
51648
  });
51649
51649
  exports3.getMetrics = void 0;
51650
51650
  var _util = __w_pdfjs_require__(0);
51651
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
51651
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
51652
51652
  t["Courier"] = 600;
51653
51653
  t["Courier-Bold"] = 600;
51654
51654
  t["Courier-BoldOblique"] = 600;
@@ -54586,7 +54586,7 @@ var require_pdf_worker = __commonJS({
54586
54586
  t2["a191"] = 918;
54587
54587
  });
54588
54588
  });
54589
- exports3.getMetrics = getMetrics;
54589
+ exports3.getMetrics = getMetrics2;
54590
54590
  }),
54591
54591
  /* 142 */
54592
54592
  /***/
@@ -113850,7 +113850,7 @@ var require_pdf_worker2 = __commonJS({
113850
113850
  });
113851
113851
  exports3.getMetrics = void 0;
113852
113852
  var _util = __w_pdfjs_require__(0);
113853
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
113853
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
113854
113854
  t["Courier"] = 600;
113855
113855
  t["Courier-Bold"] = 600;
113856
113856
  t["Courier-BoldOblique"] = 600;
@@ -116788,7 +116788,7 @@ var require_pdf_worker2 = __commonJS({
116788
116788
  t2["a191"] = 918;
116789
116789
  });
116790
116790
  });
116791
- exports3.getMetrics = getMetrics;
116791
+ exports3.getMetrics = getMetrics2;
116792
116792
  }),
116793
116793
  /* 141 */
116794
116794
  /***/
@@ -170585,7 +170585,7 @@ var require_pdf_worker3 = __commonJS({
170585
170585
  });
170586
170586
  exports3.getMetrics = void 0;
170587
170587
  var _util = __w_pdfjs_require__(0);
170588
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
170588
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
170589
170589
  t["Courier"] = 600;
170590
170590
  t["Courier-Bold"] = 600;
170591
170591
  t["Courier-BoldOblique"] = 600;
@@ -173523,7 +173523,7 @@ var require_pdf_worker3 = __commonJS({
173523
173523
  t2["a191"] = 918;
173524
173524
  });
173525
173525
  });
173526
- exports3.getMetrics = getMetrics;
173526
+ exports3.getMetrics = getMetrics2;
173527
173527
  }),
173528
173528
  /* 30 */
173529
173529
  /***/
@@ -229083,7 +229083,7 @@ var require_pdf_worker4 = __commonJS({
229083
229083
  });
229084
229084
  exports3.getMetrics = void 0;
229085
229085
  var _util = __w_pdfjs_require__(2);
229086
- var getMetrics = (0, _util.getLookupTableFactory)(function(t) {
229086
+ var getMetrics2 = (0, _util.getLookupTableFactory)(function(t) {
229087
229087
  t["Courier"] = 600;
229088
229088
  t["Courier-Bold"] = 600;
229089
229089
  t["Courier-BoldOblique"] = 600;
@@ -232021,7 +232021,7 @@ var require_pdf_worker4 = __commonJS({
232021
232021
  t2["a191"] = 918;
232022
232022
  });
232023
232023
  });
232024
- exports3.getMetrics = getMetrics;
232024
+ exports3.getMetrics = getMetrics2;
232025
232025
  }),
232026
232026
  /* 149 */
232027
232027
  /***/
@@ -281574,18 +281574,18 @@ var SSHBackend = class _SSHBackend {
281574
281574
  });
281575
281575
  return info.socket;
281576
281576
  }
281577
- async buildConnectSocketIfNeeded(sshConfig, emit9) {
281577
+ async buildConnectSocketIfNeeded(sshConfig, emit10) {
281578
281578
  if (sshConfig.jumpHost) {
281579
281579
  const jumpId = `[Jump:${sshConfig.jumpHost.host}]`;
281580
281580
  console.log(`${jumpId} Starting jump host connection flow...`);
281581
- emit9(
281581
+ emit10(
281582
281582
  `\x1B[36m\u25B9 ${jumpId} Establishing tunnel via jump host ${sshConfig.jumpHost.host}...\x1B[0m\r
281583
281583
  `
281584
281584
  );
281585
281585
  const jumpClient = new (loadSsh2()).Client();
281586
281586
  const jumpSock = await this.buildConnectSocketIfNeeded(
281587
281587
  sshConfig.jumpHost,
281588
- emit9
281588
+ emit10
281589
281589
  );
281590
281590
  if (jumpSock) {
281591
281591
  console.log(
@@ -281629,7 +281629,7 @@ var SSHBackend = class _SSHBackend {
281629
281629
  });
281630
281630
  jumpClient.connect(jumpConnectConfig);
281631
281631
  });
281632
- emit9(
281632
+ emit10(
281633
281633
  `\x1B[32m\u2714 ${jumpId} Jump host ready. Requesting forward to target ${sshConfig.host}:${sshConfig.port}...\x1B[0m\r
281634
281634
  `
281635
281635
  );
@@ -281945,25 +281945,25 @@ var SSHBackend = class _SSHBackend {
281945
281945
  };
281946
281946
  this.sessions.set(config2.id, instance);
281947
281947
  (async () => {
281948
- const emit9 = (data) => {
281948
+ const emit10 = (data) => {
281949
281949
  instance.dataCallbacks.forEach((cb) => cb(data));
281950
281950
  };
281951
281951
  const emitExit = (code) => {
281952
281952
  this.emitExitOnce(config2.id, instance, code);
281953
281953
  };
281954
281954
  client2.on("ready", async () => {
281955
- emit9("\x1B[2J\x1B[H\x1B[32m\u2714 Connection established.\x1B[0m\r\n");
281955
+ emit10("\x1B[2J\x1B[H\x1B[32m\u2714 Connection established.\x1B[0m\r\n");
281956
281956
  console.log(
281957
281957
  `[SSH] Connection ready for ${sshConfig.host}:${sshConfig.port}`
281958
281958
  );
281959
281959
  const rawShell = isRawShellPreset(sshConfig.algorithmsPreset);
281960
281960
  try {
281961
- emit9("\x1B[36m\u25B9 Setting up port forwards...\x1B[0m\r\n");
281961
+ emit10("\x1B[36m\u25B9 Setting up port forwards...\x1B[0m\r\n");
281962
281962
  console.log(`[SSH] Setting up port forwards...`);
281963
281963
  await this.setupPortForwards(instance, sshConfig);
281964
281964
  } catch (e) {
281965
281965
  console.error(`[SSH] Port forward setup failed:`, e);
281966
- emit9(`\x1B[31m\u2718 Port forward failed: ${e.message}\x1B[0m\r
281966
+ emit10(`\x1B[31m\u2718 Port forward failed: ${e.message}\x1B[0m\r
281967
281967
  `);
281968
281968
  }
281969
281969
  if (rawShell) {
@@ -281973,7 +281973,7 @@ var SSHBackend = class _SSHBackend {
281973
281973
  );
281974
281974
  } else {
281975
281975
  try {
281976
- emit9("\x1B[36m\u25B9 Detecting remote OS...\x1B[0m\r\n");
281976
+ emit10("\x1B[36m\u25B9 Detecting remote OS...\x1B[0m\r\n");
281977
281977
  console.log(`[SSH] Detecting remote OS...`);
281978
281978
  const uname = await this.execCollect(client2, "uname -s");
281979
281979
  const u = (uname.stdout || uname.stderr || "").toLowerCase();
@@ -281993,13 +281993,13 @@ var SSHBackend = class _SSHBackend {
281993
281993
  if (!instance.remoteOs) instance.remoteOs = "unix";
281994
281994
  console.log(`[SSH] Remote OS detected: ${instance.remoteOs}`);
281995
281995
  try {
281996
- emit9("\x1B[36m\u25B9 Initializing SFTP channel...\x1B[0m\r\n");
281996
+ emit10("\x1B[36m\u25B9 Initializing SFTP channel...\x1B[0m\r\n");
281997
281997
  await this.initializeSftp(instance);
281998
- emit9("\x1B[32m\u2714 SFTP channel ready.\x1B[0m\r\n");
281998
+ emit10("\x1B[32m\u2714 SFTP channel ready.\x1B[0m\r\n");
281999
281999
  } catch (error40) {
282000
282000
  const message = error40 instanceof Error ? error40.message : String(error40);
282001
282001
  instance.sftpInitError = message;
282002
- emit9(
282002
+ emit10(
282003
282003
  `\x1B[33m\u26A0 SFTP unavailable: ${message}. File panel features may be limited.\x1B[0m\r
282004
282004
  `
282005
282005
  );
@@ -282012,7 +282012,7 @@ var SSHBackend = class _SSHBackend {
282012
282012
  }
282013
282013
  }
282014
282014
  }
282015
- emit9("\x1B[36m\u25B9 Opening interactive shell...\x1B[0m\r\n");
282015
+ emit10("\x1B[36m\u25B9 Opening interactive shell...\x1B[0m\r\n");
282016
282016
  console.log(`[SSH] Opening interactive shell...`);
282017
282017
  const initialWindowSize = this.resolveRequestedWindowSize(instance, {
282018
282018
  cols: config2.cols,
@@ -282042,7 +282042,7 @@ var SSHBackend = class _SSHBackend {
282042
282042
  console.error(`[SSH] Failed to open shell:`, err);
282043
282043
  instance.initializationState = "failed";
282044
282044
  instance.isInitializing = false;
282045
- emit9(`\x1B[31m\u2718 Failed to open shell: ${err.message}\x1B[0m\r
282045
+ emit10(`\x1B[31m\u2718 Failed to open shell: ${err.message}\x1B[0m\r
282046
282046
  `);
282047
282047
  emitExit(-1);
282048
282048
  return;
@@ -282052,7 +282052,7 @@ var SSHBackend = class _SSHBackend {
282052
282052
  if (rawShell) {
282053
282053
  instance.initializationState = "ready";
282054
282054
  instance.isInitializing = false;
282055
- emit9("\x1B[32m\u2714 Shell ready.\x1B[0m\r\n");
282055
+ emit10("\x1B[32m\u2714 Shell ready.\x1B[0m\r\n");
282056
282056
  console.log(
282057
282057
  `[SSH] Raw-shell mode: shell ready immediately (preset=${sshConfig.algorithmsPreset}).`
282058
282058
  );
@@ -282060,14 +282060,14 @@ var SSHBackend = class _SSHBackend {
282060
282060
  const chunk2 = data.toString();
282061
282061
  const sanitizedChunk = this.stripReadyMarker(chunk2);
282062
282062
  this.consumeOscMarkers(instance, sanitizedChunk);
282063
- if (sanitizedChunk) emit9(sanitizedChunk);
282063
+ if (sanitizedChunk) emit10(sanitizedChunk);
282064
282064
  });
282065
282065
  stream.on("close", async (code) => {
282066
282066
  emitExit(typeof code === "number" ? code : 0);
282067
282067
  });
282068
282068
  return;
282069
282069
  }
282070
- emit9("\x1B[36m\u25B9 Initializing shell integration...\x1B[0m\r\n");
282070
+ emit10("\x1B[36m\u25B9 Initializing shell integration...\x1B[0m\r\n");
282071
282071
  console.log(
282072
282072
  `[SSH] Shell stream opened. Starting robust initialization...`
282073
282073
  );
@@ -282113,7 +282113,7 @@ var SSHBackend = class _SSHBackend {
282113
282113
  if (retryCount >= maxRetries) {
282114
282114
  instance.initializationState = "failed";
282115
282115
  instance.isInitializing = false;
282116
- emit9(
282116
+ emit10(
282117
282117
  "\x1B[31m\u2718 Initialization failed. Entering fallback mode.\x1B[0m\r\n"
282118
282118
  );
282119
282119
  console.error(
@@ -282122,7 +282122,7 @@ var SSHBackend = class _SSHBackend {
282122
282122
  clearInterval(watchdogInterval);
282123
282123
  return;
282124
282124
  }
282125
- emit9(
282125
+ emit10(
282126
282126
  `\x1B[33m\u26A0 Initialization timeout, retrying (${retryCount}/${maxRetries})...\x1B[0m\r
282127
282127
  `
282128
282128
  );
@@ -282136,7 +282136,7 @@ var SSHBackend = class _SSHBackend {
282136
282136
  if (instance.isInitializing) {
282137
282137
  instance.buffer += chunk2;
282138
282138
  if (instance.buffer.includes(GYSHELL_READY_MARKER2)) {
282139
- emit9("\x1B[2J\x1B[H");
282139
+ emit10("\x1B[2J\x1B[H");
282140
282140
  isReadySent = true;
282141
282141
  clearInterval(watchdogInterval);
282142
282142
  const sawContinuation = /(?:\r?\n)>>\s*\r?\n/.test(instance.buffer) || instance.buffer.trimEnd().endsWith("\n>>") || instance.buffer.trimEnd().endsWith("\r\n>>");
@@ -282147,7 +282147,7 @@ var SSHBackend = class _SSHBackend {
282147
282147
  const realContent = this.stripReadyMarker(
282148
282148
  parts.slice(1).join(GYSHELL_READY_MARKER2)
282149
282149
  ).trimStart();
282150
- if (realContent) emit9(realContent);
282150
+ if (realContent) emit10(realContent);
282151
282151
  }
282152
282152
  instance.buffer = "";
282153
282153
  if (sawContinuation && instance.remoteOs === "windows" && instance.stream) {
@@ -282163,7 +282163,7 @@ var SSHBackend = class _SSHBackend {
282163
282163
  const sanitizedChunk = this.stripReadyMarker(chunk2);
282164
282164
  this.consumeOscMarkers(instance, sanitizedChunk);
282165
282165
  if (sanitizedChunk) {
282166
- emit9(sanitizedChunk);
282166
+ emit10(sanitizedChunk);
282167
282167
  }
282168
282168
  }
282169
282169
  });
@@ -282177,7 +282177,7 @@ var SSHBackend = class _SSHBackend {
282177
282177
  console.error(`[SSH] Client error:`, err);
282178
282178
  instance.initializationState = "failed";
282179
282179
  instance.isInitializing = false;
282180
- emit9(`\x1B[31m\u2718 SSH Error: ${err.message}\x1B[0m\r
282180
+ emit10(`\x1B[31m\u2718 SSH Error: ${err.message}\x1B[0m\r
282181
282181
  `);
282182
282182
  emitExit(-1);
282183
282183
  });
@@ -282200,7 +282200,7 @@ var SSHBackend = class _SSHBackend {
282200
282200
  sshConfig.privateKeyPath
282201
282201
  );
282202
282202
  } catch (e) {
282203
- emit9(
282203
+ emit10(
282204
282204
  `\x1B[31m\u2718 Failed to read private key: ${e.message}\x1B[0m\r
282205
282205
  `
282206
282206
  );
@@ -282212,19 +282212,19 @@ var SSHBackend = class _SSHBackend {
282212
282212
  }
282213
282213
  try {
282214
282214
  await new Promise((r) => setTimeout(r, 50));
282215
- emit9(
282215
+ emit10(
282216
282216
  `\x1B[36m\u25B9 Connecting to ${sshConfig.host}:${sshConfig.port}...\x1B[0m\r
282217
282217
  `
282218
282218
  );
282219
282219
  console.log(
282220
282220
  `[SSH] Attempting to connect to ${sshConfig.host}:${sshConfig.port}...`
282221
282221
  );
282222
- const sock = await this.buildConnectSocketIfNeeded(sshConfig, emit9);
282222
+ const sock = await this.buildConnectSocketIfNeeded(sshConfig, emit10);
282223
282223
  if (sock) {
282224
282224
  console.log(
282225
282225
  `[SSH] SUCCESS: Connection to ${sshConfig.host} will be tunneled through sock (Jump Host/Proxy).`
282226
282226
  );
282227
- emit9(
282227
+ emit10(
282228
282228
  "\x1B[36m\u25B9 [Final] Using tunnel socket for target connection...\x1B[0m\r\n"
282229
282229
  );
282230
282230
  connectConfig.sock = sock;
@@ -282238,7 +282238,7 @@ var SSHBackend = class _SSHBackend {
282238
282238
  const errMsg = e instanceof Error ? e.message : String(e);
282239
282239
  instance.initializationState = "failed";
282240
282240
  instance.isInitializing = false;
282241
- emit9(`\x1B[31m\u2718 Connection failed: ${errMsg}\x1B[0m\r
282241
+ emit10(`\x1B[31m\u2718 Connection failed: ${errMsg}\x1B[0m\r
282242
282242
  `);
282243
282243
  emitExit(-1);
282244
282244
  }
@@ -327549,7 +327549,7 @@ var initializeSax = function() {
327549
327549
  if (parser.opt.xmlns) parser.ns = Object.create(rootNS);
327550
327550
  parser.trackPosition = parser.opt.position !== false;
327551
327551
  if (parser.trackPosition) parser.position = parser.line = parser.column = 0;
327552
- emit9(parser, "onready");
327552
+ emit10(parser, "onready");
327553
327553
  }
327554
327554
  if (!Object.create) Object.create = function(o) {
327555
327555
  function F() {
@@ -328015,16 +328015,16 @@ var initializeSax = function() {
328015
328015
  });
328016
328016
  for (var s in sax$1.STATE) sax$1.STATE[sax$1.STATE[s]] = s;
328017
328017
  S = sax$1.STATE;
328018
- function emit9(parser, event, data) {
328018
+ function emit10(parser, event, data) {
328019
328019
  parser[event] && parser[event](data);
328020
328020
  }
328021
328021
  function emitNode(parser, nodeType, data) {
328022
328022
  if (parser.textNode) closeText(parser);
328023
- emit9(parser, nodeType, data);
328023
+ emit10(parser, nodeType, data);
328024
328024
  }
328025
328025
  function closeText(parser) {
328026
328026
  parser.textNode = textopts(parser.opt, parser.textNode);
328027
- if (parser.textNode) emit9(parser, "ontext", parser.textNode);
328027
+ if (parser.textNode) emit10(parser, "ontext", parser.textNode);
328028
328028
  parser.textNode = "";
328029
328029
  }
328030
328030
  function textopts(opt, text) {
@@ -328037,7 +328037,7 @@ var initializeSax = function() {
328037
328037
  if (parser.trackPosition) er += "\nLine: " + parser.line + "\nColumn: " + parser.column + "\nChar: " + parser.c;
328038
328038
  er = new Error(er);
328039
328039
  parser.error = er;
328040
- emit9(parser, "onerror", er);
328040
+ emit10(parser, "onerror", er);
328041
328041
  return parser;
328042
328042
  }
328043
328043
  function end(parser) {
@@ -328046,7 +328046,7 @@ var initializeSax = function() {
328046
328046
  closeText(parser);
328047
328047
  parser.c = "";
328048
328048
  parser.closed = true;
328049
- emit9(parser, "onend");
328049
+ emit10(parser, "onend");
328050
328050
  SAXParser.call(parser, parser.strict, parser.opt);
328051
328051
  return parser;
328052
328052
  }
@@ -342195,6 +342195,22 @@ var BUILTIN_TOOL_INFO = [
342195
342195
  name: "create_or_edit",
342196
342196
  description: CREATE_OR_EDIT_TOOL_DESCRIPTION
342197
342197
  },
342198
+ {
342199
+ name: "write_file",
342200
+ description: WRITE_FILE_TOOL_DESCRIPTION
342201
+ },
342202
+ {
342203
+ name: "edit_file",
342204
+ description: EDIT_FILE_TOOL_DESCRIPTION
342205
+ },
342206
+ {
342207
+ name: "skill",
342208
+ description: "Load a skill to get detailed instructions for a specific task. Skills provide specialized knowledge, step-by-step guidance, and may include supporting files (scripts, references)."
342209
+ },
342210
+ {
342211
+ name: "create_skill",
342212
+ description: "Create a new skill in GyShell skills. This tool only creates new skills and does not modify or overwrite existing ones. If the skill name already exists, the call must fail and you should choose a different name. If you need to modify an existing skill, use edit_file to edit that skill's md file directly, or write_file only when intentionally replacing the full file."
342213
+ },
342198
342214
  {
342199
342215
  name: "wait",
342200
342216
  description: WAIT_TOOL_DESCRIPTION
@@ -342294,6 +342310,42 @@ var BUILTIN_TOOL_INFO = [
342294
342310
  {
342295
342311
  name: "manage_trigger",
342296
342312
  description: MANAGE_TRIGGER_DESCRIPTION
342313
+ },
342314
+ {
342315
+ name: "get_metrics",
342316
+ description: 'Read host metrics as Prometheus exposition text (for a scraper) or a one-line dashboard summary. Use to answer "how are my hosts doing" or to feed an external Prometheus/OTel collector.'
342317
+ },
342318
+ {
342319
+ name: "manage_secret",
342320
+ description: "Manage the encrypted secrets vault \u2014 list metadata (never values), set, delete, or check a secret. Secrets are materialized only at exec time and never enter the conversation. Vault must be unlocked (RTERM_SECRETS_MASTER_KEY)."
342321
+ },
342322
+ {
342323
+ name: "manage_oncall",
342324
+ description: "Incident on-call paging \u2014 list open pages, raise a page for an incident under an escalation policy, acknowledge or resolve a page, list policies, or advance the escalation clock."
342325
+ },
342326
+ {
342327
+ name: "get_cost",
342328
+ description: "AI cost & budgets \u2014 summarize token spend in dollars (per model/profile, daily/monthly), check an intended run against budgets (ok/warn/throttle/deny), or list budgets."
342329
+ },
342330
+ {
342331
+ name: "manage_recording",
342332
+ description: "asciinema-style session recording \u2014 list, start, stop, replay (scrub), export (.cast), or delete a terminal session recording."
342333
+ },
342334
+ {
342335
+ name: "manage_gitops",
342336
+ description: "GitOps for desired state \u2014 export the live estate (connections/playbooks/triggers/etc.) as a content-hashed manifest, or detect drift / verify a manifest against live."
342337
+ },
342338
+ {
342339
+ name: "manage_playbook_version",
342340
+ description: "Playbook/runbook versioning + lint \u2014 statically lint a playbook definition (undefined params, dependsOn cycles, empty steps, missing rollback), list version history, roll back, or diff two versions."
342341
+ },
342342
+ {
342343
+ name: "get_cloud_inventory",
342344
+ description: "Cloud resource inventory (AWS/GCP/Azure) \u2014 summary counts by provider/state, query instances (filter by provider/state/region), or pull fresh inventory."
342345
+ },
342346
+ {
342347
+ name: "get_live_dashboard",
342348
+ description: "Live multi-client dashboard \u2014 read the current unified dashboard state/summary, or the number of connected dashboard subscribers."
342297
342349
  }
342298
342350
  ];
342299
342351
  function buildReadFileDescription(support) {
@@ -346381,6 +346433,332 @@ ${body}`;
346381
346433
  return msg;
346382
346434
  }
346383
346435
 
346436
+ // packages/backend/src/services/AgentHelper/tools/observability_tools.ts
346437
+ function emit9(context2, toolName, input, output) {
346438
+ context2.sendEvent(context2.sessionId, {
346439
+ messageId: context2.messageId,
346440
+ type: "tool_call",
346441
+ toolName,
346442
+ input: typeof input === "string" ? input : JSON.stringify(input),
346443
+ output
346444
+ });
346445
+ }
346446
+ function obs(context2, toolName, args) {
346447
+ const o = context2.observability;
346448
+ if (!o) {
346449
+ const msg = `${toolName} is not available in this runtime (observability not wired).`;
346450
+ emit9(context2, toolName, args, msg);
346451
+ return { o: null, msg };
346452
+ }
346453
+ return { o, msg: null };
346454
+ }
346455
+ var getMetricsSchema = external_exports.object({
346456
+ format: external_exports.enum(["prometheus", "summary"]).optional().describe("'prometheus' = exposition text for a scraper; 'summary' = dashboard summary line (default).")
346457
+ });
346458
+ async function getMetrics(args, context2) {
346459
+ const { o, msg } = obs(context2, "get_metrics", args);
346460
+ if (!o) return msg;
346461
+ const out = args.format === "prometheus" ? o.metricsExport.renderPrometheus() || "# no host metrics recorded yet" : await o.dashboard.summary();
346462
+ emit9(context2, "get_metrics", args, out);
346463
+ return out;
346464
+ }
346465
+ var manageSecretSchema = external_exports.object({
346466
+ action: external_exports.enum(["list", "set", "delete", "has"]).describe("list metadata (never values), set a secret, delete one, or check existence."),
346467
+ key: external_exports.string().optional().describe("Secret key (required for set/delete/has)."),
346468
+ value: external_exports.string().optional().describe("Secret value (required for set). Never echoed back."),
346469
+ labels: external_exports.record(external_exports.string()).optional().describe("Optional labels (service, scope, connection id).")
346470
+ });
346471
+ async function manageSecret(args, context2) {
346472
+ const { o, msg } = obs(context2, "manage_secret", args);
346473
+ if (!o) return msg;
346474
+ const v = o.secrets;
346475
+ if (!v.unlocked()) {
346476
+ const m = "Secrets vault is locked \u2014 start RTerm with RTERM_SECRETS_MASTER_KEY set.";
346477
+ emit9(context2, "manage_secret", args, m);
346478
+ return m;
346479
+ }
346480
+ let out;
346481
+ if (args.action === "list") {
346482
+ const items = v.list();
346483
+ out = items.length ? items.map((m) => `- ${m.key}${m.labels ? ` ${JSON.stringify(m.labels)}` : ""} (updated ${new Date(m.updatedAt).toISOString()})`).join("\n") : "No secrets stored.";
346484
+ } else if (args.action === "set") {
346485
+ if (!args.key || args.value === void 0) {
346486
+ out = "set requires key + value.";
346487
+ } else {
346488
+ v.set(args.key, args.value, args.labels);
346489
+ out = `Stored secret '${args.key}'.`;
346490
+ }
346491
+ } else if (args.action === "delete") {
346492
+ if (!args.key) {
346493
+ out = "delete requires key.";
346494
+ } else {
346495
+ out = v.delete(args.key) ? `Deleted secret '${args.key}'.` : `No secret '${args.key}'.`;
346496
+ }
346497
+ } else {
346498
+ if (!args.key) {
346499
+ out = "has requires key.";
346500
+ } else {
346501
+ out = v.has(args.key) ? `'${args.key}' exists.` : `'${args.key}' does not exist.`;
346502
+ }
346503
+ }
346504
+ emit9(context2, "manage_secret", args, out);
346505
+ return out;
346506
+ }
346507
+ var manageOncallSchema = external_exports.object({
346508
+ action: external_exports.enum(["open_pages", "page", "ack", "resolve", "list_policies", "tick"]).describe("List open pages, raise a page, ack/resolve a page, list policies, or advance the escalation clock."),
346509
+ pageId: external_exports.string().optional().describe("Page id (ack/resolve)."),
346510
+ by: external_exports.string().optional().describe("Who is acknowledging (ack)."),
346511
+ incidentId: external_exports.string().optional().describe("Incident id (page)."),
346512
+ policyId: external_exports.string().optional().describe("Escalation policy id (page)."),
346513
+ title: external_exports.string().optional().describe("Page title (page)."),
346514
+ severity: external_exports.string().optional().describe("Severity e.g. sev1/sev2/sev3 (page).")
346515
+ });
346516
+ async function manageOncall(args, context2) {
346517
+ const { o, msg } = obs(context2, "manage_oncall", args);
346518
+ if (!o) return msg;
346519
+ const s = o.oncall;
346520
+ let out;
346521
+ try {
346522
+ if (args.action === "open_pages") {
346523
+ const pages = s.openPages();
346524
+ out = pages.length ? pages.map((p) => `- [${p.severity}] ${p.title} (level ${p.levelIndex}, page ${p.id})`).join("\n") : "No open pages.";
346525
+ } else if (args.action === "list_policies") {
346526
+ const pols = s.listPolicies();
346527
+ out = pols.length ? pols.map((p) => `- ${p.name} (${p.id}): ${p.levels.length} level(s)`).join("\n") : "No escalation policies registered.";
346528
+ } else if (args.action === "page") {
346529
+ if (!args.incidentId || !args.policyId || !args.title || !args.severity) {
346530
+ out = "page requires incidentId, policyId, title, severity.";
346531
+ } else {
346532
+ const p = await s.page({ incidentId: args.incidentId, policyId: args.policyId, title: args.title, severity: args.severity });
346533
+ out = `Paged (page ${p.id}) at level 0.`;
346534
+ }
346535
+ } else if (args.action === "ack") {
346536
+ if (!args.pageId || !args.by) {
346537
+ out = "ack requires pageId + by.";
346538
+ } else {
346539
+ s.acknowledge(args.pageId, args.by);
346540
+ out = `Page ${args.pageId} acknowledged by ${args.by}.`;
346541
+ }
346542
+ } else if (args.action === "resolve") {
346543
+ if (!args.pageId) {
346544
+ out = "resolve requires pageId.";
346545
+ } else {
346546
+ s.resolve(args.pageId);
346547
+ out = `Page ${args.pageId} resolved.`;
346548
+ }
346549
+ } else {
346550
+ const esc2 = await s.tick();
346551
+ out = esc2.length ? `Escalated ${esc2.length} page(s).` : "No pages needed escalation.";
346552
+ }
346553
+ } catch (e) {
346554
+ out = `on-call error: ${e instanceof Error ? e.message : String(e)}`;
346555
+ }
346556
+ emit9(context2, "manage_oncall", args, out);
346557
+ return out;
346558
+ }
346559
+ var getCostSchema = external_exports.object({
346560
+ action: external_exports.enum(["summary", "check", "list_budgets"]).describe("summary of spend, check a run against budgets, or list budgets."),
346561
+ period: external_exports.enum(["daily", "monthly"]).optional().describe("Window for summary (default daily)."),
346562
+ model: external_exports.string().optional().describe("Filter by model / the model to check."),
346563
+ profileId: external_exports.string().optional().describe("Filter by profile / the profile to check.")
346564
+ });
346565
+ async function getCost(args, context2) {
346566
+ const { o, msg } = obs(context2, "get_cost", args);
346567
+ if (!o) return msg;
346568
+ let out;
346569
+ if (args.action === "summary") {
346570
+ const s = o.cost.summarize({ period: args.period ?? "daily", model: args.model, profileId: args.profileId });
346571
+ const lines = s.byModel.map((m) => ` ${m.model}: $${m.usd.toFixed(4)} (${m.promptTokens}in/${m.completionTokens}out)`).join("\n");
346572
+ out = `Spend (${args.period ?? "daily"}): $${s.totalUsd.toFixed(4)} total.${lines ? "\n" + lines : ""}`;
346573
+ } else if (args.action === "check") {
346574
+ const r = o.cost.check({ model: args.model, profileId: args.profileId });
346575
+ out = `Budget check \u2192 ${r.action.toUpperCase()}${r.statuses.length ? ` (${r.statuses.map((s) => `${s.budget.id}=${(s.ratio * 100).toFixed(0)}%`).join(", ")})` : " (no matching budgets)"}.`;
346576
+ } else {
346577
+ const b = o.cost.listBudgets();
346578
+ out = b.length ? b.map((x) => `- ${x.id}: ${x.model ?? "*"}/${x.profileId ?? "*"} ${x.period} cap $${x.capUsd}`).join("\n") : "No budgets configured.";
346579
+ }
346580
+ emit9(context2, "get_cost", args, out);
346581
+ return out;
346582
+ }
346583
+ var manageRecordingSchema = external_exports.object({
346584
+ action: external_exports.enum(["list", "start", "stop", "replay", "export_cast", "delete"]).describe("List, start, stop, replay, export (.cast), or delete a recording."),
346585
+ recordingId: external_exports.string().optional().describe("Recording id (stop/replay/export_cast/delete)."),
346586
+ terminalId: external_exports.string().optional().describe("Terminal to record (start)."),
346587
+ title: external_exports.string().optional().describe("Title (start)."),
346588
+ fromSec: external_exports.number().optional().describe("Replay start offset seconds."),
346589
+ durationSec: external_exports.number().optional().describe("Replay duration seconds.")
346590
+ });
346591
+ async function manageRecording(args, context2) {
346592
+ const { o, msg } = obs(context2, "manage_recording", args);
346593
+ if (!o) return msg;
346594
+ const r = o.recording;
346595
+ let out;
346596
+ try {
346597
+ if (args.action === "list") {
346598
+ const list = r.list();
346599
+ out = list.length ? list.map((x) => `- ${x.id} (${x.terminalId}) ${x.events} events${x.endedAt ? " [stopped]" : " [recording]"}`).join("\n") : "No recordings.";
346600
+ } else if (args.action === "start") {
346601
+ if (!args.terminalId) {
346602
+ out = "start requires terminalId.";
346603
+ } else {
346604
+ out = `Recording started: ${r.start(args.terminalId, { title: args.title })}`;
346605
+ }
346606
+ } else if (args.action === "stop") {
346607
+ if (!args.recordingId) {
346608
+ out = "stop requires recordingId.";
346609
+ } else {
346610
+ const rec = r.stop(args.recordingId);
346611
+ out = `Recording ${args.recordingId} stopped (${rec.events.length} events).`;
346612
+ }
346613
+ } else if (args.action === "replay") {
346614
+ if (!args.recordingId) {
346615
+ out = "replay requires recordingId.";
346616
+ } else {
346617
+ const ev = r.replay(args.recordingId, { fromSec: args.fromSec, durationSec: args.durationSec });
346618
+ out = ev.length ? ev.map((e) => `[+${e.t.toFixed(1)}s] ${e.data}`).join("") : "(no events in window)";
346619
+ }
346620
+ } else if (args.action === "export_cast") {
346621
+ if (!args.recordingId) {
346622
+ out = "export_cast requires recordingId.";
346623
+ } else {
346624
+ out = r.exportCast(args.recordingId);
346625
+ }
346626
+ } else {
346627
+ if (!args.recordingId) {
346628
+ out = "delete requires recordingId.";
346629
+ } else {
346630
+ out = r.delete(args.recordingId) ? `Deleted ${args.recordingId}.` : `No recording ${args.recordingId}.`;
346631
+ }
346632
+ }
346633
+ } catch (e) {
346634
+ out = `recording error: ${e instanceof Error ? e.message : String(e)}`;
346635
+ }
346636
+ emit9(context2, "manage_recording", args, out);
346637
+ return out;
346638
+ }
346639
+ var manageGitopsSchema = external_exports.object({
346640
+ action: external_exports.enum(["export", "drift", "in_sync"]).describe("export the live desired-state manifest, or diff/verify a manifest against live."),
346641
+ manifest: external_exports.any().optional().describe("A StateManifest (for drift/in_sync).")
346642
+ });
346643
+ async function manageGitops(args, context2) {
346644
+ const { o, msg } = obs(context2, "manage_gitops", args);
346645
+ if (!o) return msg;
346646
+ let out;
346647
+ try {
346648
+ if (args.action === "export") {
346649
+ const m = await o.gitops.exportLive();
346650
+ out = `Exported manifest: ${m.entities.length} entities, stateHash ${m.stateHash.slice(0, 12)}\u2026`;
346651
+ } else if (args.action === "drift") {
346652
+ if (!args.manifest) {
346653
+ out = "drift requires a manifest.";
346654
+ } else {
346655
+ const d = await o.gitops.drift(args.manifest);
346656
+ out = d.length ? d.map((x) => `- ${x.id} (${x.kind}): ${x.drift}`).join("\n") : "No drift \u2014 live matches the manifest.";
346657
+ }
346658
+ } else {
346659
+ if (!args.manifest) {
346660
+ out = "in_sync requires a manifest.";
346661
+ } else {
346662
+ out = await o.gitops.inSync(args.manifest) ? "In sync." : "Out of sync (drift present).";
346663
+ }
346664
+ }
346665
+ } catch (e) {
346666
+ out = `gitops error: ${e instanceof Error ? e.message : String(e)}`;
346667
+ }
346668
+ emit9(context2, "manage_gitops", args, out);
346669
+ return out;
346670
+ }
346671
+ var managePlaybookVersionSchema = external_exports.object({
346672
+ action: external_exports.enum(["lint", "history", "rollback", "diff"]).describe("lint a playbook def, list version history, roll back, or diff two versions."),
346673
+ playbookId: external_exports.string().optional().describe("Playbook id (history/rollback/diff)."),
346674
+ def: external_exports.any().optional().describe("Playbook definition (lint)."),
346675
+ version: external_exports.number().int().optional().describe("Version to roll back to (rollback)."),
346676
+ a: external_exports.number().int().optional().describe("First version (diff)."),
346677
+ b: external_exports.number().int().optional().describe("Second version (diff).")
346678
+ });
346679
+ async function managePlaybookVersion(args, context2) {
346680
+ const { o, msg } = obs(context2, "manage_playbook_version", args);
346681
+ if (!o) return msg;
346682
+ let out;
346683
+ try {
346684
+ if (args.action === "lint") {
346685
+ if (!args.def) {
346686
+ out = "lint requires a playbook def.";
346687
+ } else {
346688
+ const issues = o.playbooks.lint(args.def);
346689
+ out = issues.length ? issues.map((i) => `- [${i.severity}] ${i.rule}: ${i.message}`).join("\n") : "Playbook lints clean.";
346690
+ }
346691
+ } else if (args.action === "history") {
346692
+ if (!args.playbookId) {
346693
+ out = "history requires playbookId.";
346694
+ } else {
346695
+ const h = o.playbooks.versioning.history(args.playbookId);
346696
+ out = h.length ? h.map((v) => `- v${v.version} (${v.hash})${v.comment ? ` ${v.comment}` : ""}`).join("\n") : `No versions for '${args.playbookId}'.`;
346697
+ }
346698
+ } else if (args.action === "rollback") {
346699
+ if (!args.playbookId || args.version === void 0) {
346700
+ out = "rollback requires playbookId + version.";
346701
+ } else {
346702
+ const v = o.playbooks.versioning.rollback(args.playbookId, args.version);
346703
+ out = `Rolled back to v${args.version} \u2192 new v${v.version}.`;
346704
+ }
346705
+ } else {
346706
+ if (!args.playbookId || args.a === void 0 || args.b === void 0) {
346707
+ out = "diff requires playbookId + a + b.";
346708
+ } else {
346709
+ out = o.playbooks.versioning.diff(args.playbookId, args.a, args.b);
346710
+ }
346711
+ }
346712
+ } catch (e) {
346713
+ out = `playbook error: ${e instanceof Error ? e.message : String(e)}`;
346714
+ }
346715
+ emit9(context2, "manage_playbook_version", args, out);
346716
+ return out;
346717
+ }
346718
+ var getCloudInventorySchema = external_exports.object({
346719
+ action: external_exports.enum(["summary", "query", "sync"]).describe("summary counts, query resources, or pull fresh inventory."),
346720
+ provider: external_exports.enum(["aws", "gcp", "azure"]).optional().describe("Filter by provider."),
346721
+ state: external_exports.string().optional().describe("Filter by state (running/stopped/\u2026)."),
346722
+ region: external_exports.string().optional().describe("Filter by region.")
346723
+ });
346724
+ async function getCloudInventory(args, context2) {
346725
+ const { o, msg } = obs(context2, "get_cloud_inventory", args);
346726
+ if (!o) return msg;
346727
+ let out;
346728
+ try {
346729
+ if (args.action === "summary") {
346730
+ const s = o.cloud.summary();
346731
+ out = `Cloud inventory: ${s.total} resources. By provider: ${JSON.stringify(s.byProvider)}. By state: ${JSON.stringify(s.byState)}.`;
346732
+ } else if (args.action === "query") {
346733
+ const r = o.cloud.query({ provider: args.provider, state: args.state, region: args.region });
346734
+ out = r.length ? r.map((x) => `- [${x.provider}] ${x.name} (${x.machineType ?? x.kind}) ${x.state ?? ""} ${x.region ?? ""}`).join("\n") : "No matching cloud resources.";
346735
+ } else {
346736
+ const r = await o.cloud.sync();
346737
+ out = `Synced ${r.added} resources${r.errors.length ? `, ${r.errors.length} account error(s)` : ""}.`;
346738
+ }
346739
+ } catch (e) {
346740
+ out = `cloud error: ${e instanceof Error ? e.message : String(e)}`;
346741
+ }
346742
+ emit9(context2, "get_cloud_inventory", args, out);
346743
+ return out;
346744
+ }
346745
+ var getLiveDashboardSchema = external_exports.object({
346746
+ action: external_exports.enum(["state", "subscribers"]).describe("'state' = current dashboard state; 'subscribers' = connected client count.")
346747
+ });
346748
+ async function getLiveDashboard(args, context2) {
346749
+ const { o, msg } = obs(context2, "get_live_dashboard", args);
346750
+ if (!o) return msg;
346751
+ let out;
346752
+ if (args.action === "subscribers") {
346753
+ out = `${o.liveDashboard.subscriberCount()} dashboard subscriber(s) connected.`;
346754
+ } else {
346755
+ const s = await o.dashboard.summary();
346756
+ out = s;
346757
+ }
346758
+ emit9(context2, "get_live_dashboard", args, out);
346759
+ return out;
346760
+ }
346761
+
346384
346762
  // packages/backend/src/services/AgentHelper/tools/skill_tools.ts
346385
346763
  var skillToolSchema = external_exports.object({
346386
346764
  name: external_exports.string().describe("The skill identifier from available_skills")
@@ -346648,6 +347026,51 @@ function buildToolsForModel(readFileSupport) {
346648
347026
  name: "import_putty",
346649
347027
  description: BUILTIN_TOOL_INFO.find((t) => t.name === "import_putty")?.description ?? "",
346650
347028
  schema: importPuttySchema
347029
+ },
347030
+ {
347031
+ name: "get_metrics",
347032
+ description: 'Read host metrics as Prometheus exposition text (for a scraper) or a one-line dashboard summary. Use to answer "how are my hosts doing" or to feed an external Prometheus/OTel collector.',
347033
+ schema: getMetricsSchema
347034
+ },
347035
+ {
347036
+ name: "manage_secret",
347037
+ description: "Manage the encrypted secrets vault \u2014 list metadata (never values), set, delete, or check a secret. Secrets are materialized only at exec time and never enter the conversation. Vault must be unlocked (RTERM_SECRETS_MASTER_KEY).",
347038
+ schema: manageSecretSchema
347039
+ },
347040
+ {
347041
+ name: "manage_oncall",
347042
+ description: "Incident on-call paging \u2014 list open pages, raise a page for an incident under an escalation policy, acknowledge or resolve a page, list policies, or advance the escalation clock.",
347043
+ schema: manageOncallSchema
347044
+ },
347045
+ {
347046
+ name: "get_cost",
347047
+ description: "AI cost & budgets \u2014 summarize token spend in dollars (per model/profile, daily/monthly), check an intended run against budgets (ok/warn/throttle/deny), or list budgets.",
347048
+ schema: getCostSchema
347049
+ },
347050
+ {
347051
+ name: "manage_recording",
347052
+ description: "asciinema-style session recording \u2014 list, start, stop, replay (scrub), export (.cast), or delete a terminal session recording.",
347053
+ schema: manageRecordingSchema
347054
+ },
347055
+ {
347056
+ name: "manage_gitops",
347057
+ description: "GitOps for desired state \u2014 export the live estate (connections/playbooks/triggers/etc.) as a content-hashed manifest, or detect drift / verify a manifest against live.",
347058
+ schema: manageGitopsSchema
347059
+ },
347060
+ {
347061
+ name: "manage_playbook_version",
347062
+ description: "Playbook/runbook versioning + lint \u2014 statically lint a playbook definition (undefined params, dependsOn cycles, empty steps, missing rollback), list version history, roll back, or diff two versions.",
347063
+ schema: managePlaybookVersionSchema
347064
+ },
347065
+ {
347066
+ name: "get_cloud_inventory",
347067
+ description: "Cloud resource inventory (AWS/GCP/Azure) \u2014 summary counts by provider/state, query instances (filter by provider/state/region), or pull fresh inventory.",
347068
+ schema: getCloudInventorySchema
347069
+ },
347070
+ {
347071
+ name: "get_live_dashboard",
347072
+ description: "Live multi-client dashboard \u2014 read the current unified dashboard state/summary, or the number of connected dashboard subscribers.",
347073
+ schema: getLiveDashboardSchema
346651
347074
  }
346652
347075
  ].map((tool2) => convertToOpenAITool(tool2));
346653
347076
  }
@@ -346684,6 +347107,15 @@ var toolImplementations = {
346684
347107
  manageChange,
346685
347108
  manageTrigger,
346686
347109
  importPutty,
347110
+ getMetrics,
347111
+ manageSecret,
347112
+ manageOncall,
347113
+ getCost,
347114
+ manageRecording,
347115
+ manageGitops,
347116
+ managePlaybookVersion,
347117
+ getCloudInventory,
347118
+ getLiveDashboard,
346687
347119
  writeFile,
346688
347120
  editFile,
346689
347121
  writeAndEdit,
@@ -348813,11 +349245,11 @@ var AbstractChatCompletionRunner = class extends EventStream {
348813
349245
  this._addMessage(message);
348814
349246
  return chatCompletion;
348815
349247
  }
348816
- _addMessage(message, emit9 = true) {
349248
+ _addMessage(message, emit10 = true) {
348817
349249
  if (!("content" in message))
348818
349250
  message.content = null;
348819
349251
  this.messages.push(message);
348820
- if (emit9) {
349252
+ if (emit10) {
348821
349253
  this._emit("message", message);
348822
349254
  if (isToolMessage2(message) && message.content) {
348823
349255
  this._emit("functionToolCallResult", message.content);
@@ -349069,8 +349501,8 @@ var ChatCompletionRunner = class _ChatCompletionRunner extends AbstractChatCompl
349069
349501
  runner._run(() => runner._runTools(client2, params, opts));
349070
349502
  return runner;
349071
349503
  }
349072
- _addMessage(message, emit9 = true) {
349073
- super._addMessage(message, emit9);
349504
+ _addMessage(message, emit10 = true) {
349505
+ super._addMessage(message, emit10);
349074
349506
  if (isAssistantMessage(message) && message.content) {
349075
349507
  this._emit("content", message.content);
349076
349508
  }
@@ -359896,6 +360328,7 @@ var AgentService_v2 = class {
359896
360328
  /** Optional automation store backing the automation agent tools. */
359897
360329
  automationManager;
359898
360330
  triggerEngine;
360331
+ observability;
359899
360332
  /** Optional session-log handle for list_session_logs / read_session_log. */
359900
360333
  sessionLogger;
359901
360334
  /** Optional run ledger — persisted audit + token-cost record of every
@@ -359969,6 +360402,10 @@ var AgentService_v2 = class {
359969
360402
  setTriggerEngine(engine) {
359970
360403
  this.triggerEngine = engine ?? void 0;
359971
360404
  }
360405
+ /** Wire the observability handle (v2.9.x) so the observability_* agent tools work. */
360406
+ setObservability(obs2) {
360407
+ this.observability = obs2 ?? void 0;
360408
+ }
359972
360409
  /** Wire a session-log handle so list_session_logs / read_session_log work. */
359973
360410
  setSessionLogger(logger) {
359974
360411
  this.sessionLogger = logger ?? void 0;
@@ -361145,6 +361582,87 @@ Actually, your intention might be different. Please re-read the description of t
361145
361582
  }
361146
361583
  break;
361147
361584
  }
361585
+ case "get_metrics": {
361586
+ try {
361587
+ const validatedArgs = getMetricsSchema.parse(toolCall.args || {});
361588
+ result = await toolImplementations.getMetrics(validatedArgs, executionContext);
361589
+ } catch (err) {
361590
+ result = `Parameter validation error for get_metrics: ${err.message}`;
361591
+ }
361592
+ break;
361593
+ }
361594
+ case "manage_secret": {
361595
+ try {
361596
+ const validatedArgs = manageSecretSchema.parse(toolCall.args || {});
361597
+ result = await toolImplementations.manageSecret(validatedArgs, executionContext);
361598
+ } catch (err) {
361599
+ result = `Parameter validation error for manage_secret: ${err.message}`;
361600
+ }
361601
+ break;
361602
+ }
361603
+ case "manage_oncall": {
361604
+ try {
361605
+ const validatedArgs = manageOncallSchema.parse(toolCall.args || {});
361606
+ result = await toolImplementations.manageOncall(validatedArgs, executionContext);
361607
+ } catch (err) {
361608
+ result = `Parameter validation error for manage_oncall: ${err.message}`;
361609
+ }
361610
+ break;
361611
+ }
361612
+ case "get_cost": {
361613
+ try {
361614
+ const validatedArgs = getCostSchema.parse(toolCall.args || {});
361615
+ result = await toolImplementations.getCost(validatedArgs, executionContext);
361616
+ } catch (err) {
361617
+ result = `Parameter validation error for get_cost: ${err.message}`;
361618
+ }
361619
+ break;
361620
+ }
361621
+ case "manage_recording": {
361622
+ try {
361623
+ const validatedArgs = manageRecordingSchema.parse(toolCall.args || {});
361624
+ result = await toolImplementations.manageRecording(validatedArgs, executionContext);
361625
+ } catch (err) {
361626
+ result = `Parameter validation error for manage_recording: ${err.message}`;
361627
+ }
361628
+ break;
361629
+ }
361630
+ case "manage_gitops": {
361631
+ try {
361632
+ const validatedArgs = manageGitopsSchema.parse(toolCall.args || {});
361633
+ result = await toolImplementations.manageGitops(validatedArgs, executionContext);
361634
+ } catch (err) {
361635
+ result = `Parameter validation error for manage_gitops: ${err.message}`;
361636
+ }
361637
+ break;
361638
+ }
361639
+ case "manage_playbook_version": {
361640
+ try {
361641
+ const validatedArgs = managePlaybookVersionSchema.parse(toolCall.args || {});
361642
+ result = await toolImplementations.managePlaybookVersion(validatedArgs, executionContext);
361643
+ } catch (err) {
361644
+ result = `Parameter validation error for manage_playbook_version: ${err.message}`;
361645
+ }
361646
+ break;
361647
+ }
361648
+ case "get_cloud_inventory": {
361649
+ try {
361650
+ const validatedArgs = getCloudInventorySchema.parse(toolCall.args || {});
361651
+ result = await toolImplementations.getCloudInventory(validatedArgs, executionContext);
361652
+ } catch (err) {
361653
+ result = `Parameter validation error for get_cloud_inventory: ${err.message}`;
361654
+ }
361655
+ break;
361656
+ }
361657
+ case "get_live_dashboard": {
361658
+ try {
361659
+ const validatedArgs = getLiveDashboardSchema.parse(toolCall.args || {});
361660
+ result = await toolImplementations.getLiveDashboard(validatedArgs, executionContext);
361661
+ } catch (err) {
361662
+ result = `Parameter validation error for get_live_dashboard: ${err.message}`;
361663
+ }
361664
+ break;
361665
+ }
361148
361666
  case "manage_device_memory": {
361149
361667
  try {
361150
361668
  const validatedArgs = manageDeviceMemorySchema.parse(toolCall.args || {});
@@ -361946,6 +362464,7 @@ ${reminder}`;
361946
362464
  agentRunLedger: this.agentRunLedger,
361947
362465
  changeLedger: this.changeLedger,
361948
362466
  triggerEngine: this.triggerEngine,
362467
+ observability: this.observability,
361949
362468
  agentRunId,
361950
362469
  savedSshConnections: this.settings?.connections?.ssh ?? [],
361951
362470
  savedWinrmConnections: this.settings?.connections?.winrm ?? [],
@@ -365469,6 +365988,24 @@ var WebSocketGatewayAdapter = class {
365469
365988
  }
365470
365989
  async executeRequest(request, socket) {
365471
365990
  const params = request.params ?? {};
365991
+ if (request.method.startsWith("observability:")) {
365992
+ const bridge = this.options.observabilityBridge;
365993
+ if (!bridge) {
365994
+ throw new WebSocketRpcError(
365995
+ "METHOD_NOT_FOUND",
365996
+ `${request.method} is not available on this websocket gateway.`
365997
+ );
365998
+ }
365999
+ const fnName = request.method.slice("observability:".length);
366000
+ const fn = bridge[fnName];
366001
+ if (typeof fn !== "function") {
366002
+ throw new WebSocketRpcError(
366003
+ "METHOD_NOT_FOUND",
366004
+ `Unknown observability method: ${request.method}`
366005
+ );
366006
+ }
366007
+ return await fn(params);
366008
+ }
365472
366009
  switch (request.method) {
365473
366010
  case "gateway:ping":
365474
366011
  return { pong: true, ts: Date.now() };
@@ -383986,6 +384523,89 @@ function createObservability(deps) {
383986
384523
  };
383987
384524
  }
383988
384525
 
384526
+ // packages/backend/src/services/Gateway/observabilityBridge.ts
384527
+ function requireObs(deps) {
384528
+ const o = deps.observability();
384529
+ if (!o) throw new Error("observability is not available on this runtime");
384530
+ return o;
384531
+ }
384532
+ function createObservabilityBridge(deps) {
384533
+ return {
384534
+ // ── metrics / prometheus / otel ─────────────────────────────────────────
384535
+ /** Prometheus exposition text for all host metrics. */
384536
+ metricsPrometheus: async () => requireObs(deps).metricsExport.renderPrometheus(),
384537
+ /** dashboard state (unified). */
384538
+ dashboardState: async () => requireObs(deps).dashboard.state(),
384539
+ /** dashboard summary line. */
384540
+ dashboardSummary: async () => requireObs(deps).dashboard.summary(),
384541
+ // ── secrets vault (metadata only — never values) ────────────────────────
384542
+ secretsList: async (params) => requireObs(deps).secrets.list(params),
384543
+ secretsSet: async (params) => {
384544
+ const v = requireObs(deps).secrets;
384545
+ v.set(params.key, params.value, params.labels);
384546
+ return { ok: true, key: params.key };
384547
+ },
384548
+ secretsDelete: async (params) => ({ deleted: requireObs(deps).secrets.delete(params.key) }),
384549
+ secretsHas: async (params) => ({ exists: requireObs(deps).secrets.has(params.key) }),
384550
+ // ── on-call / escalation ────────────────────────────────────────────────
384551
+ oncallListPolicies: async () => requireObs(deps).oncall.listPolicies(),
384552
+ oncallRegisterPolicy: async (params) => {
384553
+ requireObs(deps).oncall.registerPolicy(params);
384554
+ return { ok: true, id: params.id };
384555
+ },
384556
+ oncallOpenPages: async () => requireObs(deps).oncall.openPages(),
384557
+ oncallPage: async (params) => requireObs(deps).oncall.page(params),
384558
+ oncallAck: async (params) => requireObs(deps).oncall.acknowledge(params.pageId, params.by),
384559
+ oncallResolve: async (params) => requireObs(deps).oncall.resolve(params.pageId),
384560
+ oncallTick: async () => requireObs(deps).oncall.tick(),
384561
+ // ── AI cost & budgets ───────────────────────────────────────────────────
384562
+ costSummary: async (params) => requireObs(deps).cost.summarize(params),
384563
+ costRecord: async (params) => ({
384564
+ usd: requireObs(deps).cost.record(params)
384565
+ }),
384566
+ costCheck: async (params) => requireObs(deps).cost.check(params),
384567
+ costListBudgets: async () => requireObs(deps).cost.listBudgets(),
384568
+ costSetBudget: async (params) => {
384569
+ requireObs(deps).cost.setBudget(params);
384570
+ return { ok: true, id: params.id };
384571
+ },
384572
+ costRemoveBudget: async (params) => ({ removed: requireObs(deps).cost.removeBudget(params.id) }),
384573
+ // ── session recording ───────────────────────────────────────────────────
384574
+ recordingList: async () => requireObs(deps).recording.list(),
384575
+ recordingStart: async (params) => ({
384576
+ recordingId: requireObs(deps).recording.start(params.terminalId, params)
384577
+ }),
384578
+ recordingStop: async (params) => requireObs(deps).recording.stop(params.recordingId),
384579
+ recordingReplay: async (params) => requireObs(deps).recording.replay(params.recordingId, params),
384580
+ recordingExportCast: async (params) => requireObs(deps).recording.exportCast(params.recordingId),
384581
+ recordingDelete: async (params) => ({ deleted: requireObs(deps).recording.delete(params.recordingId) }),
384582
+ // ── gitops ──────────────────────────────────────────────────────────────
384583
+ gitopsExport: async () => requireObs(deps).gitops.exportLive(),
384584
+ gitopsDrift: async (params) => requireObs(deps).gitops.drift(params.manifest),
384585
+ gitopsInSync: async (params) => ({
384586
+ inSync: await requireObs(deps).gitops.inSync(params.manifest)
384587
+ }),
384588
+ gitopsReconcile: async (params) => requireObs(deps).gitops.reconcile(params.manifest, { deleteRemoved: params.deleteRemoved }),
384589
+ // ── playbook versioning + lint ──────────────────────────────────────────
384590
+ playbookLint: async (params) => requireObs(deps).playbooks.lint(params.def),
384591
+ playbookHistory: async (params) => requireObs(deps).playbooks.versioning.history(params.playbookId),
384592
+ playbookSave: async (params) => requireObs(deps).playbooks.versioning.save(params.playbookId, params.def, params.comment),
384593
+ playbookRollback: async (params) => requireObs(deps).playbooks.versioning.rollback(params.playbookId, params.version, params.comment),
384594
+ playbookDiff: async (params) => requireObs(deps).playbooks.versioning.diff(params.playbookId, params.a, params.b),
384595
+ // ── cloud inventory ─────────────────────────────────────────────────────
384596
+ cloudSummary: async () => requireObs(deps).cloud.summary(),
384597
+ cloudQuery: async (params) => requireObs(deps).cloud.query(params),
384598
+ cloudSync: async () => requireObs(deps).cloud.sync(),
384599
+ cloudAddAccount: async (params) => {
384600
+ requireObs(deps).cloud.addAccount(params);
384601
+ return { ok: true };
384602
+ },
384603
+ // ── live dashboard hub ──────────────────────────────────────────────────
384604
+ liveDashboardState: async () => requireObs(deps).liveDashboard.lastState() ?? await requireObs(deps).dashboard.state(),
384605
+ liveDashboardSubscriberCount: async () => ({ count: requireObs(deps).liveDashboard.subscriberCount() })
384606
+ };
384607
+ }
384608
+
383989
384609
  // packages/backend/src/services/ResourceMonitorService.ts
383990
384610
  var import_os2 = __toESM(require("os"), 1);
383991
384611
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
@@ -385995,6 +386615,7 @@ async function startGyBackend() {
385995
386615
  }
385996
386616
  });
385997
386617
  console.log(`[gybackend] Observability wired: dashboard state available (hosts=${observability.metricsLedger.hosts().length})`);
386618
+ agentService.setObservability(observability);
385998
386619
  if (settingsService.getSettings().sessionLogging?.enabled) {
385999
386620
  const logDir = import_node_path28.default.join(
386000
386621
  import_node_process2.default.env.GYSHELL_STORE_DIR || "",
@@ -386434,7 +387055,13 @@ async function startGyBackend() {
386434
387055
  gatewayService.broadcastRaw("tools:builtInUpdated", summary);
386435
387056
  return summary;
386436
387057
  }
386437
- }
387058
+ },
387059
+ // Observability bridge (v2.9.x): exposes the 9 platform capabilities
387060
+ // (metrics export, secrets, on-call, cost, recording, gitops, playbooks,
387061
+ // cloud, live dashboard) as observability:* RPC methods.
387062
+ observabilityBridge: createObservabilityBridge({
387063
+ observability: () => observability
387064
+ })
386438
387065
  })
386439
387066
  });
386440
387067
  await wsGatewayControlService.applyPolicy(startupPolicy);