@dudousxd/nestjs-agent-dashboard 0.22.0 → 0.23.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.
@@ -38,6 +38,7 @@ __export(index_exports, {
38
38
  AGENT_CONSOLE_ID: () => AGENT_CONSOLE_ID,
39
39
  AGENT_DASHBOARD_CONFIG_ID: () => AGENT_DASHBOARD_CONFIG_ID,
40
40
  AGENT_GOVERNANCE_QUERIES: () => AGENT_GOVERNANCE_QUERIES,
41
+ AGENT_OPTIONS: () => AGENT_OPTIONS,
41
42
  AGENT_PRICING_STORE: () => AGENT_PRICING_STORE,
42
43
  AVIARY_CONSOLES_SLOT: () => AVIARY_CONSOLES_SLOT,
43
44
  AgentApiController: () => AgentApiController,
@@ -51,6 +52,7 @@ __export(index_exports, {
51
52
  CONSOLE_GATE: () => CONSOLE_GATE,
52
53
  CONSOLE_PAGE_METADATA: () => CONSOLE_PAGE_METADATA,
53
54
  CONSOLE_PROBE_TIMEOUT_MS: () => CONSOLE_PROBE_TIMEOUT_MS,
55
+ CONTEXT_ACCESSOR: () => CONTEXT_ACCESSOR,
54
56
  ConsoleAccessDenied: () => ConsoleAccessDenied,
55
57
  ConsoleAuthorizeFilter: () => ConsoleAuthorizeFilter,
56
58
  ConsoleAuthorizeGuard: () => ConsoleAuthorizeGuard,
@@ -147,12 +149,37 @@ function isFiniteNonNegative(value) {
147
149
  }
148
150
  __name(isFiniteNonNegative, "isFiniteNonNegative");
149
151
 
152
+ // src/server/tenancy.ts
153
+ var SLOT = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-diagnostics:accessor");
154
+ function consoleTenantFilter(option = "inherit", accessor) {
155
+ const slot = globalThis[SLOT];
156
+ const a = accessor ?? slot?.current;
157
+ if (option === false || typeof a?.tenancy !== "function" || !a.tenantFilter) return void 0;
158
+ const own = typeof option === "object" ? option : {};
159
+ const inherit = own.enabled === void 0 || own.enabled === "inherit";
160
+ if (!(inherit ? a.tenancy().enabled : own.enabled)) return void 0;
161
+ const filter = a.tenantFilter(own.kinds ? {
162
+ kinds: own.kinds
163
+ } : void 0);
164
+ if (filter.mode === "system" || filter.mode === "all") return void 0;
165
+ if (filter.mode === "tenantless") return {
166
+ nulls: true
167
+ };
168
+ return {
169
+ tenant: filter.tenant.id,
170
+ nulls: own.nullRows === "shared"
171
+ };
172
+ }
173
+ __name(consoleTenantFilter, "consoleTenantFilter");
174
+
150
175
  // src/server/tokens.ts
151
176
  var AGENT_GOVERNANCE_QUERIES = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:governance-queries");
152
177
  var AGENT_ACTOR_DIRECTORY = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:actor-directory");
153
178
  var AGENT_PRICING_STORE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:pricing-store");
154
179
  var AGENT_APPROVAL_PORT = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:approval-port");
155
180
  var AGENT_ACTOR_RESOLVER = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:actor-resolver");
181
+ var AGENT_OPTIONS = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:options");
182
+ var CONTEXT_ACCESSOR = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-context:accessor");
156
183
  var DASHBOARD_BASE_PATH = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:base-path");
157
184
  var DASHBOARD_API_PATH = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:api-path");
158
185
  var DASHBOARD_APPROVAL_ACTOR_REF = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent-dashboard:approval-actor-ref");
@@ -188,6 +215,7 @@ function _ts_param(paramIndex, decorator) {
188
215
  __name(_ts_param, "_ts_param");
189
216
  var PRICING_STORE_UNBOUND_MESSAGE = "Pricing CRUD is unavailable: no AGENT_PRICING_STORE is bound. Bind a pricing store (e.g. MikroOrmPricingStore from @dudousxd/nestjs-agent-store-mikro-orm) to enable it.";
190
217
  var APPROVAL_PORT_UNBOUND_MESSAGE = "Approve/reject is unavailable: no AGENT_APPROVAL_PORT is bound. Import AgentModule from @dudousxd/nestjs-agent alongside this dashboard to enable it \u2014 the approvals inbox stays read-only until then.";
218
+ var TENANT_SCOPE_UNSUPPORTED_MESSAGE = "The agent console is tenant-scoped (AgentModule tenancy is on), and the bound AGENT_GOVERNANCE_QUERIES store does not implement forTenant. Use a store adapter that does (Drizzle, MikroORM, in-memory) or set AgentModule `tenancy: false`.";
191
219
  var GENUI_STATS_UNSUPPORTED_MESSAGE = "Generative UI telemetry is unavailable: the bound AGENT_GOVERNANCE_QUERIES store does not implement genuiStats. Use a store adapter that records generative-UI calls (recordGenuiCalls) to enable it.";
192
220
  var AGENT_EVENTS = [
193
221
  "run.started",
@@ -211,19 +239,37 @@ var DashboardService = class {
211
239
  actorDirectory;
212
240
  pricingStore;
213
241
  approvalPort;
214
- constructor(queries, actorDirectory, pricingStore, approvalPort) {
242
+ agentOptions;
243
+ contextAccessor;
244
+ constructor(queries, actorDirectory, pricingStore, approvalPort, agentOptions, contextAccessor) {
215
245
  this.queries = queries;
216
246
  this.actorDirectory = actorDirectory;
217
247
  this.pricingStore = pricingStore;
218
248
  this.approvalPort = approvalPort;
249
+ this.agentOptions = agentOptions;
250
+ this.contextAccessor = contextAccessor;
251
+ }
252
+ /**
253
+ * The read-model for this request: with the agent's tenancy on, narrowed to the viewer's context
254
+ * tenant (another tenant's thread or run is not found). A store without `forTenant` cannot be
255
+ * narrowed, so the console refuses (`501`) rather than show every tenant's rows.
256
+ */
257
+ scoped() {
258
+ const filter = consoleTenantFilter(this.agentOptions?.tenancy ?? "inherit", this.contextAccessor);
259
+ if (filter === void 0) return this.queries;
260
+ if (typeof this.queries.forTenant !== "function") {
261
+ throw new import_common3.NotImplementedException(TENANT_SCOPE_UNSUPPORTED_MESSAGE);
262
+ }
263
+ return this.queries.forTenant(filter);
219
264
  }
220
265
  /** Spend/usage overview for a day range: by-model + by-actor spend and the daily trend, in parallel. */
221
266
  async spend(range) {
267
+ const queries = this.scoped();
222
268
  const [byModel, byActorRaw, trend, byFeature] = await Promise.all([
223
- this.queries.spendByModel(range),
224
- this.queries.spendByActor(range),
225
- this.queries.usageTrend(range),
226
- this.queries.spendByFeature?.(range)
269
+ queries.spendByModel(range),
270
+ queries.spendByActor(range),
271
+ queries.usageTrend(range),
272
+ queries.spendByFeature?.(range)
227
273
  ]);
228
274
  const byActor = await this.withActorLabels(byActorRaw);
229
275
  return {
@@ -237,16 +283,17 @@ var DashboardService = class {
237
283
  }
238
284
  /** Top threads by cost for a day range (default 10, highest cost first). */
239
285
  async topThreads(range, limit2 = 10) {
240
- const rows = await this.queries.spendByThread(range, limit2);
286
+ const rows = await this.scoped().spendByThread(range, limit2);
241
287
  return this.withActorLabels(rows);
242
288
  }
243
289
  /** Run reliability for a day range: metrics, by-agent/by-error breakdowns and the trend, in parallel. */
244
290
  async reliability(range) {
291
+ const queries = this.scoped();
245
292
  const [metrics, byAgent, errors, trend] = await Promise.all([
246
- this.queries.runMetrics(range),
247
- this.queries.runsByAgent(range),
248
- this.queries.runErrors(range),
249
- this.queries.runTrend(range)
293
+ queries.runMetrics(range),
294
+ queries.runsByAgent(range),
295
+ queries.runErrors(range),
296
+ queries.runTrend(range)
250
297
  ]);
251
298
  return {
252
299
  metrics,
@@ -257,19 +304,19 @@ var DashboardService = class {
257
304
  }
258
305
  /** Most recent runs (status/agent/duration/error) for the Reliability recent-runs table. */
259
306
  recentRuns(limit2) {
260
- return this.queries.recentRuns(limit2);
307
+ return this.scoped().recentRuns(limit2);
261
308
  }
262
309
  /** Most recent tool calls (status/type/thread) for the Runs & tools activity feed. */
263
310
  recentToolCalls(limit2) {
264
- return this.queries.recentToolCalls(limit2);
311
+ return this.scoped().recentToolCalls(limit2);
265
312
  }
266
313
  /** Paged, filterable tool calls for the Runs & tools activity table. */
267
314
  toolCallsPage(query) {
268
- return this.queries.toolCallsPage(query);
315
+ return this.scoped().toolCallsPage(query);
269
316
  }
270
317
  /** Paged, filterable runs for the Reliability recent-runs table. */
271
318
  runsPage(query) {
272
- return this.queries.runsPage(query);
319
+ return this.scoped().runsPage(query);
273
320
  }
274
321
  /**
275
322
  * Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox.
@@ -277,11 +324,11 @@ var DashboardService = class {
277
324
  * {@link approvalsPage}, which reports how much of the backlog the cap hid.
278
325
  */
279
326
  pendingApprovals(limit2) {
280
- return this.queries.pendingApprovals(limit2);
327
+ return this.scoped().pendingApprovals(limit2);
281
328
  }
282
329
  /** Paged, filterable approvals inbox with a total — the backlog-safe read of the HITL queue. */
283
330
  approvalsPage(query) {
284
- return this.queries.approvalsPage(query);
331
+ return this.scoped().approvalsPage(query);
285
332
  }
286
333
  /**
287
334
  * One run with its thread and its tool calls. 404s on an unknown id rather than returning an empty
@@ -289,7 +336,7 @@ var DashboardService = class {
289
336
  * that conflates them sends an operator looking for a bug that isn't there.
290
337
  */
291
338
  async runDetail(runId) {
292
- const detail = await this.queries.runDetail(runId);
339
+ const detail = await this.scoped().runDetail(runId);
293
340
  if (detail === null) {
294
341
  throw new import_common3.NotFoundException(`No run "${runId}".`);
295
342
  }
@@ -306,7 +353,7 @@ var DashboardService = class {
306
353
  }
307
354
  /** One thread with its usage rollup, runs and messages. 404s on an unknown id, like {@link runDetail}. */
308
355
  async threadDetail(query) {
309
- const detail = await this.queries.threadDetail(query);
356
+ const detail = await this.scoped().threadDetail(query);
310
357
  if (detail === null) {
311
358
  throw new import_common3.NotFoundException(`No thread "${query.threadId}".`);
312
359
  }
@@ -323,7 +370,7 @@ var DashboardService = class {
323
370
  }
324
371
  /** Per-tool call/failure/rejection/latency rollup for a day range, for the Tools section. */
325
372
  toolStats(range) {
326
- return this.queries.toolStats(range);
373
+ return this.scoped().toolStats(range);
327
374
  }
328
375
  /**
329
376
  * Generative-UI telemetry for a day range — first-try success per tool/model, common errors, UI
@@ -332,10 +379,11 @@ var DashboardService = class {
332
379
  * same posture as an unbound pricing store — the console renders that as its own state.
333
380
  */
334
381
  async genuiStats(range) {
335
- if (this.queries.genuiStats === void 0) {
382
+ const queries = this.scoped();
383
+ if (queries.genuiStats === void 0) {
336
384
  throw new import_common3.NotImplementedException(GENUI_STATS_UNSUPPORTED_MESSAGE);
337
385
  }
338
- return this.queries.genuiStats(range);
386
+ return queries.genuiStats(range);
339
387
  }
340
388
  /**
341
389
  * Decide a pending HITL tool call from the console. Routes through the OPTIONAL
@@ -366,7 +414,7 @@ var DashboardService = class {
366
414
  }
367
415
  /** Most recent threads with rolled-up message/token counts. */
368
416
  async recentThreads(limit2) {
369
- const rows = await this.queries.recentThreads(limit2);
417
+ const rows = await this.scoped().recentThreads(limit2);
370
418
  return this.withActorLabels(rows);
371
419
  }
372
420
  /**
@@ -374,7 +422,7 @@ var DashboardService = class {
374
422
  * {@link recentThreads} is.
375
423
  */
376
424
  async threadsPage(query) {
377
- const page2 = await this.queries.threadsPage(query);
425
+ const page2 = await this.scoped().threadsPage(query);
378
426
  const rows = await this.withActorLabels(page2.rows);
379
427
  return {
380
428
  ...page2,
@@ -463,12 +511,18 @@ DashboardService = _ts_decorate([
463
511
  _ts_param(2, (0, import_common3.Inject)(AGENT_PRICING_STORE)),
464
512
  _ts_param(3, (0, import_common3.Optional)()),
465
513
  _ts_param(3, (0, import_common3.Inject)(AGENT_APPROVAL_PORT)),
514
+ _ts_param(4, (0, import_common3.Optional)()),
515
+ _ts_param(4, (0, import_common3.Inject)(AGENT_OPTIONS)),
516
+ _ts_param(5, (0, import_common3.Optional)()),
517
+ _ts_param(5, (0, import_common3.Inject)(CONTEXT_ACCESSOR)),
466
518
  _ts_metadata("design:type", Function),
467
519
  _ts_metadata("design:paramtypes", [
468
520
  typeof AgentGovernanceQueries === "undefined" ? Object : AgentGovernanceQueries,
469
521
  typeof ActorDirectory === "undefined" ? Object : ActorDirectory,
470
522
  typeof AgentPricingStore === "undefined" ? Object : AgentPricingStore,
471
- typeof AgentApprovalPort === "undefined" ? Object : AgentApprovalPort
523
+ typeof AgentApprovalPort === "undefined" ? Object : AgentApprovalPort,
524
+ Object,
525
+ Object
472
526
  ])
473
527
  ], DashboardService);
474
528
 
@@ -2398,6 +2452,7 @@ AgentDashboardModule = _ts_decorate7([
2398
2452
  AGENT_CONSOLE_ID,
2399
2453
  AGENT_DASHBOARD_CONFIG_ID,
2400
2454
  AGENT_GOVERNANCE_QUERIES,
2455
+ AGENT_OPTIONS,
2401
2456
  AGENT_PRICING_STORE,
2402
2457
  AVIARY_CONSOLES_SLOT,
2403
2458
  AgentApiController,
@@ -2411,6 +2466,7 @@ AgentDashboardModule = _ts_decorate7([
2411
2466
  CONSOLE_GATE,
2412
2467
  CONSOLE_PAGE_METADATA,
2413
2468
  CONSOLE_PROBE_TIMEOUT_MS,
2469
+ CONTEXT_ACCESSOR,
2414
2470
  ConsoleAccessDenied,
2415
2471
  ConsoleAuthorizeFilter,
2416
2472
  ConsoleAuthorizeGuard,