@dudousxd/nestjs-agent-dashboard 0.20.0 → 0.22.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.
@@ -35,15 +35,22 @@ __export(index_exports, {
35
35
  AGENT_ACTOR_DIRECTORY: () => AGENT_ACTOR_DIRECTORY,
36
36
  AGENT_ACTOR_RESOLVER: () => AGENT_ACTOR_RESOLVER,
37
37
  AGENT_APPROVAL_PORT: () => AGENT_APPROVAL_PORT,
38
+ AGENT_CONSOLE_ID: () => AGENT_CONSOLE_ID,
39
+ AGENT_DASHBOARD_CONFIG_ID: () => AGENT_DASHBOARD_CONFIG_ID,
38
40
  AGENT_GOVERNANCE_QUERIES: () => AGENT_GOVERNANCE_QUERIES,
39
41
  AGENT_PRICING_STORE: () => AGENT_PRICING_STORE,
42
+ AVIARY_CONSOLES_SLOT: () => AVIARY_CONSOLES_SLOT,
40
43
  AgentApiController: () => AgentApiController,
41
44
  AgentApiModule: () => AgentApiModule,
45
+ AgentConsoleRegistration: () => AgentConsoleRegistration,
46
+ AgentConsolesController: () => AgentConsolesController,
42
47
  AgentDashboardModule: () => AgentDashboardModule,
48
+ AgentDevToolsRegistration: () => AgentDevToolsRegistration,
43
49
  AgentUiController: () => AgentUiController,
44
50
  CONSOLE_AUTHORIZE_MISSING_WARNING: () => CONSOLE_AUTHORIZE_MISSING_WARNING,
45
51
  CONSOLE_GATE: () => CONSOLE_GATE,
46
52
  CONSOLE_PAGE_METADATA: () => CONSOLE_PAGE_METADATA,
53
+ CONSOLE_PROBE_TIMEOUT_MS: () => CONSOLE_PROBE_TIMEOUT_MS,
47
54
  ConsoleAccessDenied: () => ConsoleAccessDenied,
48
55
  ConsoleAuthorizeFilter: () => ConsoleAuthorizeFilter,
49
56
  ConsoleAuthorizeGuard: () => ConsoleAuthorizeGuard,
@@ -52,13 +59,18 @@ __export(index_exports, {
52
59
  DASHBOARD_APPROVAL_ACTOR_REF: () => DASHBOARD_APPROVAL_ACTOR_REF,
53
60
  DASHBOARD_BASE_PATH: () => DASHBOARD_BASE_PATH,
54
61
  DASHBOARD_CONSOLE_OPTIONS: () => DASHBOARD_CONSOLE_OPTIONS,
62
+ DASHBOARD_DEV_TOOLS: () => DASHBOARD_DEV_TOOLS,
55
63
  DashboardConsoleAccess: () => DashboardConsoleAccess,
56
64
  DashboardService: () => DashboardService,
57
65
  UseConsoleAuthorize: () => UseConsoleAuthorize,
58
66
  agentDashboardMountPaths: () => agentDashboardMountPaths,
67
+ agentDevTools: () => agentDevTools,
68
+ anyAuthorize: () => anyAuthorize,
59
69
  authorizeByToken: () => authorizeByToken,
70
+ listVisibleConsoles: () => listVisibleConsoles,
60
71
  normalizeConsoleResult: () => normalizeConsoleResult,
61
72
  parsePriceInput: () => parsePriceInput,
73
+ registerAviaryConsole: () => registerAviaryConsole,
62
74
  resolveConsoleAuthorize: () => resolveConsoleAuthorize
63
75
  });
64
76
  module.exports = __toCommonJS(index_exports);
@@ -145,6 +157,7 @@ var DASHBOARD_BASE_PATH = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-das
145
157
  var DASHBOARD_API_PATH = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:api-path");
146
158
  var DASHBOARD_APPROVAL_ACTOR_REF = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:approval-actor-ref");
147
159
  var DASHBOARD_CONSOLE_OPTIONS = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:console-options");
160
+ var DASHBOARD_DEV_TOOLS = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:dev-tools");
148
161
 
149
162
  // src/server/dashboard.service.ts
150
163
  function _ts_decorate(decorators, target, key, desc) {
@@ -223,8 +236,8 @@ var DashboardService = class {
223
236
  };
224
237
  }
225
238
  /** Top threads by cost for a day range (default 10, highest cost first). */
226
- async topThreads(range, limit = 10) {
227
- const rows = await this.queries.spendByThread(range, limit);
239
+ async topThreads(range, limit2 = 10) {
240
+ const rows = await this.queries.spendByThread(range, limit2);
228
241
  return this.withActorLabels(rows);
229
242
  }
230
243
  /** Run reliability for a day range: metrics, by-agent/by-error breakdowns and the trend, in parallel. */
@@ -243,12 +256,12 @@ var DashboardService = class {
243
256
  };
244
257
  }
245
258
  /** Most recent runs (status/agent/duration/error) for the Reliability recent-runs table. */
246
- recentRuns(limit) {
247
- return this.queries.recentRuns(limit);
259
+ recentRuns(limit2) {
260
+ return this.queries.recentRuns(limit2);
248
261
  }
249
262
  /** Most recent tool calls (status/type/thread) for the Runs & tools activity feed. */
250
- recentToolCalls(limit) {
251
- return this.queries.recentToolCalls(limit);
263
+ recentToolCalls(limit2) {
264
+ return this.queries.recentToolCalls(limit2);
252
265
  }
253
266
  /** Paged, filterable tool calls for the Runs & tools activity table. */
254
267
  toolCallsPage(query) {
@@ -263,8 +276,8 @@ var DashboardService = class {
263
276
  * Capped and totalless — kept because the SPA still calls `GET approvals`; new callers want
264
277
  * {@link approvalsPage}, which reports how much of the backlog the cap hid.
265
278
  */
266
- pendingApprovals(limit) {
267
- return this.queries.pendingApprovals(limit);
279
+ pendingApprovals(limit2) {
280
+ return this.queries.pendingApprovals(limit2);
268
281
  }
269
282
  /** Paged, filterable approvals inbox with a total — the backlog-safe read of the HITL queue. */
270
283
  approvalsPage(query) {
@@ -352,8 +365,8 @@ var DashboardService = class {
352
365
  });
353
366
  }
354
367
  /** Most recent threads with rolled-up message/token counts. */
355
- async recentThreads(limit) {
356
- const rows = await this.queries.recentThreads(limit);
368
+ async recentThreads(limit2) {
369
+ const rows = await this.queries.recentThreads(limit2);
357
370
  return this.withActorLabels(rows);
358
371
  }
359
372
  /**
@@ -361,10 +374,10 @@ var DashboardService = class {
361
374
  * {@link recentThreads} is.
362
375
  */
363
376
  async threadsPage(query) {
364
- const page = await this.queries.threadsPage(query);
365
- const rows = await this.withActorLabels(page.rows);
377
+ const page2 = await this.queries.threadsPage(query);
378
+ const rows = await this.withActorLabels(page2.rows);
366
379
  return {
367
- ...page,
380
+ ...page2,
368
381
  rows
369
382
  };
370
383
  }
@@ -685,27 +698,27 @@ var AgentApiController = class {
685
698
  return this.dashboard.spend(resolveRange(from, to));
686
699
  }
687
700
  /** Top threads by cost (default 10, max 200) for a day range (defaults to the last 30 days). */
688
- topThreads(from, to, limit) {
689
- return this.dashboard.topThreads(resolveRange(from, to), parseLimit(limit, 10));
701
+ topThreads(from, to, limit2) {
702
+ return this.dashboard.topThreads(resolveRange(from, to), parseLimit(limit2, 10));
690
703
  }
691
704
  /** `{ metrics, byAgent, errors, trend }` for a day range (defaults to the last 30 days). */
692
705
  reliability(from, to) {
693
706
  return this.dashboard.reliability(resolveRange(from, to));
694
707
  }
695
708
  /** Most recent runs (default 50, max 200) for the Reliability recent-runs table. */
696
- runs(limit) {
697
- return this.dashboard.recentRuns(parseLimit(limit, 50));
709
+ runs(limit2) {
710
+ return this.dashboard.recentRuns(parseLimit(limit2, 50));
698
711
  }
699
712
  /**
700
713
  * Paged, filterable runs for the Reliability recent-runs table. `page` (default 1), `limit`
701
714
  * (default 25, max 200), and `where[agentName]`/`where[status]`/`where[errorCode]`/
702
715
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
703
716
  */
704
- runsPage(page, limit, where) {
705
- const parsedWhere = parseRunWhere(where);
717
+ runsPage(page2, limit2, where2) {
718
+ const parsedWhere = parseRunWhere(where2);
706
719
  return this.dashboard.runsPage({
707
- page: parsePageNumber(page),
708
- pageSize: parseLimit(limit, 25),
720
+ page: parsePageNumber(page2),
721
+ pageSize: parseLimit(limit2, 25),
709
722
  ...parsedWhere !== void 0 ? {
710
723
  where: parsedWhere
711
724
  } : {}
@@ -722,19 +735,19 @@ var AgentApiController = class {
722
735
  return this.dashboard.runDetail(runId);
723
736
  }
724
737
  /** Most recent tool calls (default 50, max 200) for the activity feed. */
725
- toolCalls(limit) {
726
- return this.dashboard.recentToolCalls(parseLimit(limit, 50));
738
+ toolCalls(limit2) {
739
+ return this.dashboard.recentToolCalls(parseLimit(limit2, 50));
727
740
  }
728
741
  /**
729
742
  * Paged, filterable tool calls for the Runs & tools activity table. `page` (default 1), `limit`
730
743
  * (default 25, max 200), and `where[toolName]`/`where[toolType]`/`where[status]`/`where[threadId]`/
731
744
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
732
745
  */
733
- toolCallsPage(page, limit, where) {
734
- const parsedWhere = parseToolCallWhere(where);
746
+ toolCallsPage(page2, limit2, where2) {
747
+ const parsedWhere = parseToolCallWhere(where2);
735
748
  return this.dashboard.toolCallsPage({
736
- page: parsePageNumber(page),
737
- pageSize: parseLimit(limit, 25),
749
+ page: parsePageNumber(page2),
750
+ pageSize: parseLimit(limit2, 25),
738
751
  ...parsedWhere !== void 0 ? {
739
752
  where: parsedWhere
740
753
  } : {}
@@ -746,8 +759,8 @@ var AgentApiController = class {
746
759
  * Capped with NO total, so a backlog past `limit` is invisible from the response alone. Kept
747
760
  * because the SPA still calls it; anything new should call `approvals-page` instead.
748
761
  */
749
- approvals(limit) {
750
- return this.dashboard.pendingApprovals(parseLimit(limit, 50));
762
+ approvals(limit2) {
763
+ return this.dashboard.pendingApprovals(parseLimit(limit2, 50));
751
764
  }
752
765
  /**
753
766
  * Paged, filterable approvals inbox, oldest first. `page` (default 1), `limit` (default 25, max
@@ -757,11 +770,11 @@ var AgentApiController = class {
757
770
  * Unlike `GET approvals` this reports `total`, so the console can say "showing N of M" instead of
758
771
  * silently hiding pending decisions behind a row cap.
759
772
  */
760
- approvalsPage(page, limit, where) {
761
- const parsedWhere = parseApprovalWhere(where);
773
+ approvalsPage(page2, limit2, where2) {
774
+ const parsedWhere = parseApprovalWhere(where2);
762
775
  return this.dashboard.approvalsPage({
763
- page: parsePageNumber(page),
764
- pageSize: parseLimit(limit, 25),
776
+ page: parsePageNumber(page2),
777
+ pageSize: parseLimit(limit2, 25),
765
778
  ...parsedWhere !== void 0 ? {
766
779
  where: parsedWhere
767
780
  } : {}
@@ -808,19 +821,19 @@ var AgentApiController = class {
808
821
  return this.dashboard.genuiStats(resolveRange(from, to));
809
822
  }
810
823
  /** Most recent threads (default 50, max 200) with rolled-up counts. */
811
- threads(limit) {
812
- return this.dashboard.recentThreads(parseLimit(limit, 50));
824
+ threads(limit2) {
825
+ return this.dashboard.recentThreads(parseLimit(limit2, 50));
813
826
  }
814
827
  /**
815
828
  * Paged, filterable threads for the Runs & tools threads table. `page` (default 1), `limit`
816
829
  * (default 25, max 200), and `where[actorRef]`/`where[title]` (case-insensitive substring)/
817
830
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
818
831
  */
819
- threadsPage(page, limit, where) {
820
- const parsedWhere = parseThreadWhere(where);
832
+ threadsPage(page2, limit2, where2) {
833
+ const parsedWhere = parseThreadWhere(where2);
821
834
  return this.dashboard.threadsPage({
822
- page: parsePageNumber(page),
823
- pageSize: parseLimit(limit, 25),
835
+ page: parsePageNumber(page2),
836
+ pageSize: parseLimit(limit2, 25),
824
837
  ...parsedWhere !== void 0 ? {
825
838
  where: parsedWhere
826
839
  } : {}
@@ -1104,33 +1117,37 @@ function agentDashboardMountPaths(options) {
1104
1117
  __name(agentDashboardMountPaths, "agentDashboardMountPaths");
1105
1118
 
1106
1119
  // src/server/agent-dashboard.module.ts
1107
- var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
1120
+ var import_nestjs_agent_core4 = require("@dudousxd/nestjs-agent-core");
1108
1121
  var import_reflect_metadata = require("reflect-metadata");
1109
- var import_common9 = require("@nestjs/common");
1110
- var import_core2 = require("@nestjs/core");
1122
+ var import_common11 = require("@nestjs/common");
1123
+ var import_core3 = require("@nestjs/core");
1111
1124
 
1112
1125
  // src/server/agent-ui.controller.ts
1113
1126
  var import_node_fs = require("fs");
1114
1127
  var import_node_path = require("path");
1115
1128
  var import_node_url = require("url");
1116
- var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
1117
- var import_common8 = require("@nestjs/common");
1129
+ var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
1130
+ var import_common9 = require("@nestjs/common");
1118
1131
 
1119
1132
  // src/server/console-authorize.guard.ts
1120
1133
  var import_common7 = require("@nestjs/common");
1121
- var import_core = require("@nestjs/core");
1134
+ var import_core2 = require("@nestjs/core");
1122
1135
 
1123
1136
  // src/server/console-authorize.ts
1124
1137
  var import_node_crypto = require("crypto");
1125
1138
  var import_common6 = require("@nestjs/common");
1139
+ var import_core = require("@nestjs/core");
1126
1140
  var CONSOLE_GATE = /* @__PURE__ */ Symbol.for("@dudousxd/aviary:console-gate");
1127
1141
  var PACKAGE = "@dudousxd/nestjs-agent-dashboard";
1128
1142
  var MODULE = "AgentDashboardModule";
1129
1143
  var logger = new import_common6.Logger(MODULE);
1130
1144
  var CONSOLE_AUTHORIZE_MISSING_WARNING = `[${PACKAGE}] console has no \`authorize\` configured: it is open outside production and denies every request in production. Set \`authorize\` in ${MODULE}.forRoot().`;
1131
- var allow = /* @__PURE__ */ __name(() => ({
1145
+ var allow = /* @__PURE__ */ __name((caller) => caller !== void 0 && caller !== "" ? {
1146
+ allowed: true,
1147
+ caller
1148
+ } : {
1132
1149
  allowed: true
1133
- }), "allow");
1150
+ }, "allow");
1134
1151
  var forbidden = /* @__PURE__ */ __name(() => ({
1135
1152
  allowed: false,
1136
1153
  reason: "forbidden"
@@ -1154,7 +1171,9 @@ function normalizeConsoleResult(result) {
1154
1171
  redirectTo: value.redirectTo
1155
1172
  };
1156
1173
  }
1157
- if (value.allowed === true) return allow();
1174
+ if (value.allowed === true) {
1175
+ return allow(typeof value.caller === "string" ? value.caller : void 0);
1176
+ }
1158
1177
  return value.reason === "unauthenticated" ? unauthenticated() : forbidden();
1159
1178
  }
1160
1179
  __name(normalizeConsoleResult, "normalizeConsoleResult");
@@ -1230,7 +1249,7 @@ async function resolveConsoleAuthorize(authorize, moduleRef, options = {}) {
1230
1249
  if (authorize === void 0) {
1231
1250
  if (options.warnIfMissing !== false) log.warn(CONSOLE_AUTHORIZE_MISSING_WARNING);
1232
1251
  const production = isProduction();
1233
- return async () => production ? forbidden() : allow();
1252
+ return async () => production ? forbidden() : allow("dev-open");
1234
1253
  }
1235
1254
  const instanceOf = classInstances(moduleRef);
1236
1255
  let decide;
@@ -1280,12 +1299,18 @@ function authorizeByToken(options) {
1280
1299
  throw new Error("authorizeByToken: `token` is empty; set it (e.g. from an env var).");
1281
1300
  }
1282
1301
  const expected = sha256(token);
1302
+ const caller = `token:${expected.toString("hex").slice(0, 12)}`;
1283
1303
  return (context) => {
1284
1304
  const req = context.switchToHttp().getRequest();
1285
1305
  const header = req?.headers?.authorization;
1286
1306
  const value = Array.isArray(header) ? header[0] : header;
1287
1307
  const match = typeof value === "string" ? /^Bearer\s+(.+)$/i.exec(value.trim()) : null;
1288
- if (match?.[1] !== void 0 && (0, import_node_crypto.timingSafeEqual)(sha256(match[1]), expected)) return true;
1308
+ if (match?.[1] !== void 0 && (0, import_node_crypto.timingSafeEqual)(sha256(match[1]), expected)) {
1309
+ return {
1310
+ allowed: true,
1311
+ caller
1312
+ };
1313
+ }
1289
1314
  return {
1290
1315
  allowed: false,
1291
1316
  reason: "unauthenticated"
@@ -1293,6 +1318,48 @@ function authorizeByToken(options) {
1293
1318
  };
1294
1319
  }
1295
1320
  __name(authorizeByToken, "authorizeByToken");
1321
+ function anyAuthorize(...forms) {
1322
+ if (forms.length === 0) throw new Error("anyAuthorize: pass at least one authorize form.");
1323
+ let AnyConsoleAuthorizer = class AnyConsoleAuthorizer {
1324
+ static {
1325
+ __name(this, "AnyConsoleAuthorizer");
1326
+ }
1327
+ moduleRef;
1328
+ #decides;
1329
+ constructor(moduleRef) {
1330
+ this.moduleRef = moduleRef;
1331
+ }
1332
+ async authorize(context) {
1333
+ this.#decides ??= Promise.all(forms.map((form) => resolveConsoleAuthorize(form, this.moduleRef, {
1334
+ warnIfMissing: false
1335
+ })));
1336
+ this.#decides.catch(() => {
1337
+ this.#decides = void 0;
1338
+ });
1339
+ let unauthenticated2;
1340
+ for (const decide of await this.#decides) {
1341
+ const decision = await decide(context);
1342
+ if (decision.allowed) return decision;
1343
+ if (decision.reason === "unauthenticated") unauthenticated2 ??= decision;
1344
+ }
1345
+ if (unauthenticated2 === void 0) return {
1346
+ allowed: false,
1347
+ reason: "forbidden"
1348
+ };
1349
+ return "redirectTo" in unauthenticated2 && unauthenticated2.redirectTo !== void 0 ? {
1350
+ redirectTo: unauthenticated2.redirectTo
1351
+ } : {
1352
+ allowed: false,
1353
+ reason: "unauthenticated"
1354
+ };
1355
+ }
1356
+ };
1357
+ Reflect.defineMetadata("design:paramtypes", [
1358
+ import_core.ModuleRef
1359
+ ], AnyConsoleAuthorizer);
1360
+ return AnyConsoleAuthorizer;
1361
+ }
1362
+ __name(anyAuthorize, "anyAuthorize");
1296
1363
 
1297
1364
  // src/server/console-authorize.guard.ts
1298
1365
  function _ts_decorate3(decorators, target, key, desc) {
@@ -1350,7 +1417,7 @@ DashboardConsoleAccess = _ts_decorate3([
1350
1417
  _ts_metadata3("design:type", Function),
1351
1418
  _ts_metadata3("design:paramtypes", [
1352
1419
  typeof DashboardConsoleOptions === "undefined" ? Object : DashboardConsoleOptions,
1353
- typeof import_core.ModuleRef === "undefined" ? Object : import_core.ModuleRef
1420
+ typeof import_core2.ModuleRef === "undefined" ? Object : import_core2.ModuleRef
1354
1421
  ])
1355
1422
  ], DashboardConsoleAccess);
1356
1423
  var CONSOLE_PAGE_METADATA = "@dudousxd/nestjs-agent-dashboard:console-page";
@@ -1361,7 +1428,7 @@ var ConsoleAccessDenied = class extends import_common7.HttpException {
1361
1428
  }
1362
1429
  decision;
1363
1430
  page;
1364
- constructor(decision, page) {
1431
+ constructor(decision, page2) {
1365
1432
  super(decision.reason === "forbidden" ? {
1366
1433
  error: "forbidden"
1367
1434
  } : {
@@ -1369,13 +1436,13 @@ var ConsoleAccessDenied = class extends import_common7.HttpException {
1369
1436
  ...decision.redirectTo !== void 0 ? {
1370
1437
  redirectTo: decision.redirectTo
1371
1438
  } : {}
1372
- }, decision.reason === "forbidden" ? 403 : 401), this.decision = decision, this.page = page;
1439
+ }, decision.reason === "forbidden" ? 403 : 401), this.decision = decision, this.page = page2;
1373
1440
  }
1374
1441
  };
1375
1442
  function isPageNavigation(context) {
1376
1443
  if (context.getType() !== "http") return false;
1377
- const page = Reflect.getMetadata(CONSOLE_PAGE_METADATA, context.getHandler()) === true || Reflect.getMetadata(CONSOLE_PAGE_METADATA, context.getClass()) === true;
1378
- if (!page) return false;
1444
+ const page2 = Reflect.getMetadata(CONSOLE_PAGE_METADATA, context.getHandler()) === true || Reflect.getMetadata(CONSOLE_PAGE_METADATA, context.getClass()) === true;
1445
+ if (!page2) return false;
1379
1446
  const req = context.switchToHttp().getRequest();
1380
1447
  if ((req.method ?? "GET").toUpperCase() !== "GET") return false;
1381
1448
  const accept = req.headers?.accept;
@@ -1422,12 +1489,12 @@ var ConsoleAuthorizeFilter = class {
1422
1489
  catch(exception, host) {
1423
1490
  const adapter = this.adapterHost.httpAdapter;
1424
1491
  const res = host.switchToHttp().getResponse();
1425
- const { decision, page } = exception;
1426
- if (page && decision.reason === "unauthenticated" && decision.redirectTo !== void 0) {
1492
+ const { decision, page: page2 } = exception;
1493
+ if (page2 && decision.reason === "unauthenticated" && decision.redirectTo !== void 0) {
1427
1494
  adapter.redirect(res, 302, decision.redirectTo);
1428
1495
  return;
1429
1496
  }
1430
- if (page) {
1497
+ if (page2) {
1431
1498
  const forbidden2 = decision.reason === "forbidden";
1432
1499
  adapter.setHeader(res, "Content-Type", "text/html; charset=utf-8");
1433
1500
  adapter.reply(res, forbidden2 ? FORBIDDEN_PAGE : UNAUTHENTICATED_PAGE, forbidden2 ? 403 : 401);
@@ -1441,7 +1508,7 @@ ConsoleAuthorizeFilter = _ts_decorate3([
1441
1508
  (0, import_common7.Injectable)(),
1442
1509
  _ts_metadata3("design:type", Function),
1443
1510
  _ts_metadata3("design:paramtypes", [
1444
- typeof import_core.HttpAdapterHost === "undefined" ? Object : import_core.HttpAdapterHost
1511
+ typeof import_core2.HttpAdapterHost === "undefined" ? Object : import_core2.HttpAdapterHost
1445
1512
  ])
1446
1513
  ], ConsoleAuthorizeFilter);
1447
1514
  function UseConsoleAuthorize() {
@@ -1449,7 +1516,9 @@ function UseConsoleAuthorize() {
1449
1516
  }
1450
1517
  __name(UseConsoleAuthorize, "UseConsoleAuthorize");
1451
1518
 
1452
- // src/server/agent-ui.controller.ts
1519
+ // src/server/console-switcher.ts
1520
+ var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
1521
+ var import_common8 = require("@nestjs/common");
1453
1522
  function _ts_decorate4(decorators, target, key, desc) {
1454
1523
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1455
1524
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1476,7 +1545,186 @@ function _ts_param4(paramIndex, decorator) {
1476
1545
  };
1477
1546
  }
1478
1547
  __name(_ts_param4, "_ts_param");
1548
+ var AVIARY_CONSOLES_SLOT = /* @__PURE__ */ Symbol.for("@dudousxd/aviary:consoles");
1549
+ var ID = /^[a-z][a-z0-9-]*$/;
1550
+ var ICONS = /* @__PURE__ */ new Set([
1551
+ "workflow",
1552
+ "telescope",
1553
+ "media",
1554
+ "payments",
1555
+ "agent",
1556
+ "identity",
1557
+ "generic"
1558
+ ]);
1559
+ var CONSOLE_PROBE_TIMEOUT_MS = 300;
1560
+ function isSameOriginPath(path) {
1561
+ return typeof path === "string" && path.startsWith("/") && !path.startsWith("//");
1562
+ }
1563
+ __name(isSameOriginPath, "isSameOriginPath");
1564
+ function readAviaryConsoles() {
1565
+ const value = globalThis[AVIARY_CONSOLES_SLOT];
1566
+ if (value?.version !== 1 || !Array.isArray(value.entries)) return void 0;
1567
+ return value;
1568
+ }
1569
+ __name(readAviaryConsoles, "readAviaryConsoles");
1570
+ function registerAviaryConsole(entry, logger4) {
1571
+ if (!ID.test(entry.id)) throw new Error(`console id ${JSON.stringify(entry.id)} is invalid`);
1572
+ if (!isSameOriginPath(entry.path)) {
1573
+ throw new Error(`console path ${JSON.stringify(entry.path)} must start with a single "/"`);
1574
+ }
1575
+ const holder = globalThis;
1576
+ if (holder[AVIARY_CONSOLES_SLOT] === void 0) {
1577
+ const fresh = {
1578
+ version: 1,
1579
+ entries: []
1580
+ };
1581
+ holder[AVIARY_CONSOLES_SLOT] = fresh;
1582
+ }
1583
+ const registry = readAviaryConsoles();
1584
+ if (registry === void 0) return void 0;
1585
+ if (registry.entries.some((existing) => existing.id === entry.id)) {
1586
+ logger4?.warn(`console id "${entry.id}" is already registered`);
1587
+ return void 0;
1588
+ }
1589
+ registry.entries.push(entry);
1590
+ return () => {
1591
+ const index = registry.entries.indexOf(entry);
1592
+ if (index !== -1) registry.entries.splice(index, 1);
1593
+ };
1594
+ }
1595
+ __name(registerAviaryConsole, "registerAviaryConsole");
1596
+ function consoleSwitcherConfig(selfId, endpoint) {
1597
+ const registry = readAviaryConsoles();
1598
+ if (!registry?.entries.some((entry) => entry.id === selfId)) return void 0;
1599
+ const others = registry.entries.filter((entry) => entry.id !== selfId).length;
1600
+ return others > 0 ? {
1601
+ endpoint,
1602
+ others
1603
+ } : void 0;
1604
+ }
1605
+ __name(consoleSwitcherConfig, "consoleSwitcherConfig");
1606
+ async function allows(entry, context, ms) {
1607
+ let timer;
1608
+ const timeout = new Promise((resolve2) => {
1609
+ timer = setTimeout(() => resolve2(false), ms);
1610
+ });
1611
+ try {
1612
+ return await Promise.race([
1613
+ Promise.resolve().then(() => entry.authorize(context)).then((decision) => decision?.allowed === true, () => false),
1614
+ timeout
1615
+ ]);
1616
+ } finally {
1617
+ clearTimeout(timer);
1618
+ }
1619
+ }
1620
+ __name(allows, "allows");
1621
+ async function listVisibleConsoles(registry, selfId, context, timeoutMs = CONSOLE_PROBE_TIMEOUT_MS) {
1622
+ const others = (registry?.entries ?? []).filter((entry) => entry.id !== selfId && isSameOriginPath(entry.path)).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
1623
+ const verdicts = await Promise.all(others.map((entry) => allows(entry, context, timeoutMs)));
1624
+ return {
1625
+ version: 1,
1626
+ current: selfId,
1627
+ consoles: others.filter((_, index) => verdicts[index]).map((entry) => ({
1628
+ id: entry.id,
1629
+ title: entry.title,
1630
+ icon: ICONS.has(entry.icon) ? entry.icon : "generic",
1631
+ href: entry.path
1632
+ }))
1633
+ };
1634
+ }
1635
+ __name(listVisibleConsoles, "listVisibleConsoles");
1636
+ var AGENT_CONSOLE_ID = "agent";
1637
+ var logger2 = new import_common8.Logger("AgentDashboardModule");
1638
+ var AgentConsoleRegistration = class {
1639
+ static {
1640
+ __name(this, "AgentConsoleRegistration");
1641
+ }
1642
+ basePath;
1643
+ access;
1644
+ #unregister;
1645
+ constructor(basePath, access) {
1646
+ this.basePath = basePath;
1647
+ this.access = access;
1648
+ }
1649
+ onModuleInit() {
1650
+ this.#unregister = registerAviaryConsole({
1651
+ id: AGENT_CONSOLE_ID,
1652
+ title: "Agents",
1653
+ icon: "agent",
1654
+ order: 30,
1655
+ path: this.basePath === "" ? "/" : this.basePath,
1656
+ authorize: /* @__PURE__ */ __name((context) => this.access.check(context), "authorize")
1657
+ }, logger2);
1658
+ }
1659
+ onModuleDestroy() {
1660
+ this.#unregister?.();
1661
+ this.#unregister = void 0;
1662
+ }
1663
+ };
1664
+ AgentConsoleRegistration = _ts_decorate4([
1665
+ (0, import_common8.Injectable)(),
1666
+ _ts_param4(0, (0, import_common8.Inject)(DASHBOARD_BASE_PATH)),
1667
+ _ts_metadata4("design:type", Function),
1668
+ _ts_metadata4("design:paramtypes", [
1669
+ String,
1670
+ typeof DashboardConsoleAccess === "undefined" ? Object : DashboardConsoleAccess
1671
+ ])
1672
+ ], AgentConsoleRegistration);
1673
+ var CurrentExecutionContext = (0, import_common8.createParamDecorator)((_data, context) => ({
1674
+ context
1675
+ }));
1676
+ var AgentConsolesController = class {
1677
+ static {
1678
+ __name(this, "AgentConsolesController");
1679
+ }
1680
+ consoles(current) {
1681
+ return listVisibleConsoles(readAviaryConsoles(), AGENT_CONSOLE_ID, current.context);
1682
+ }
1683
+ };
1684
+ _ts_decorate4([
1685
+ (0, import_common8.Get)("consoles"),
1686
+ (0, import_common8.Header)("Cache-Control", "private, no-store"),
1687
+ _ts_param4(0, CurrentExecutionContext()),
1688
+ _ts_metadata4("design:type", Function),
1689
+ _ts_metadata4("design:paramtypes", [
1690
+ typeof CurrentContext === "undefined" ? Object : CurrentContext
1691
+ ]),
1692
+ _ts_metadata4("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1693
+ ], AgentConsolesController.prototype, "consoles", null);
1694
+ AgentConsolesController = _ts_decorate4([
1695
+ (0, import_nestjs_agent_core2.CanAnyone)(),
1696
+ (0, import_common8.Controller)()
1697
+ ], AgentConsolesController);
1698
+
1699
+ // src/server/agent-ui.controller.ts
1700
+ function _ts_decorate5(decorators, target, key, desc) {
1701
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1702
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1703
+ r = Reflect.decorate(decorators, target, key, desc);
1704
+ } else {
1705
+ for (var i = decorators.length - 1; i >= 0; i--) {
1706
+ if (d = decorators[i]) {
1707
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1708
+ }
1709
+ }
1710
+ }
1711
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1712
+ }
1713
+ __name(_ts_decorate5, "_ts_decorate");
1714
+ function _ts_metadata5(metadataKey, metadataValue) {
1715
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1716
+ return Reflect.metadata(metadataKey, metadataValue);
1717
+ }
1718
+ }
1719
+ __name(_ts_metadata5, "_ts_metadata");
1720
+ function _ts_param5(paramIndex, decorator) {
1721
+ return function(target, key) {
1722
+ decorator(target, key, paramIndex);
1723
+ };
1724
+ }
1725
+ __name(_ts_param5, "_ts_param");
1479
1726
  var BUILD_BASE = "/ai-gateway";
1727
+ var AGENT_DASHBOARD_CONFIG_ID = "agent-dashboard-config";
1480
1728
  function spaDir() {
1481
1729
  return (0, import_node_url.fileURLToPath)(new URL("../spa", __importMetaUrl));
1482
1730
  }
@@ -1511,66 +1759,486 @@ var AgentUiController = class {
1511
1759
  }
1512
1760
  const indexPath = (0, import_node_path.join)(this.dir, "index.html");
1513
1761
  if (!(0, import_node_fs.existsSync)(indexPath)) {
1514
- throw new import_common8.NotFoundException("Dashboard is not built. Run the package build.");
1762
+ throw new import_common9.NotFoundException("Dashboard is not built. Run the package build.");
1515
1763
  }
1516
1764
  const html = (0, import_node_fs.readFileSync)(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
1517
- const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;
1765
+ const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>${this.configBlock()}`;
1518
1766
  return html.includes("</head>") ? html.replace("</head>", `${inject}</head>`) : inject + html;
1519
1767
  }
1768
+ /**
1769
+ * The page's JSON config block (`agent-dashboard-config`, CSP-safe: data, not script). It carries
1770
+ * `switcher` only when another Aviary console is registered.
1771
+ */
1772
+ configBlock() {
1773
+ const switcher = consoleSwitcherConfig(AGENT_CONSOLE_ID, `${this.apiBasePath}/consoles`);
1774
+ const json = JSON.stringify({
1775
+ apiBase: this.apiBasePath,
1776
+ ...switcher !== void 0 ? {
1777
+ switcher
1778
+ } : {}
1779
+ }).replaceAll("<", "\\u003c");
1780
+ return `<script type="application/json" id="${AGENT_DASHBOARD_CONFIG_ID}">${json}</script>`;
1781
+ }
1520
1782
  asset(file) {
1521
1783
  const safe = (0, import_node_path.basename)(file);
1522
- if (safe !== file) throw new import_common8.NotFoundException();
1784
+ if (safe !== file) throw new import_common9.NotFoundException();
1523
1785
  const root = (0, import_node_path.resolve)(this.dir, "assets");
1524
1786
  const assetPath = (0, import_node_path.resolve)(root, safe);
1525
1787
  if (!assetPath.startsWith(root + import_node_path.sep) || !(0, import_node_fs.existsSync)(assetPath)) {
1526
- throw new import_common8.NotFoundException();
1788
+ throw new import_common9.NotFoundException();
1527
1789
  }
1528
1790
  const type = CONTENT_TYPES[(0, import_node_path.extname)(safe)] ?? "application/octet-stream";
1529
- return new import_common8.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1791
+ return new import_common9.StreamableFile((0, import_node_fs.readFileSync)(assetPath), {
1530
1792
  type
1531
1793
  });
1532
1794
  }
1533
1795
  };
1534
- _ts_decorate4([
1535
- (0, import_common8.Get)(),
1796
+ _ts_decorate5([
1797
+ (0, import_common9.Get)(),
1536
1798
  ConsolePage(),
1537
- (0, import_common8.Header)("Content-Type", "text/html; charset=utf-8"),
1538
- (0, import_common8.Header)("Cache-Control", "no-store, must-revalidate"),
1539
- _ts_param4(0, (0, import_common8.Req)()),
1540
- _ts_param4(1, (0, import_common8.Res)({
1799
+ (0, import_common9.Header)("Content-Type", "text/html; charset=utf-8"),
1800
+ (0, import_common9.Header)("Cache-Control", "no-store, must-revalidate"),
1801
+ _ts_param5(0, (0, import_common9.Req)()),
1802
+ _ts_param5(1, (0, import_common9.Res)({
1541
1803
  passthrough: true
1542
1804
  })),
1543
- _ts_metadata4("design:type", Function),
1544
- _ts_metadata4("design:paramtypes", [
1805
+ _ts_metadata5("design:type", Function),
1806
+ _ts_metadata5("design:paramtypes", [
1545
1807
  typeof UiPageRequest === "undefined" ? Object : UiPageRequest,
1546
1808
  typeof UiPageResponse === "undefined" ? Object : UiPageResponse
1547
1809
  ]),
1548
- _ts_metadata4("design:returntype", String)
1810
+ _ts_metadata5("design:returntype", String)
1549
1811
  ], AgentUiController.prototype, "index", null);
1550
- _ts_decorate4([
1551
- (0, import_common8.Get)("assets/:file"),
1552
- (0, import_common8.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1553
- _ts_param4(0, (0, import_common8.Param)("file")),
1554
- _ts_metadata4("design:type", Function),
1555
- _ts_metadata4("design:paramtypes", [
1812
+ _ts_decorate5([
1813
+ (0, import_common9.Get)("assets/:file"),
1814
+ (0, import_common9.Header)("Cache-Control", "public, max-age=31536000, immutable"),
1815
+ _ts_param5(0, (0, import_common9.Param)("file")),
1816
+ _ts_metadata5("design:type", Function),
1817
+ _ts_metadata5("design:paramtypes", [
1556
1818
  String
1557
1819
  ]),
1558
- _ts_metadata4("design:returntype", typeof import_common8.StreamableFile === "undefined" ? Object : import_common8.StreamableFile)
1820
+ _ts_metadata5("design:returntype", typeof import_common9.StreamableFile === "undefined" ? Object : import_common9.StreamableFile)
1559
1821
  ], AgentUiController.prototype, "asset", null);
1560
- AgentUiController = _ts_decorate4([
1561
- (0, import_nestjs_agent_core2.CanAnyone)(),
1562
- (0, import_common8.Controller)(),
1563
- _ts_param4(0, (0, import_common8.Inject)(DASHBOARD_BASE_PATH)),
1564
- _ts_param4(1, (0, import_common8.Inject)(DASHBOARD_API_PATH)),
1565
- _ts_metadata4("design:type", Function),
1566
- _ts_metadata4("design:paramtypes", [
1822
+ AgentUiController = _ts_decorate5([
1823
+ (0, import_nestjs_agent_core3.CanAnyone)(),
1824
+ (0, import_common9.Controller)(),
1825
+ _ts_param5(0, (0, import_common9.Inject)(DASHBOARD_BASE_PATH)),
1826
+ _ts_param5(1, (0, import_common9.Inject)(DASHBOARD_API_PATH)),
1827
+ _ts_metadata5("design:type", Function),
1828
+ _ts_metadata5("design:paramtypes", [
1567
1829
  String,
1568
1830
  String
1569
1831
  ])
1570
1832
  ], AgentUiController);
1571
1833
 
1834
+ // src/server/dev-tools.ts
1835
+ var import_common10 = require("@nestjs/common");
1836
+ function _ts_decorate6(decorators, target, key, desc) {
1837
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1838
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1839
+ r = Reflect.decorate(decorators, target, key, desc);
1840
+ } else {
1841
+ for (var i = decorators.length - 1; i >= 0; i--) {
1842
+ if (d = decorators[i]) {
1843
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1844
+ }
1845
+ }
1846
+ }
1847
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1848
+ }
1849
+ __name(_ts_decorate6, "_ts_decorate");
1850
+ function _ts_metadata6(metadataKey, metadataValue) {
1851
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
1852
+ return Reflect.metadata(metadataKey, metadataValue);
1853
+ }
1854
+ }
1855
+ __name(_ts_metadata6, "_ts_metadata");
1856
+ function _ts_param6(paramIndex, decorator) {
1857
+ return function(target, key) {
1858
+ decorator(target, key, paramIndex);
1859
+ };
1860
+ }
1861
+ __name(_ts_param6, "_ts_param");
1862
+ var DEV_TOOLS_SLOT = /* @__PURE__ */ Symbol.for("@dudousxd/aviary:dev-tools");
1863
+ function devToolsSlot() {
1864
+ const holder = globalThis;
1865
+ const existing = holder[DEV_TOOLS_SLOT];
1866
+ if (existing !== void 0) return existing;
1867
+ const libs = [];
1868
+ const slot = {
1869
+ version: 1,
1870
+ libs,
1871
+ register(lib) {
1872
+ if (libs.some((entry) => entry.lib === lib.lib)) {
1873
+ throw new Error(`dev tools: the lib "${lib.lib}" is already registered`);
1874
+ }
1875
+ libs.push(lib);
1876
+ return () => {
1877
+ const index = libs.indexOf(lib);
1878
+ if (index !== -1) libs.splice(index, 1);
1879
+ };
1880
+ }
1881
+ };
1882
+ holder[DEV_TOOLS_SLOT] = slot;
1883
+ return slot;
1884
+ }
1885
+ __name(devToolsSlot, "devToolsSlot");
1886
+ var DEFAULT_LIMIT = 20;
1887
+ var MAX_LIMIT = 100;
1888
+ var MESSAGE_LIMIT = 50;
1889
+ var MESSAGE_BYTES = 2 * 1024;
1890
+ var DAY_MS2 = 864e5;
1891
+ var ISO_DAY3 = /^\d{4}-\d{2}-\d{2}$/;
1892
+ var day = {
1893
+ type: "string",
1894
+ description: "UTC day, YYYY-MM-DD."
1895
+ };
1896
+ var page = {
1897
+ type: "integer",
1898
+ description: "Page, from 1. Pass the `next` of the previous page.",
1899
+ minimum: 1
1900
+ };
1901
+ var limit = {
1902
+ type: "integer",
1903
+ description: `Rows per page (default ${DEFAULT_LIMIT}, max ${MAX_LIMIT}).`,
1904
+ minimum: 1,
1905
+ maximum: MAX_LIMIT
1906
+ };
1907
+ var str = /* @__PURE__ */ __name((value) => typeof value === "string" && value !== "" ? value : void 0, "str");
1908
+ function dayOf(input, key) {
1909
+ const value = str(input[key]);
1910
+ if (value !== void 0 && !ISO_DAY3.test(value)) throw new Error(`"${key}" must be YYYY-MM-DD`);
1911
+ return value;
1912
+ }
1913
+ __name(dayOf, "dayOf");
1914
+ function rangeOf(input) {
1915
+ const utcDay2 = /* @__PURE__ */ __name((daysAgo) => new Date(Date.now() - daysAgo * DAY_MS2).toISOString().slice(0, 10), "utcDay");
1916
+ return {
1917
+ fromDay: dayOf(input, "from") ?? utcDay2(29),
1918
+ toDay: dayOf(input, "to") ?? utcDay2(0)
1919
+ };
1920
+ }
1921
+ __name(rangeOf, "rangeOf");
1922
+ function pageOf(input) {
1923
+ return {
1924
+ page: typeof input.page === "number" ? input.page : 1,
1925
+ pageSize: typeof input.limit === "number" ? input.limit : DEFAULT_LIMIT
1926
+ };
1927
+ }
1928
+ __name(pageOf, "pageOf");
1929
+ function where(fields) {
1930
+ const set = Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== void 0));
1931
+ return Object.keys(set).length > 0 ? {
1932
+ where: set
1933
+ } : {};
1934
+ }
1935
+ __name(where, "where");
1936
+ function listOf(result) {
1937
+ return {
1938
+ items: result.rows,
1939
+ next: result.page * result.pageSize < result.total ? result.page + 1 : null,
1940
+ total: result.total
1941
+ };
1942
+ }
1943
+ __name(listOf, "listOf");
1944
+ function cut(text, maxBytes) {
1945
+ const size = Buffer.byteLength(text, "utf8");
1946
+ if (size <= maxBytes) return text;
1947
+ const suffix = `\u2026(truncated, ${size} bytes)`;
1948
+ const keep = Math.max(0, maxBytes - Buffer.byteLength(suffix, "utf8"));
1949
+ let head = Buffer.from(text, "utf8").subarray(0, keep).toString("utf8");
1950
+ if (head.endsWith("\uFFFD")) head = head.slice(0, -1);
1951
+ return `${head}${suffix}`;
1952
+ }
1953
+ __name(cut, "cut");
1954
+ function agentDevTools(dashboard) {
1955
+ return [
1956
+ {
1957
+ name: "agent_list_runs",
1958
+ kind: "read",
1959
+ description: "Agent runs, newest first: agent, actor, status, duration, cost, error. Filters: agent, status, errorCode, threadId, from/to (UTC days). Returns { items, next, total }; pass next as page.",
1960
+ input: {
1961
+ type: "object",
1962
+ properties: {
1963
+ agent: {
1964
+ type: "string",
1965
+ description: "Agent name."
1966
+ },
1967
+ status: {
1968
+ type: "string",
1969
+ enum: [
1970
+ "running",
1971
+ "completed",
1972
+ "failed",
1973
+ "cancelled"
1974
+ ]
1975
+ },
1976
+ errorCode: {
1977
+ type: "string"
1978
+ },
1979
+ threadId: {
1980
+ type: "string"
1981
+ },
1982
+ from: day,
1983
+ to: day,
1984
+ page,
1985
+ limit
1986
+ }
1987
+ },
1988
+ async run(input) {
1989
+ return listOf(await dashboard.runsPage({
1990
+ ...pageOf(input),
1991
+ ...where({
1992
+ agentName: str(input.agent),
1993
+ status: str(input.status),
1994
+ errorCode: str(input.errorCode),
1995
+ threadId: str(input.threadId),
1996
+ fromDay: dayOf(input, "from"),
1997
+ toDay: dayOf(input, "to")
1998
+ })
1999
+ }));
2000
+ }
2001
+ },
2002
+ {
2003
+ name: "agent_get_run",
2004
+ kind: "read",
2005
+ description: "One run: the run, its thread, its tool calls and timings. With includeMessages: true, the thread's latest 50 messages, each cut to 2 KB. An error when no run has that id.",
2006
+ input: {
2007
+ type: "object",
2008
+ properties: {
2009
+ id: {
2010
+ type: "string",
2011
+ description: "Run id."
2012
+ },
2013
+ includeMessages: {
2014
+ type: "boolean",
2015
+ description: "Include messages (default false)."
2016
+ }
2017
+ },
2018
+ required: [
2019
+ "id"
2020
+ ]
2021
+ },
2022
+ async run(input) {
2023
+ let detail;
2024
+ try {
2025
+ detail = await dashboard.runDetail(String(input.id));
2026
+ } catch (error) {
2027
+ if (error instanceof import_common10.NotFoundException) throw new Error(`run ${String(input.id)} not found`);
2028
+ throw error;
2029
+ }
2030
+ if (input.includeMessages !== true) return detail;
2031
+ const thread = await dashboard.threadDetail({
2032
+ threadId: detail.run.threadId,
2033
+ messageLimit: MESSAGE_LIMIT,
2034
+ runLimit: 1
2035
+ });
2036
+ return {
2037
+ ...detail,
2038
+ messages: thread.messages.map((message) => ({
2039
+ ...message,
2040
+ content: cut(message.content, MESSAGE_BYTES)
2041
+ }))
2042
+ };
2043
+ }
2044
+ },
2045
+ {
2046
+ name: "agent_get_spend",
2047
+ kind: "read",
2048
+ description: "Tokens and cost over UTC days from/to (default the last 30 days): by model, by actor, by feature and the daily trend. `by` returns one of them.",
2049
+ input: {
2050
+ type: "object",
2051
+ properties: {
2052
+ by: {
2053
+ type: "string",
2054
+ enum: [
2055
+ "model",
2056
+ "actor",
2057
+ "feature"
2058
+ ]
2059
+ },
2060
+ from: day,
2061
+ to: day
2062
+ }
2063
+ },
2064
+ async run(input) {
2065
+ const spend = await dashboard.spend(rangeOf(input));
2066
+ switch (input.by) {
2067
+ case "model":
2068
+ return {
2069
+ items: spend.byModel
2070
+ };
2071
+ case "actor":
2072
+ return {
2073
+ items: spend.byActor
2074
+ };
2075
+ case "feature":
2076
+ return {
2077
+ items: spend.byFeature ?? []
2078
+ };
2079
+ default:
2080
+ return spend;
2081
+ }
2082
+ }
2083
+ },
2084
+ {
2085
+ name: "agent_get_tool_stats",
2086
+ kind: "read",
2087
+ description: "Per tool: calls, failures, rejections and latency, over UTC days from/to (default the last 30 days).",
2088
+ input: {
2089
+ type: "object",
2090
+ properties: {
2091
+ from: day,
2092
+ to: day
2093
+ }
2094
+ },
2095
+ async run(input) {
2096
+ return {
2097
+ items: await dashboard.toolStats(rangeOf(input))
2098
+ };
2099
+ }
2100
+ },
2101
+ {
2102
+ name: "agent_get_reliability",
2103
+ kind: "read",
2104
+ description: "Run metrics, by-agent and by-error breakdowns and the trend, over UTC days from/to (default the last 30 days).",
2105
+ input: {
2106
+ type: "object",
2107
+ properties: {
2108
+ from: day,
2109
+ to: day
2110
+ }
2111
+ },
2112
+ async run(input) {
2113
+ return dashboard.reliability(rangeOf(input));
2114
+ }
2115
+ },
2116
+ {
2117
+ name: "agent_list_pending_approvals",
2118
+ kind: "read",
2119
+ description: "Tool calls waiting for a human approval, oldest first. Read-only: approve them in the app. Returns { items, next, total }.",
2120
+ input: {
2121
+ type: "object",
2122
+ properties: {
2123
+ toolName: {
2124
+ type: "string"
2125
+ },
2126
+ agent: {
2127
+ type: "string",
2128
+ description: "Agent name."
2129
+ },
2130
+ actor: {
2131
+ type: "string",
2132
+ description: "Actor ref of the thread owner."
2133
+ },
2134
+ threadId: {
2135
+ type: "string"
2136
+ },
2137
+ from: day,
2138
+ to: day,
2139
+ page,
2140
+ limit
2141
+ }
2142
+ },
2143
+ async run(input) {
2144
+ return listOf(await dashboard.approvalsPage({
2145
+ ...pageOf(input),
2146
+ ...where({
2147
+ toolName: str(input.toolName),
2148
+ agentName: str(input.agent),
2149
+ actorRef: str(input.actor),
2150
+ threadId: str(input.threadId),
2151
+ fromDay: dayOf(input, "from"),
2152
+ toDay: dayOf(input, "to")
2153
+ })
2154
+ }));
2155
+ }
2156
+ },
2157
+ {
2158
+ name: "agent_list_recent_tool_calls",
2159
+ kind: "read",
2160
+ description: "Tool calls of every agent, newest first. Filters: toolName, status, threadId, from/to (UTC days). Returns { items, next, total }.",
2161
+ input: {
2162
+ type: "object",
2163
+ properties: {
2164
+ toolName: {
2165
+ type: "string"
2166
+ },
2167
+ status: {
2168
+ type: "string"
2169
+ },
2170
+ threadId: {
2171
+ type: "string"
2172
+ },
2173
+ from: day,
2174
+ to: day,
2175
+ page,
2176
+ limit
2177
+ }
2178
+ },
2179
+ async run(input) {
2180
+ return listOf(await dashboard.toolCallsPage({
2181
+ ...pageOf(input),
2182
+ ...where({
2183
+ toolName: str(input.toolName),
2184
+ status: str(input.status),
2185
+ threadId: str(input.threadId),
2186
+ fromDay: dayOf(input, "from"),
2187
+ toDay: dayOf(input, "to")
2188
+ })
2189
+ }));
2190
+ }
2191
+ }
2192
+ ];
2193
+ }
2194
+ __name(agentDevTools, "agentDevTools");
2195
+ var logger3 = new import_common10.Logger("AgentDashboardModule");
2196
+ var AgentDevToolsRegistration = class {
2197
+ static {
2198
+ __name(this, "AgentDevToolsRegistration");
2199
+ }
2200
+ enabled;
2201
+ dashboard;
2202
+ access;
2203
+ #unregister;
2204
+ constructor(enabled, dashboard, access) {
2205
+ this.enabled = enabled;
2206
+ this.dashboard = dashboard;
2207
+ this.access = access;
2208
+ }
2209
+ onModuleInit() {
2210
+ if (!this.enabled) return;
2211
+ const slot = devToolsSlot();
2212
+ if (slot.version !== 1 || typeof slot.register !== "function") return;
2213
+ try {
2214
+ this.#unregister = slot.register({
2215
+ lib: "agent",
2216
+ title: "Agent governance",
2217
+ authorize: /* @__PURE__ */ __name((context) => this.access.check(context), "authorize"),
2218
+ tools: agentDevTools(this.dashboard)
2219
+ });
2220
+ } catch (error) {
2221
+ logger3.warn(`agent dev tools not registered: ${error instanceof Error ? error.message : String(error)}`);
2222
+ }
2223
+ }
2224
+ onModuleDestroy() {
2225
+ this.#unregister?.();
2226
+ this.#unregister = void 0;
2227
+ }
2228
+ };
2229
+ AgentDevToolsRegistration = _ts_decorate6([
2230
+ (0, import_common10.Injectable)(),
2231
+ _ts_param6(0, (0, import_common10.Inject)(DASHBOARD_DEV_TOOLS)),
2232
+ _ts_metadata6("design:type", Function),
2233
+ _ts_metadata6("design:paramtypes", [
2234
+ Boolean,
2235
+ typeof DashboardService === "undefined" ? Object : DashboardService,
2236
+ typeof DashboardConsoleAccess === "undefined" ? Object : DashboardConsoleAccess
2237
+ ])
2238
+ ], AgentDevToolsRegistration);
2239
+
1572
2240
  // src/server/agent-dashboard.module.ts
1573
- function _ts_decorate5(decorators, target, key, desc) {
2241
+ function _ts_decorate7(decorators, target, key, desc) {
1574
2242
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1575
2243
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
1576
2244
  r = Reflect.decorate(decorators, target, key, desc);
@@ -1583,7 +2251,7 @@ function _ts_decorate5(decorators, target, key, desc) {
1583
2251
  }
1584
2252
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1585
2253
  }
1586
- __name(_ts_decorate5, "_ts_decorate");
2254
+ __name(_ts_decorate7, "_ts_decorate");
1587
2255
  function normalize(path) {
1588
2256
  return normalizeDashboardPath(path);
1589
2257
  }
@@ -1591,8 +2259,8 @@ __name(normalize, "normalize");
1591
2259
  function consoleDecorators(decorators) {
1592
2260
  return [
1593
2261
  ...decorators ?? [],
1594
- (0, import_common9.UseGuards)(ConsoleAuthorizeGuard),
1595
- (0, import_common9.UseFilters)(ConsoleAuthorizeFilter)
2262
+ (0, import_common11.UseGuards)(ConsoleAuthorizeGuard),
2263
+ (0, import_common11.UseFilters)(ConsoleAuthorizeFilter)
1596
2264
  ];
1597
2265
  }
1598
2266
  __name(consoleDecorators, "consoleDecorators");
@@ -1611,8 +2279,9 @@ var AgentApiModule = class _AgentApiModule {
1611
2279
  imports: [
1612
2280
  ...options.imports ?? []
1613
2281
  ],
1614
- controllers: options.routes === false ? [] : (0, import_nestjs_agent_core3.withControllerDecorators)([
1615
- AgentApiController
2282
+ controllers: options.routes === false ? [] : (0, import_nestjs_agent_core4.withControllerDecorators)([
2283
+ AgentApiController,
2284
+ AgentConsolesController
1616
2285
  ], consoleDecorators(options.decorators)),
1617
2286
  providers: [
1618
2287
  DashboardService,
@@ -1626,7 +2295,12 @@ var AgentApiModule = class _AgentApiModule {
1626
2295
  provide: DASHBOARD_CONSOLE_OPTIONS,
1627
2296
  useValue: consoleOptions
1628
2297
  },
1629
- DashboardConsoleAccess
2298
+ DashboardConsoleAccess,
2299
+ {
2300
+ provide: DASHBOARD_DEV_TOOLS,
2301
+ useValue: options.devTools ?? options.routes !== false
2302
+ },
2303
+ AgentDevToolsRegistration
1630
2304
  ],
1631
2305
  // What a self-mounted `AgentApiController` subclass injects, too (`routes: false`), and the
1632
2306
  // access check `UseConsoleAuthorize()` runs.
@@ -1638,8 +2312,8 @@ var AgentApiModule = class _AgentApiModule {
1638
2312
  };
1639
2313
  }
1640
2314
  };
1641
- AgentApiModule = _ts_decorate5([
1642
- (0, import_common9.Module)({})
2315
+ AgentApiModule = _ts_decorate7([
2316
+ (0, import_common11.Module)({})
1643
2317
  ], AgentApiModule);
1644
2318
  var AgentDashboardModule = class _AgentDashboardModule {
1645
2319
  static {
@@ -1668,10 +2342,13 @@ var AgentDashboardModule = class _AgentDashboardModule {
1668
2342
  } : {},
1669
2343
  ...options.authorize !== void 0 ? {
1670
2344
  authorize: options.authorize
2345
+ } : {},
2346
+ ...options.devTools !== void 0 ? {
2347
+ devTools: options.devTools
1671
2348
  } : {}
1672
2349
  }),
1673
2350
  ...options.routes === false ? [] : [
1674
- import_core2.RouterModule.register([
2351
+ import_core3.RouterModule.register([
1675
2352
  {
1676
2353
  path: basePath,
1677
2354
  module: _AgentDashboardModule
@@ -1683,7 +2360,7 @@ var AgentDashboardModule = class _AgentDashboardModule {
1683
2360
  ])
1684
2361
  ]
1685
2362
  ],
1686
- controllers: options.routes === false ? [] : (0, import_nestjs_agent_core3.withControllerDecorators)([
2363
+ controllers: options.routes === false ? [] : (0, import_nestjs_agent_core4.withControllerDecorators)([
1687
2364
  AgentUiController
1688
2365
  ], consoleDecorators(options.decorators)),
1689
2366
  providers: [
@@ -1694,7 +2371,11 @@ var AgentDashboardModule = class _AgentDashboardModule {
1694
2371
  {
1695
2372
  provide: DASHBOARD_API_PATH,
1696
2373
  useValue: apiBasePath
1697
- }
2374
+ },
2375
+ // The console switcher lists this console only where it serves its own page.
2376
+ ...options.routes === false ? [] : [
2377
+ AgentConsoleRegistration
2378
+ ]
1698
2379
  ],
1699
2380
  // Re-export the API module so its DashboardService reaches importers (e.g. the host's own
1700
2381
  // controllers), and the paths a self-mounted `AgentUiController` subclass injects.
@@ -1706,23 +2387,30 @@ var AgentDashboardModule = class _AgentDashboardModule {
1706
2387
  };
1707
2388
  }
1708
2389
  };
1709
- AgentDashboardModule = _ts_decorate5([
1710
- (0, import_common9.Module)({})
2390
+ AgentDashboardModule = _ts_decorate7([
2391
+ (0, import_common11.Module)({})
1711
2392
  ], AgentDashboardModule);
1712
2393
  // Annotate the CommonJS export names for ESM import in node:
1713
2394
  0 && (module.exports = {
1714
2395
  AGENT_ACTOR_DIRECTORY,
1715
2396
  AGENT_ACTOR_RESOLVER,
1716
2397
  AGENT_APPROVAL_PORT,
2398
+ AGENT_CONSOLE_ID,
2399
+ AGENT_DASHBOARD_CONFIG_ID,
1717
2400
  AGENT_GOVERNANCE_QUERIES,
1718
2401
  AGENT_PRICING_STORE,
2402
+ AVIARY_CONSOLES_SLOT,
1719
2403
  AgentApiController,
1720
2404
  AgentApiModule,
2405
+ AgentConsoleRegistration,
2406
+ AgentConsolesController,
1721
2407
  AgentDashboardModule,
2408
+ AgentDevToolsRegistration,
1722
2409
  AgentUiController,
1723
2410
  CONSOLE_AUTHORIZE_MISSING_WARNING,
1724
2411
  CONSOLE_GATE,
1725
2412
  CONSOLE_PAGE_METADATA,
2413
+ CONSOLE_PROBE_TIMEOUT_MS,
1726
2414
  ConsoleAccessDenied,
1727
2415
  ConsoleAuthorizeFilter,
1728
2416
  ConsoleAuthorizeGuard,
@@ -1731,13 +2419,18 @@ AgentDashboardModule = _ts_decorate5([
1731
2419
  DASHBOARD_APPROVAL_ACTOR_REF,
1732
2420
  DASHBOARD_BASE_PATH,
1733
2421
  DASHBOARD_CONSOLE_OPTIONS,
2422
+ DASHBOARD_DEV_TOOLS,
1734
2423
  DashboardConsoleAccess,
1735
2424
  DashboardService,
1736
2425
  UseConsoleAuthorize,
1737
2426
  agentDashboardMountPaths,
2427
+ agentDevTools,
2428
+ anyAuthorize,
1738
2429
  authorizeByToken,
2430
+ listVisibleConsoles,
1739
2431
  normalizeConsoleResult,
1740
2432
  parsePriceInput,
2433
+ registerAviaryConsole,
1741
2434
  resolveConsoleAuthorize
1742
2435
  });
1743
2436
  //# sourceMappingURL=index.cjs.map