@dudousxd/nestjs-agent-dashboard 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +29 -4
  2. package/dist/client/agent-client.d.ts +111 -1
  3. package/dist/client/agent-client.d.ts.map +1 -1
  4. package/dist/client/agent-client.js +27 -1
  5. package/dist/client/agent-client.js.map +1 -1
  6. package/dist/client/describe-error.d.ts +30 -0
  7. package/dist/client/describe-error.d.ts.map +1 -0
  8. package/dist/client/describe-error.js +63 -0
  9. package/dist/client/describe-error.js.map +1 -0
  10. package/dist/client/format-day.d.ts +19 -0
  11. package/dist/client/format-day.d.ts.map +1 -0
  12. package/dist/client/format-day.js +38 -0
  13. package/dist/client/format-day.js.map +1 -0
  14. package/dist/client/trend-summary.d.ts +33 -0
  15. package/dist/client/trend-summary.d.ts.map +1 -0
  16. package/dist/client/trend-summary.js +33 -0
  17. package/dist/client/trend-summary.js.map +1 -0
  18. package/dist/server/index.cjs +170 -2
  19. package/dist/server/index.cjs.map +1 -1
  20. package/dist/server/index.d.cts +62 -4
  21. package/dist/server/index.d.ts +62 -4
  22. package/dist/server/index.js +181 -13
  23. package/dist/server/index.js.map +1 -1
  24. package/dist/spa/assets/base-ui-CKhU3I2F.js +55 -0
  25. package/dist/spa/assets/index-CO6XH1b7.css +1 -0
  26. package/dist/spa/assets/index-Cvgm9m_c.js +1 -0
  27. package/dist/spa/assets/index-Dr3vAOUw.js +25 -0
  28. package/dist/spa/assets/preview-BdD_YKne.js +1 -0
  29. package/dist/spa/assets/recharts-CPMXF7sD.js +69 -0
  30. package/dist/spa/index.html +5 -3
  31. package/dist/spa/preview.html +5 -3
  32. package/package.json +9 -3
  33. package/dist/client/run-trend-path.d.ts +0 -30
  34. package/dist/client/run-trend-path.d.ts.map +0 -1
  35. package/dist/client/run-trend-path.js +0 -36
  36. package/dist/client/run-trend-path.js.map +0 -1
  37. package/dist/client/trend-path.d.ts +0 -27
  38. package/dist/client/trend-path.d.ts.map +0 -1
  39. package/dist/client/trend-path.js +0 -25
  40. package/dist/client/trend-path.js.map +0 -1
  41. package/dist/spa/assets/index-C42SW8IV.js +0 -1
  42. package/dist/spa/assets/index-DMBWMAsE.css +0 -1
  43. package/dist/spa/assets/index-DZVPxvtJ.js +0 -49
  44. package/dist/spa/assets/preview-DhDnTjWH.js +0 -1
@@ -1,4 +1,4 @@
1
- import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ToolStatRow, ThreadActivityRow, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
1
+ import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ThreadActivityRow, ToolStatRow, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
2
2
  export { ActorDirectory } from '@dudousxd/nestjs-agent-core';
3
3
  import { Observable } from 'rxjs';
4
4
  import { DynamicModule, Type, CanActivate, Provider, InjectionToken, OptionalFactoryDependency, StreamableFile } from '@nestjs/common';
@@ -10,6 +10,18 @@ interface WithActorLabel {
10
10
  type ActorSpendRowWithLabel = ActorSpendRow & WithActorLabel;
11
11
  type ThreadSpendRowWithLabel = ThreadSpendRow & WithActorLabel;
12
12
  type ThreadActivityRowWithLabel = ThreadActivityRow & WithActorLabel;
13
+ /**
14
+ * `GET <api>/runs/:runId` — a run drill-down with the owning thread's `actorLabel` resolved, the
15
+ * same way {@link threadsPage} labels its rows. The run row itself stays unlabeled, matching every
16
+ * other run surface in this console.
17
+ */
18
+ type RunDetailWithLabel = Omit<GovernanceRunDetail, 'thread'> & {
19
+ thread: GovernanceRunDetail['thread'] & WithActorLabel;
20
+ };
21
+ /** `GET <api>/threads/:threadId` — a thread drill-down, actor-labeled like {@link threadsPage}. */
22
+ type ThreadDetailWithLabel = Omit<GovernanceThreadDetail, 'thread'> & {
23
+ thread: ThreadActivityRowWithLabel;
24
+ };
13
25
  /** The spend/usage overview the SPA renders on its headline section (`GET <api>/spend`). */
14
26
  interface SpendOverview {
15
27
  byModel: ModelSpendRow[];
@@ -65,8 +77,22 @@ declare class DashboardService {
65
77
  toolCallsPage(query: GovernancePageQuery<ToolCallWhere>): Promise<GovernancePage<ToolCallActivityRow>>;
66
78
  /** Paged, filterable runs for the Reliability recent-runs table. */
67
79
  runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;
68
- /** Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox. */
80
+ /**
81
+ * Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox.
82
+ * Capped and totalless — kept because the SPA still calls `GET approvals`; new callers want
83
+ * {@link approvalsPage}, which reports how much of the backlog the cap hid.
84
+ */
69
85
  pendingApprovals(limit: number): Promise<PendingApprovalRow[]>;
86
+ /** Paged, filterable approvals inbox with a total — the backlog-safe read of the HITL queue. */
87
+ approvalsPage(query: GovernancePageQuery<ApprovalWhere>): Promise<GovernancePage<PendingApprovalRow>>;
88
+ /**
89
+ * One run with its thread and its tool calls. 404s on an unknown id rather than returning an empty
90
+ * detail: "this run does not exist" and "this run did nothing" are different answers, and a console
91
+ * that conflates them sends an operator looking for a bug that isn't there.
92
+ */
93
+ runDetail(runId: string): Promise<RunDetailWithLabel>;
94
+ /** One thread with its usage rollup, runs and messages. 404s on an unknown id, like {@link runDetail}. */
95
+ threadDetail(query: GovernanceThreadDetailQuery): Promise<ThreadDetailWithLabel>;
70
96
  /** Per-tool call/failure/rejection/latency rollup for a day range, for the Tools section. */
71
97
  toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;
72
98
  /**
@@ -136,6 +162,14 @@ declare class AgentApiController {
136
162
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
137
163
  */
138
164
  runsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<RecentRunRow>>;
165
+ /**
166
+ * One run drill-down: the run, its owning thread's headline (actor-labeled) and its tool calls, in
167
+ * ONE round trip. 404s on an unknown run id.
168
+ *
169
+ * Declared AFTER `runs-page` so the literal route wins over this parameterised one regardless of
170
+ * how the router orders same-prefix paths.
171
+ */
172
+ runDetail(runId: string): Promise<RunDetailWithLabel>;
139
173
  /** Most recent tool calls (default 50, max 200) for the activity feed. */
140
174
  toolCalls(limit?: string): Promise<ToolCallActivityRow[]>;
141
175
  /**
@@ -144,8 +178,22 @@ declare class AgentApiController {
144
178
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
145
179
  */
146
180
  toolCallsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<ToolCallActivityRow>>;
147
- /** Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox. */
181
+ /**
182
+ * Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox.
183
+ *
184
+ * Capped with NO total, so a backlog past `limit` is invisible from the response alone. Kept
185
+ * because the SPA still calls it; anything new should call `approvals-page` instead.
186
+ */
148
187
  approvals(limit?: string): Promise<PendingApprovalRow[]>;
188
+ /**
189
+ * Paged, filterable approvals inbox, oldest first. `page` (default 1), `limit` (default 25, max
190
+ * 200), and `where[toolName]`/`where[threadId]`/`where[actorRef]`/`where[agentName]`/
191
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
192
+ *
193
+ * Unlike `GET approvals` this reports `total`, so the console can say "showing N of M" instead of
194
+ * silently hiding pending decisions behind a row cap.
195
+ */
196
+ approvalsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<PendingApprovalRow>>;
149
197
  /**
150
198
  * Decide a pending HITL tool call. Body `{ approved: boolean; reason?: string }`. 501s (via
151
199
  * `DashboardService.decideApproval`) when no `AGENT_APPROVAL_PORT` is bound. `executedByRef`
@@ -170,6 +218,16 @@ declare class AgentApiController {
170
218
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
171
219
  */
172
220
  threadsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<ThreadActivityRowWithLabel>>;
221
+ /**
222
+ * One thread drill-down: the thread (actor-labeled), its lifetime token/cost rollup, its newest
223
+ * runs and its newest messages, in ONE round trip. `messages` (default 50, max 200) and `runs`
224
+ * (default 25, max 200) cap the two lists; `runTotal` and `thread.messageCount` report the true
225
+ * sizes so the console can say what the caps hid. 404s on an unknown thread id.
226
+ *
227
+ * A soft-deleted thread is still returned, flagged `deleted: true` — an audit needs the thread it
228
+ * just lost, and the alternative is a drill-down that 404s on exactly the interesting case.
229
+ */
230
+ threadDetail(threadId: string, messages?: string, runs?: string): Promise<ThreadDetailWithLabel>;
173
231
  /**
174
232
  * Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when
175
233
  * no `AGENT_PRICING_STORE` is bound.
@@ -636,4 +694,4 @@ declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
636
694
  */
637
695
  declare const DASHBOARD_AUTH: unique symbol;
638
696
 
639
- export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, type AgentDashboardAsyncOptions, AgentDashboardAuthController, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, type AuthMode, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type RevalidateHook, type SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type UnauthenticatedPageContext, type UnauthenticatedPageHook, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
697
+ export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, type AgentDashboardAsyncOptions, AgentDashboardAuthController, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, type AuthMode, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type RevalidateHook, type RunDetailWithLabel, type SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadDetailWithLabel, type ThreadSpendRowWithLabel, type UnauthenticatedPageContext, type UnauthenticatedPageHook, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
@@ -1,4 +1,4 @@
1
- import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ToolStatRow, ThreadActivityRow, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
1
+ import { ActorSpendRow, AgentGovernanceQueries, ActorDirectory, AgentPricingStore, AgentApprovalPort, GovernanceRange, ModelSpendRow, UsageTrendPoint, ThreadSpendRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, ToolCallActivityRow, GovernancePageQuery, ToolCallWhere, GovernancePage, RunWhere, PendingApprovalRow, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ThreadActivityRow, ToolStatRow, ThreadWhere, CurrentModelPrice, ActorResolver, ModelPriceInput } from '@dudousxd/nestjs-agent-core';
2
2
  export { ActorDirectory } from '@dudousxd/nestjs-agent-core';
3
3
  import { Observable } from 'rxjs';
4
4
  import { DynamicModule, Type, CanActivate, Provider, InjectionToken, OptionalFactoryDependency, StreamableFile } from '@nestjs/common';
@@ -10,6 +10,18 @@ interface WithActorLabel {
10
10
  type ActorSpendRowWithLabel = ActorSpendRow & WithActorLabel;
11
11
  type ThreadSpendRowWithLabel = ThreadSpendRow & WithActorLabel;
12
12
  type ThreadActivityRowWithLabel = ThreadActivityRow & WithActorLabel;
13
+ /**
14
+ * `GET <api>/runs/:runId` — a run drill-down with the owning thread's `actorLabel` resolved, the
15
+ * same way {@link threadsPage} labels its rows. The run row itself stays unlabeled, matching every
16
+ * other run surface in this console.
17
+ */
18
+ type RunDetailWithLabel = Omit<GovernanceRunDetail, 'thread'> & {
19
+ thread: GovernanceRunDetail['thread'] & WithActorLabel;
20
+ };
21
+ /** `GET <api>/threads/:threadId` — a thread drill-down, actor-labeled like {@link threadsPage}. */
22
+ type ThreadDetailWithLabel = Omit<GovernanceThreadDetail, 'thread'> & {
23
+ thread: ThreadActivityRowWithLabel;
24
+ };
13
25
  /** The spend/usage overview the SPA renders on its headline section (`GET <api>/spend`). */
14
26
  interface SpendOverview {
15
27
  byModel: ModelSpendRow[];
@@ -65,8 +77,22 @@ declare class DashboardService {
65
77
  toolCallsPage(query: GovernancePageQuery<ToolCallWhere>): Promise<GovernancePage<ToolCallActivityRow>>;
66
78
  /** Paged, filterable runs for the Reliability recent-runs table. */
67
79
  runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;
68
- /** Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox. */
80
+ /**
81
+ * Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox.
82
+ * Capped and totalless — kept because the SPA still calls `GET approvals`; new callers want
83
+ * {@link approvalsPage}, which reports how much of the backlog the cap hid.
84
+ */
69
85
  pendingApprovals(limit: number): Promise<PendingApprovalRow[]>;
86
+ /** Paged, filterable approvals inbox with a total — the backlog-safe read of the HITL queue. */
87
+ approvalsPage(query: GovernancePageQuery<ApprovalWhere>): Promise<GovernancePage<PendingApprovalRow>>;
88
+ /**
89
+ * One run with its thread and its tool calls. 404s on an unknown id rather than returning an empty
90
+ * detail: "this run does not exist" and "this run did nothing" are different answers, and a console
91
+ * that conflates them sends an operator looking for a bug that isn't there.
92
+ */
93
+ runDetail(runId: string): Promise<RunDetailWithLabel>;
94
+ /** One thread with its usage rollup, runs and messages. 404s on an unknown id, like {@link runDetail}. */
95
+ threadDetail(query: GovernanceThreadDetailQuery): Promise<ThreadDetailWithLabel>;
70
96
  /** Per-tool call/failure/rejection/latency rollup for a day range, for the Tools section. */
71
97
  toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;
72
98
  /**
@@ -136,6 +162,14 @@ declare class AgentApiController {
136
162
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
137
163
  */
138
164
  runsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<RecentRunRow>>;
165
+ /**
166
+ * One run drill-down: the run, its owning thread's headline (actor-labeled) and its tool calls, in
167
+ * ONE round trip. 404s on an unknown run id.
168
+ *
169
+ * Declared AFTER `runs-page` so the literal route wins over this parameterised one regardless of
170
+ * how the router orders same-prefix paths.
171
+ */
172
+ runDetail(runId: string): Promise<RunDetailWithLabel>;
139
173
  /** Most recent tool calls (default 50, max 200) for the activity feed. */
140
174
  toolCalls(limit?: string): Promise<ToolCallActivityRow[]>;
141
175
  /**
@@ -144,8 +178,22 @@ declare class AgentApiController {
144
178
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
145
179
  */
146
180
  toolCallsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<ToolCallActivityRow>>;
147
- /** Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox. */
181
+ /**
182
+ * Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox.
183
+ *
184
+ * Capped with NO total, so a backlog past `limit` is invisible from the response alone. Kept
185
+ * because the SPA still calls it; anything new should call `approvals-page` instead.
186
+ */
148
187
  approvals(limit?: string): Promise<PendingApprovalRow[]>;
188
+ /**
189
+ * Paged, filterable approvals inbox, oldest first. `page` (default 1), `limit` (default 25, max
190
+ * 200), and `where[toolName]`/`where[threadId]`/`where[actorRef]`/`where[agentName]`/
191
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
192
+ *
193
+ * Unlike `GET approvals` this reports `total`, so the console can say "showing N of M" instead of
194
+ * silently hiding pending decisions behind a row cap.
195
+ */
196
+ approvalsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<PendingApprovalRow>>;
149
197
  /**
150
198
  * Decide a pending HITL tool call. Body `{ approved: boolean; reason?: string }`. 501s (via
151
199
  * `DashboardService.decideApproval`) when no `AGENT_APPROVAL_PORT` is bound. `executedByRef`
@@ -170,6 +218,16 @@ declare class AgentApiController {
170
218
  * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
171
219
  */
172
220
  threadsPage(page?: string, limit?: string, where?: Record<string, string>): Promise<GovernancePage<ThreadActivityRowWithLabel>>;
221
+ /**
222
+ * One thread drill-down: the thread (actor-labeled), its lifetime token/cost rollup, its newest
223
+ * runs and its newest messages, in ONE round trip. `messages` (default 50, max 200) and `runs`
224
+ * (default 25, max 200) cap the two lists; `runTotal` and `thread.messageCount` report the true
225
+ * sizes so the console can say what the caps hid. 404s on an unknown thread id.
226
+ *
227
+ * A soft-deleted thread is still returned, flagged `deleted: true` — an audit needs the thread it
228
+ * just lost, and the alternative is a drill-down that 404s on exactly the interesting case.
229
+ */
230
+ threadDetail(threadId: string, messages?: string, runs?: string): Promise<ThreadDetailWithLabel>;
173
231
  /**
174
232
  * Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when
175
233
  * no `AGENT_PRICING_STORE` is bound.
@@ -636,4 +694,4 @@ declare const DASHBOARD_APPROVAL_ACTOR_REF: unique symbol;
636
694
  */
637
695
  declare const DASHBOARD_AUTH: unique symbol;
638
696
 
639
- export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, type AgentDashboardAsyncOptions, AgentDashboardAuthController, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, type AuthMode, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type RevalidateHook, type SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadSpendRowWithLabel, type UnauthenticatedPageContext, type UnauthenticatedPageHook, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
697
+ export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_GOVERNANCE_QUERIES, AGENT_PRICING_STORE, type ActorSpendRowWithLabel, AgentApiController, AgentApiModule, type AgentDashboardAsyncOptions, AgentDashboardAuthController, AgentDashboardModule, type AgentDashboardMountPathsOptions, type AgentDashboardOptions, AgentUiController, type AuthMode, DASHBOARD_API_PATH, DASHBOARD_APPROVAL_ACTOR_REF, DASHBOARD_AUTH, DASHBOARD_BASE_PATH, type DashboardAuthOptions, DashboardService, type LiveAgentEvent, type LoginHook, type ReliabilityOverview, type ResolvedDashboardAuth, type RevalidateHook, type RunDetailWithLabel, type SessionHook, type SpendOverview, type ThreadActivityRowWithLabel, type ThreadDetailWithLabel, type ThreadSpendRowWithLabel, type UnauthenticatedPageContext, type UnauthenticatedPageHook, type WithActorLabel, agentDashboardMountPaths, parsePriceInput, resolveDashboardAuth };
@@ -387,7 +387,7 @@ DashboardAuthGuard = _ts_decorate([
387
387
  // src/server/dashboard.service.ts
388
388
  import { subscribe, unsubscribe } from "node:diagnostics_channel";
389
389
  import { channelName } from "@dudousxd/nestjs-diagnostics";
390
- import { Inject as Inject2, Injectable as Injectable2, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
390
+ import { Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
391
391
  import { Observable as Observable2 } from "rxjs";
392
392
 
393
393
  // src/server/parse-approval-decision.ts
@@ -548,10 +548,56 @@ var DashboardService = class {
548
548
  runsPage(query) {
549
549
  return this.queries.runsPage(query);
550
550
  }
551
- /** Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox. */
551
+ /**
552
+ * Tool calls sitting `pending_approval`, oldest first, for the cross-thread approvals inbox.
553
+ * Capped and totalless — kept because the SPA still calls `GET approvals`; new callers want
554
+ * {@link approvalsPage}, which reports how much of the backlog the cap hid.
555
+ */
552
556
  pendingApprovals(limit) {
553
557
  return this.queries.pendingApprovals(limit);
554
558
  }
559
+ /** Paged, filterable approvals inbox with a total — the backlog-safe read of the HITL queue. */
560
+ approvalsPage(query) {
561
+ return this.queries.approvalsPage(query);
562
+ }
563
+ /**
564
+ * One run with its thread and its tool calls. 404s on an unknown id rather than returning an empty
565
+ * detail: "this run does not exist" and "this run did nothing" are different answers, and a console
566
+ * that conflates them sends an operator looking for a bug that isn't there.
567
+ */
568
+ async runDetail(runId) {
569
+ const detail = await this.queries.runDetail(runId);
570
+ if (detail === null) {
571
+ throw new NotFoundException(`No run "${runId}".`);
572
+ }
573
+ const [thread] = await this.withActorLabels([
574
+ detail.thread
575
+ ]);
576
+ return {
577
+ ...detail,
578
+ thread: thread ?? {
579
+ ...detail.thread,
580
+ actorLabel: null
581
+ }
582
+ };
583
+ }
584
+ /** One thread with its usage rollup, runs and messages. 404s on an unknown id, like {@link runDetail}. */
585
+ async threadDetail(query) {
586
+ const detail = await this.queries.threadDetail(query);
587
+ if (detail === null) {
588
+ throw new NotFoundException(`No thread "${query.threadId}".`);
589
+ }
590
+ const [thread] = await this.withActorLabels([
591
+ detail.thread
592
+ ]);
593
+ return {
594
+ ...detail,
595
+ thread: thread ?? {
596
+ ...detail.thread,
597
+ actorLabel: null
598
+ }
599
+ };
600
+ }
555
601
  /** Per-tool call/failure/rejection/latency rollup for a day range, for the Tools section. */
556
602
  toolStats(range) {
557
603
  return this.queries.toolStats(range);
@@ -785,6 +831,7 @@ var RUN_WHERE_FIELDS = [
785
831
  "agentName",
786
832
  "status",
787
833
  "errorCode",
834
+ "threadId",
788
835
  "fromDay",
789
836
  "toDay"
790
837
  ];
@@ -802,6 +849,9 @@ function parseRunWhere(raw) {
802
849
  ...raw.errorCode !== void 0 ? {
803
850
  errorCode: raw.errorCode
804
851
  } : {},
852
+ ...raw.threadId !== void 0 ? {
853
+ threadId: raw.threadId
854
+ } : {},
805
855
  ...raw.fromDay !== void 0 ? {
806
856
  fromDay: raw.fromDay
807
857
  } : {},
@@ -811,6 +861,40 @@ function parseRunWhere(raw) {
811
861
  };
812
862
  }
813
863
  __name(parseRunWhere, "parseRunWhere");
864
+ var APPROVAL_WHERE_FIELDS = [
865
+ "toolName",
866
+ "threadId",
867
+ "actorRef",
868
+ "agentName",
869
+ "fromDay",
870
+ "toDay"
871
+ ];
872
+ function parseApprovalWhere(raw) {
873
+ if (raw === void 0 || Object.keys(raw).length === 0) return void 0;
874
+ assertKnownFields(raw, APPROVAL_WHERE_FIELDS);
875
+ assertDayFields(raw, DAY_FIELDS);
876
+ return {
877
+ ...raw.toolName !== void 0 ? {
878
+ toolName: raw.toolName
879
+ } : {},
880
+ ...raw.threadId !== void 0 ? {
881
+ threadId: raw.threadId
882
+ } : {},
883
+ ...raw.actorRef !== void 0 ? {
884
+ actorRef: raw.actorRef
885
+ } : {},
886
+ ...raw.agentName !== void 0 ? {
887
+ agentName: raw.agentName
888
+ } : {},
889
+ ...raw.fromDay !== void 0 ? {
890
+ fromDay: raw.fromDay
891
+ } : {},
892
+ ...raw.toDay !== void 0 ? {
893
+ toDay: raw.toDay
894
+ } : {}
895
+ };
896
+ }
897
+ __name(parseApprovalWhere, "parseApprovalWhere");
814
898
 
815
899
  // src/server/agent-api.controller.ts
816
900
  function _ts_decorate3(decorators, target, key, desc) {
@@ -896,6 +980,16 @@ var AgentApiController = class {
896
980
  } : {}
897
981
  });
898
982
  }
983
+ /**
984
+ * One run drill-down: the run, its owning thread's headline (actor-labeled) and its tool calls, in
985
+ * ONE round trip. 404s on an unknown run id.
986
+ *
987
+ * Declared AFTER `runs-page` so the literal route wins over this parameterised one regardless of
988
+ * how the router orders same-prefix paths.
989
+ */
990
+ runDetail(runId) {
991
+ return this.dashboard.runDetail(runId);
992
+ }
899
993
  /** Most recent tool calls (default 50, max 200) for the activity feed. */
900
994
  toolCalls(limit) {
901
995
  return this.dashboard.recentToolCalls(parseLimit(limit, 50));
@@ -915,11 +1009,34 @@ var AgentApiController = class {
915
1009
  } : {}
916
1010
  });
917
1011
  }
918
- /** Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox. */
1012
+ /**
1013
+ * Tool calls sitting `pending_approval` (default 50, max 200), oldest first — the approvals inbox.
1014
+ *
1015
+ * Capped with NO total, so a backlog past `limit` is invisible from the response alone. Kept
1016
+ * because the SPA still calls it; anything new should call `approvals-page` instead.
1017
+ */
919
1018
  approvals(limit) {
920
1019
  return this.dashboard.pendingApprovals(parseLimit(limit, 50));
921
1020
  }
922
1021
  /**
1022
+ * Paged, filterable approvals inbox, oldest first. `page` (default 1), `limit` (default 25, max
1023
+ * 200), and `where[toolName]`/`where[threadId]`/`where[actorRef]`/`where[agentName]`/
1024
+ * `where[fromDay]`/`where[toDay]` (`YYYY-MM-DD`) — an unknown `where` field 400s naming it.
1025
+ *
1026
+ * Unlike `GET approvals` this reports `total`, so the console can say "showing N of M" instead of
1027
+ * silently hiding pending decisions behind a row cap.
1028
+ */
1029
+ approvalsPage(page, limit, where) {
1030
+ const parsedWhere = parseApprovalWhere(where);
1031
+ return this.dashboard.approvalsPage({
1032
+ page: parsePageNumber(page),
1033
+ pageSize: parseLimit(limit, 25),
1034
+ ...parsedWhere !== void 0 ? {
1035
+ where: parsedWhere
1036
+ } : {}
1037
+ });
1038
+ }
1039
+ /**
923
1040
  * Decide a pending HITL tool call. Body `{ approved: boolean; reason?: string }`. 501s (via
924
1041
  * `DashboardService.decideApproval`) when no `AGENT_APPROVAL_PORT` is bound. `executedByRef`
925
1042
  * comes from {@link deciderRef} run against the live request.
@@ -971,6 +1088,22 @@ var AgentApiController = class {
971
1088
  });
972
1089
  }
973
1090
  /**
1091
+ * One thread drill-down: the thread (actor-labeled), its lifetime token/cost rollup, its newest
1092
+ * runs and its newest messages, in ONE round trip. `messages` (default 50, max 200) and `runs`
1093
+ * (default 25, max 200) cap the two lists; `runTotal` and `thread.messageCount` report the true
1094
+ * sizes so the console can say what the caps hid. 404s on an unknown thread id.
1095
+ *
1096
+ * A soft-deleted thread is still returned, flagged `deleted: true` — an audit needs the thread it
1097
+ * just lost, and the alternative is a drill-down that 404s on exactly the interesting case.
1098
+ */
1099
+ threadDetail(threadId, messages, runs) {
1100
+ return this.dashboard.threadDetail({
1101
+ threadId,
1102
+ messageLimit: parseLimit(messages, 50),
1103
+ runLimit: parseLimit(runs, 25)
1104
+ });
1105
+ }
1106
+ /**
974
1107
  * Current price row per model, for the pricing tab. 501s (via `DashboardService.listPrices`) when
975
1108
  * no `AGENT_PRICING_STORE` is bound.
976
1109
  */
@@ -1047,6 +1180,15 @@ _ts_decorate3([
1047
1180
  ]),
1048
1181
  _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1049
1182
  ], AgentApiController.prototype, "runsPage", null);
1183
+ _ts_decorate3([
1184
+ Get("runs/:runId"),
1185
+ _ts_param3(0, Param("runId")),
1186
+ _ts_metadata3("design:type", Function),
1187
+ _ts_metadata3("design:paramtypes", [
1188
+ String
1189
+ ]),
1190
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1191
+ ], AgentApiController.prototype, "runDetail", null);
1050
1192
  _ts_decorate3([
1051
1193
  Get("tool-calls"),
1052
1194
  _ts_param3(0, Query("limit")),
@@ -1078,6 +1220,19 @@ _ts_decorate3([
1078
1220
  ]),
1079
1221
  _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1080
1222
  ], AgentApiController.prototype, "approvals", null);
1223
+ _ts_decorate3([
1224
+ Get("approvals-page"),
1225
+ _ts_param3(0, Query("page")),
1226
+ _ts_param3(1, Query("limit")),
1227
+ _ts_param3(2, Query("where")),
1228
+ _ts_metadata3("design:type", Function),
1229
+ _ts_metadata3("design:paramtypes", [
1230
+ String,
1231
+ String,
1232
+ typeof Record === "undefined" ? Object : Record
1233
+ ]),
1234
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1235
+ ], AgentApiController.prototype, "approvalsPage", null);
1081
1236
  _ts_decorate3([
1082
1237
  Post("approvals/:toolCallId"),
1083
1238
  HttpCode(204),
@@ -1125,6 +1280,19 @@ _ts_decorate3([
1125
1280
  ]),
1126
1281
  _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1127
1282
  ], AgentApiController.prototype, "threadsPage", null);
1283
+ _ts_decorate3([
1284
+ Get("threads/:threadId"),
1285
+ _ts_param3(0, Param("threadId")),
1286
+ _ts_param3(1, Query("messages")),
1287
+ _ts_param3(2, Query("runs")),
1288
+ _ts_metadata3("design:type", Function),
1289
+ _ts_metadata3("design:paramtypes", [
1290
+ String,
1291
+ String,
1292
+ String
1293
+ ]),
1294
+ _ts_metadata3("design:returntype", typeof Promise === "undefined" ? Object : Promise)
1295
+ ], AgentApiController.prototype, "threadDetail", null);
1128
1296
  _ts_decorate3([
1129
1297
  Get("pricing"),
1130
1298
  _ts_metadata3("design:type", Function),
@@ -1161,7 +1329,7 @@ AgentApiController = _ts_decorate3([
1161
1329
  ], AgentApiController);
1162
1330
 
1163
1331
  // src/server/agent-dashboard-auth.controller.ts
1164
- import { Body as Body2, Controller as Controller2, Get as Get2, Header, HttpCode as HttpCode2, Inject as Inject4, Logger, NotFoundException, Optional as Optional4, Post as Post2, Query as Query2, Req as Req2, Res, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
1332
+ import { Body as Body2, Controller as Controller2, Get as Get2, Header, HttpCode as HttpCode2, Inject as Inject4, Logger, NotFoundException as NotFoundException2, Optional as Optional4, Post as Post2, Query as Query2, Req as Req2, Res, UnauthorizedException as UnauthorizedException2 } from "@nestjs/common";
1165
1333
 
1166
1334
  // src/server/auth/login-page.ts
1167
1335
  function escapeHtml(value) {
@@ -1336,7 +1504,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1336
1504
  }
1337
1505
  loginPage(req, res, returnToQuery, error) {
1338
1506
  const auth = this.requireAuth();
1339
- if (!auth.modes.includes("login")) throw new NotFoundException();
1507
+ if (!auth.modes.includes("login")) throw new NotFoundException2();
1340
1508
  const returnTo = sanitizeReturnTo(this.basePath, returnToQuery);
1341
1509
  if (this.currentSession(req)) {
1342
1510
  res.status(302);
@@ -1351,7 +1519,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1351
1519
  }
1352
1520
  async login(body, req, res) {
1353
1521
  const auth = this.requireAuth();
1354
- if (!auth.modes.includes("login")) throw new NotFoundException();
1522
+ if (!auth.modes.includes("login")) throw new NotFoundException2();
1355
1523
  const returnTo = sanitizeReturnTo(this.basePath, body?.returnTo);
1356
1524
  const username = body?.username;
1357
1525
  const password = body?.password;
@@ -1386,7 +1554,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1386
1554
  // request and returns the session user, or `null` to deny. No credential reaches this library.
1387
1555
  async session(request, response) {
1388
1556
  const auth = this.requireAuth();
1389
- if (!auth.modes.includes("session")) throw new NotFoundException();
1557
+ if (!auth.modes.includes("session")) throw new NotFoundException2();
1390
1558
  const user = await this.runHook("session", () => auth.session?.(request) ?? null);
1391
1559
  if (!user) throw new UnauthorizedException2();
1392
1560
  issueSessionCookie(user, {
@@ -1406,7 +1574,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1406
1574
  // path; the host owns its own headers on the hook path.
1407
1575
  async sessionRequiredPage(req, res) {
1408
1576
  const auth = this.requireAuth();
1409
- if (auth.modes.includes("login")) throw new NotFoundException();
1577
+ if (auth.modes.includes("login")) throw new NotFoundException2();
1410
1578
  const hook = auth.unauthenticatedPage;
1411
1579
  if (hook) {
1412
1580
  try {
@@ -1461,7 +1629,7 @@ var AgentDashboardAuthController = class _AgentDashboardAuthController {
1461
1629
  this.logger.warn(message);
1462
1630
  }
1463
1631
  requireAuth() {
1464
- if (!this.auth) throw new NotFoundException();
1632
+ if (!this.auth) throw new NotFoundException2();
1465
1633
  return this.auth;
1466
1634
  }
1467
1635
  };
@@ -1583,7 +1751,7 @@ import { RouterModule } from "@nestjs/core";
1583
1751
  import { existsSync, readFileSync } from "node:fs";
1584
1752
  import { basename, extname, join, resolve, sep } from "node:path";
1585
1753
  import { fileURLToPath } from "node:url";
1586
- import { Controller as Controller3, Get as Get3, Header as Header2, Inject as Inject6, NotFoundException as NotFoundException2, Param as Param2, Req as Req3, Res as Res2, StreamableFile, UseFilters, UseGuards as UseGuards2 } from "@nestjs/common";
1754
+ import { Controller as Controller3, Get as Get3, Header as Header2, Inject as Inject6, NotFoundException as NotFoundException3, Param as Param2, Req as Req3, Res as Res2, StreamableFile, UseFilters, UseGuards as UseGuards2 } from "@nestjs/common";
1587
1755
 
1588
1756
  // src/server/auth/dashboard-auth-page.guard.ts
1589
1757
  import { Inject as Inject5, Injectable as Injectable4, Optional as Optional5 } from "@nestjs/common";
@@ -1757,7 +1925,7 @@ var AgentUiController = class {
1757
1925
  }
1758
1926
  const indexPath = join(this.dir, "index.html");
1759
1927
  if (!existsSync(indexPath)) {
1760
- throw new NotFoundException2("Dashboard is not built. Run the package build.");
1928
+ throw new NotFoundException3("Dashboard is not built. Run the package build.");
1761
1929
  }
1762
1930
  const html = readFileSync(indexPath, "utf8").replaceAll(`="${BUILD_BASE}/`, `="${this.basePath}/`);
1763
1931
  const inject = `<script>window.__AGENT_BASE__='${this.basePath}';window.__AGENT_API__='${this.apiBasePath}';</script>`;
@@ -1765,11 +1933,11 @@ var AgentUiController = class {
1765
1933
  }
1766
1934
  asset(file) {
1767
1935
  const safe = basename(file);
1768
- if (safe !== file) throw new NotFoundException2();
1936
+ if (safe !== file) throw new NotFoundException3();
1769
1937
  const root = resolve(this.dir, "assets");
1770
1938
  const assetPath = resolve(root, safe);
1771
1939
  if (!assetPath.startsWith(root + sep) || !existsSync(assetPath)) {
1772
- throw new NotFoundException2();
1940
+ throw new NotFoundException3();
1773
1941
  }
1774
1942
  const type = CONTENT_TYPES[extname(safe)] ?? "application/octet-stream";
1775
1943
  return new StreamableFile(readFileSync(assetPath), {