Aviary
Packages

@dudousxd/nestjs-agent-telescope

Telescope extension that adds an "Agent" tab — live runs + tool calls off diagnostics, historical spend off the governance read-model.

The first-class @dudousxd/nestjs-telescope extension for nestjs-agent. It adds an "Agent" tab fed by two sources: the aviary:agent:* diagnostics channel (live runs, tool calls) via a watcher, and the AGENT_GOVERNANCE_QUERIES read-model (historical spend/usage, run reliability, tool stats, the approvals inbox, and paginated runs/tool-calls/threads tables) via a set of dashboard data providers. Run detail also correlates into the TRACES tab (see Tracing below).

pnpm add @dudousxd/nestjs-agent-telescope @dudousxd/nestjs-telescope
npm install @dudousxd/nestjs-agent-telescope @dudousxd/nestjs-telescope

Minimal example

Register agentTelescopeExtension() on Telescope's extensions array, same as any other Telescope extension:

import { TelescopeModule } from '@dudousxd/nestjs-telescope';
import { agentTelescopeExtension } from '@dudousxd/nestjs-agent-telescope';

@Module({
  imports: [
    TelescopeModule.forRoot({
      authorizer: () => true, // restrict in production
      extensions: [agentTelescopeExtension()],
    }),
  ],
})
export class AppModule {}

The governance panels need AGENT_GOVERNANCE_QUERIES bound

The Spend / Models / Actors panels resolve AGENT_GOVERNANCE_QUERIES from the host DI container at request time. The host must bind that token — by importing a store module (store-mikro-orm, store-drizzle, or testing's InMemoryGovernanceQueries) — in the same app that registers TelescopeModule.forRoot({ extensions: [agentTelescopeExtension()] }). If the binding is absent, those panels render an empty state; the live watcher-fed panels (runs, tool calls) keep working regardless, since they depend only on the diagnostics channel.

Exports

ExportKindPurpose
agentTelescopeExtension(opts?)function → TelescopeExtensionThe extension: registers the watcher, the agent entry type, the "Agent" dashboard, and every data provider below. opts.threadHref/opts.runHref are URL templates ({threadId}/{runId}) that deep-link a table row's thread/run cell out to the host's own viewer — runId defaults to the in-app trace waterfall (#/traces/{runId}, see Tracing below) when runHref is omitted
AgentTelescopeWatcherclass (Watcher)Subscribes to all 8 point events on aviary:agent:* (run.started, message, tool-call, quota.exceeded, run.finished, run.failed, delegated, retrieved — driven off core's AGENT_DIAGNOSTIC_EVENTS, so a future point event is picked up automatically) and records each as a Telescope entry of type agent. Has a dispose() to detach cleanly on module teardown
agentDashboard(opts?)functionThe "Agent" dashboard definition (panels wired to the data providers, paginated list tables — see below)
agentRunsProvider, agentTokensProvider, agentToolStatusProviderdata providersLive activity panels, sourced from watcher-recorded entries
agentSpendTotalProvider, agentTokensTotalProvider, agentSpendByModelProvider, agentModelSpendTableProvider, agentSpendByActorProvider, agentActorSpendTableProvider, agentUsageTrendProvider, agentTopThreadsTableProviderdata providersSpend/usage governance panels, sourced from AGENT_GOVERNANCE_QUERIES
agentRunsTotalProvider, agentRunsSuccessRateProvider, agentRunsFailedProvider, agentRunsRetriesProvider, agentRunsDurationProvider, agentRunsByAgentTableProvider, agentRunErrorsProvider, agentRunsTrendProvider, agentRecentRunsTableProviderdata providersReliability governance panels (success/error rate, p50/p95 duration, failure breakdown, recent runs)
agentRecentToolCallsTableProvider, agentToolStatsTableProviderdata providersTool governance panels (recent calls, per-tool calls/failed/rejected + p95 executionMs)
agentRecentThreadsTableProvider, agentPendingApprovalsCountProvider, agentPendingApprovalsTableProviderdata providersRecent threads and the HITL approvals inbox (count + table)
agentRunsPagedTableProvider, agentToolCallsPagedTableProvider, agentThreadsPagedTableProviderdata providersPaginated runs/tool-calls/threads tables (reads AgentGovernanceQueries' runsPage/toolCallsPage/threadsPage), backing the Agent tab's prev/next tables — requires @dudousxd/nestjs-telescope >=1.18 for the renderer's paged: true support
resolveRange, shiftUtcDayfunctionsRange/day-bucketing helpers shared by the governance providers
toActorSpendRows, toActorSpendSegments, toModelSpendRows, toModelSpendSegments, totalCostUsd, totalTokens, toUsageTrendRowsfunctionsPure row/segment shaping helpers behind the governance panels

Automatic dedup with the generic diagnostics bridge

AgentTelescopeWatcher.register() claims every agent:* diagnostics key it records via @dudousxd/nestjs-diagnostics' claim registry (claimDiagnostics, diagnostics 0.7+) and releases the claim in dispose(). @dudousxd/nestjs-diagnostics-telescope's generic bridge checks the registry before recording a diagnostic entry, so it skips every key this watcher already owns — no hand-written exclude: [agentDiagnosticKey(...)] list needed to avoid double-recording the same event under two entry types.

Tracing

Every agent run also emits diagnostics spansllm.turn, tool.execution, retrieval, follow-ups (core's AGENT_SPAN_EVENTS) — correlated by traceId = runId. With a span-aware bridge these render in Telescope's TRACES tab as a nested waterfall for the run: one row per model call, tool execution, RAG retrieval, or follow-up-suggestions call, each with its duration and, on failure, an error phase. Span payloads are metadata-only (model id, token counts, tool name/type, step index) — never prompt or output text — and are emitted from inside the checkpointed step bodies, so a replayed (cached) step never re-emits its span.

Rendering requires:

  • @dudousxd/nestjs-agent-core >=0.7.0 (emits the spans; already satisfied by this package's peer).
  • @dudousxd/nestjs-diagnostics-telescope >=0.7 — the span-aware diagnostics bridge that turns :start/:end/:asyncStart/:asyncEnd/:error sub-channel traffic into Telescope spans.
  • @dudousxd/nestjs-telescope >=1.17 — the version that added explicit RecordInput.traceId support.

Without both bridge versions the spans are still emitted (cheaply — the phase envelopes are gated on subscriber presence) but simply go unobserved; nothing breaks. Once wired, a run/thread table's runId cell defaults to a #/traces/{runId} deep link into that waterfall (override via agentTelescopeExtension({ runHref }) if the host has its own run viewer).

Runs also show up in the Workflows tab, for free

Under the durable runner (AgentModule.forRoot({ durable: true })), each turn is a durable workflow, so it already appears in @dudousxd/nestjs-durable's Telescope "Workflows" tab with no extra wiring — the Agent tab's governance sections and the trace waterfall are additive, not a replacement. Since dispatchedSteps now defaults ON under durable: true, the llm.turn/tool.execution spans for a given run may originate from whichever worker actually executed that dispatched step, not necessarily the pod that started the run — the trace still stitches them together by traceId = runId.

Peer dependencies

@dudousxd/nestjs-telescope (>=1.18.0).

When to use it

Add this package once you're already running @dudousxd/nestjs-telescope and want agent runs, tool calls, and spend in the same console as your requests, queries, and jobs — no separate route to stand up. If you don't run Telescope, @dudousxd/nestjs-agent-dashboard gives you the same governance surfaces standalone (see Cost & Governance).

  • Cost & Governance — the ledger, the read-model, and surfacing it via dashboard or Telescope tab
  • Telescope docs — the extension mechanism, watchers, and the console itself

On this page