@dudousxd/nestjs-agent-core 0.11.0 → 0.12.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.
- package/dist/index.cjs +73 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -3
- package/dist/index.d.ts +93 -3
- package/dist/index.js +68 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tokens.ts","../src/spi/token-stream-sink.ts","../src/stream-events.ts","../src/spi/pricing-store.ts","../src/spi/governance-queries.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.ts","../src/tool-retry.ts"],"sourcesContent":["/**\n * Public, cross-lib-discoverable DI tokens.\n *\n * These use `Symbol.for(...)` (the global symbol registry) on purpose: pnpm peer\n * multiplexing + dual ESM/CJS can load `core` more than once, and a plain `Symbol()`\n * would mint a distinct token per copy and break DI across package boundaries. A\n * registered symbol collapses every copy onto the same token, and lets a sibling lib\n * resolve our injectables by name without importing our internals.\n *\n * Naming convention (ecosystem-wide): `@dudousxd/nestjs-<lib>:<name>`.\n */\nexport const AGENT_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:options');\nexport const AGENT_STORE = Symbol.for('@dudousxd/nestjs-agent:store');\nexport const AGENT_RUNNER = Symbol.for('@dudousxd/nestjs-agent:runner');\n/**\n * The durable runner, provided ONLY by `AgentDurableModule`. When `durable: true`, the module\n * binds `AGENT_RUNNER` to this via an optional injection, so a missing `AgentDurableModule`\n * fails with a clear error instead of a cryptic unresolved-dependency one.\n */\nexport const AGENT_DURABLE_RUNNER = Symbol.for('@dudousxd/nestjs-agent:durable-runner');\nexport const AGENT_SINK = Symbol.for('@dudousxd/nestjs-agent:sink');\nexport const AGENT_MODEL = Symbol.for('@dudousxd/nestjs-agent:model');\nexport const AGENT_ROLES_POLICY = Symbol.for('@dudousxd/nestjs-agent:roles-policy');\nexport const AGENT_QUOTA_STORE = Symbol.for('@dudousxd/nestjs-agent:quota-store');\nexport const AGENT_TOOL_REGISTRY = Symbol.for('@dudousxd/nestjs-agent:tool-registry');\nexport const AGENT_REGISTRY = Symbol.for('@dudousxd/nestjs-agent:agent-registry');\nexport const AGENT_ACTOR_RESOLVER = Symbol.for('@dudousxd/nestjs-agent:actor-resolver');\n/** The governance read-model (usage/spend/threads), consumed by the dashboard + telescope surfaces. */\nexport const AGENT_GOVERNANCE_QUERIES = Symbol.for('@dudousxd/nestjs-agent:governance-queries');\n/** The pricing WRITE side (`AgentPricingStore`) — seeds/updates the per-model rates cost is priced against. */\nexport const AGENT_PRICING_STORE = Symbol.for('@dudousxd/nestjs-agent:pricing-store');\n/** The RAG retrieval seam (`Retriever`) — vector/keyword search behind the agentic tool or inject mode. */\nexport const AGENT_RETRIEVER = Symbol.for('@dudousxd/nestjs-agent:retriever');\n/** The embedding provider (`EmbeddingProvider`) — text→vector for retrieval + ingestion. */\nexport const AGENT_EMBEDDING_PROVIDER = Symbol.for('@dudousxd/nestjs-agent:embedding-provider');\n// Per-agent deps factory. A Symbol.for token (not the class) so DI survives tsup's dual\n// index/durable bundles, which each get their own copy of the AgentDepsFactory class.\nexport const AGENT_DEPS_FACTORY = Symbol.for('@dudousxd/nestjs-agent:deps-factory');\n/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */\nexport const AGENT_PROMPT_CONTRIBUTORS = Symbol.for('@dudousxd/nestjs-agent:prompt-contributors');\n/**\n * Resolves opaque store `actorRef`s to human display labels for governance/dashboard read surfaces.\n * Optional — see {@link import('./spi/actor-directory.js').ActorDirectory}.\n */\nexport const AGENT_ACTOR_DIRECTORY = Symbol.for('@dudousxd/nestjs-agent:actor-directory');\n/**\n * Persists an uploaded attachment somewhere the model can fetch it from and returns a\n * `MessageAttachment`. Optional — see\n * {@link import('./spi/attachment-staging.js').AttachmentStagingStore}.\n */\nexport const AGENT_ATTACHMENT_STAGING = Symbol.for('@dudousxd/nestjs-agent:attachment-staging');\n/**\n * Console-side HITL approve/reject for the cross-thread approvals inbox. Optional — see\n * {@link import('./spi/approval-port.js').AgentApprovalPort}.\n */\nexport const AGENT_APPROVAL_PORT = Symbol.for('@dudousxd/nestjs-agent:approval-port');\n","/**\n * The \"data plane\": live token transport, decoupled from the durable control plane.\n *\n * The model turn writes deltas to a `SinkWriter` keyed by runId; the HTTP layer\n * `subscribe`s by runId and pipes the chunks to the browser as SSE. A late subscriber\n * (reconnect/resume) replays buffered chunks first, then follows live — which is what\n * makes streaming survive a dropped connection or a pod restart.\n */\nexport interface SinkWriter {\n write(chunk: Uint8Array): void | Promise<void>;\n /** Mark the run's stream finished (no more chunks). */\n end(): void | Promise<void>;\n /**\n * Terminate the run's stream with an error instead of a normal end. Subscribers replay any\n * buffered chunks first, then throw an {@link AgentStreamError} carrying this `code`/`message`\n * — so the transport can surface a typed failure frame instead of leaking it as assistant text.\n */\n fail(error: StreamError): void | Promise<void>;\n}\n\n/** A machine-readable stream failure. `code` is a stable slug; `message` is human-facing. */\nexport interface StreamError {\n code: string;\n message: string;\n}\n\n/**\n * Thrown out of {@link TokenStreamSink.subscribe} when a run ended via {@link SinkWriter.fail}.\n * Carries the structured {@link StreamError} so the HTTP layer can emit an `event: error` frame.\n */\nexport class AgentStreamError extends Error {\n readonly code: string;\n constructor(error: StreamError) {\n super(error.message);\n this.name = 'AgentStreamError';\n this.code = error.code;\n }\n}\n\nexport interface TokenStreamSink {\n /** Open (or reopen) the writer for a run. */\n open(runId: string): SinkWriter | Promise<SinkWriter>;\n /**\n * Replay buffered chunks for the run, then yield live ones until `end()`. Throws\n * {@link AgentStreamError} if the run was terminated with {@link SinkWriter.fail}.\n */\n subscribe(runId: string): AsyncIterable<Uint8Array>;\n /** Drop any buffer/resources for the run. */\n close(runId: string): void | Promise<void>;\n}\n","/**\n * The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.\n *\n * The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one\n * `JSON.stringify(event)\\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an\n * SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk\n * protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same\n * rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the\n * client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).\n *\n * Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:\n * the adapter owns model-parts → event, the transport owns event → UI-chunk.\n */\nimport type { MessageUsage } from './types.js';\n\nexport type AgentStreamEvent =\n | { kind: 'step-start' }\n /**\n * Closes the step opened by the matching `step-start`. Carries the model call's token usage and\n * `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a\n * fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.\n */\n | { kind: 'step-finish'; usage?: MessageUsage; costUsd?: number | null }\n | { kind: 'text'; text: string }\n | { kind: 'reasoning'; text: string }\n /** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */\n | { kind: 'tool-input-start'; id: string; name: string; toolKind: 'read' | 'action' }\n | { kind: 'tool-input-delta'; id: string; delta: string }\n | {\n kind: 'tool-input-available';\n id: string;\n name: string;\n input: unknown;\n toolKind: 'read' | 'action';\n }\n | { kind: 'tool-output'; id: string; output: unknown }\n | { kind: 'tool-output-error'; id: string; error: string };\n\nconst encoder = new TextEncoder();\n\n/** Encode one event as an NDJSON line (`{...}\\n`) for {@link SinkWriter.write}. */\nexport function encodeStreamEvent(event: AgentStreamEvent): Uint8Array {\n return encoder.encode(`${JSON.stringify(event)}\\n`);\n}\n","/**\n * The WRITE side of the pricing table the {@link import('./governance-queries.js').AgentGovernanceQueries}\n * read-model prices usage against. Cost is $0 for an unpriced model, so an app seeds its models'\n * per-1M rates once (and re-`upsert`s when a provider changes prices). A store adapter implements\n * this; consumers inject via `AGENT_PRICING_STORE`. Use `seedModelPrices` for a one-shot batch.\n */\n\n/** A per-1M-token price for one model. Cache rates fall back to the input rate when omitted. */\nexport interface ModelPriceInput {\n modelId: string;\n inputPricePer1m: number;\n outputPricePer1m: number;\n /** Per-1M price for cache-write (prompt-cache) input tokens. Omit → priced at the input rate. */\n cacheWritePricePer1m?: number;\n /** Per-1M price for cache-read (prompt-cache) input tokens. Omit → priced at the input rate. */\n cacheReadPricePer1m?: number;\n}\n\n/** A current price row as read back, with the timestamp it took effect. */\nexport interface CurrentModelPrice extends ModelPriceInput {\n effectiveFrom: string;\n}\n\nexport interface AgentPricingStore {\n /**\n * Set the current price for a model. Atomic supersede: the model's prior `isCurrent` row (if any)\n * is retired and this one is inserted as current, effective now — so the read-model always joins\n * to exactly one live price per model, with no window where two rows race for `isCurrent`.\n */\n upsertModelPrice(input: ModelPriceInput): Promise<void>;\n /** The current price row per model (`isCurrent`), for a pricing admin view. */\n listCurrentPrices(): Promise<CurrentModelPrice[]>;\n}\n\n/** Seed (or refresh) a batch of model prices — one `upsertModelPrice` per row, in order. */\nexport async function seedModelPrices(\n store: AgentPricingStore,\n prices: ModelPriceInput[],\n): Promise<void> {\n for (const price of prices) {\n await store.upsertModelPrice(price);\n }\n}\n","/**\n * A read-model over the persisted agent data (usage ⋈ pricing, tool calls, threads) for the\n * governance surfaces — the standalone `-dashboard` SPA and the `-telescope` \"Agent\" tab both\n * consume this ONE interface, so cost/usage aggregation lives in a single place.\n *\n * Separate from {@link AgentStore} on purpose: that SPI owns the write/thread path, this owns the\n * read/analytics path. A store adapter implements both. Consumers inject via\n * `AGENT_GOVERNANCE_QUERIES`.\n *\n * Live activity (in-flight runs, streaming tool calls, delegations, forbidden attempts) is NOT here\n * — that comes off the `aviary:agent:*` diagnostics channel. This interface is the durable, restart-\n * surviving history.\n */\n\n/** Inclusive UTC day range, each `YYYY-MM-DD`. */\nexport interface GovernanceRange {\n fromDay: string;\n toDay: string;\n}\n\n/** Spend + token totals for one model over a range. */\nexport interface ModelSpendRow {\n modelId: string;\n requests: number;\n inputTokens: number;\n outputTokens: number;\n costUsd: number;\n}\n\n/** Spend + token totals for one acting ref (user/tenant) over a range. */\nexport interface ActorSpendRow {\n actorRef: string;\n requests: number;\n totalTokens: number;\n costUsd: number;\n /** Distinct threads the actor used in the range. */\n threadCount: number;\n}\n\n/** Spend + token totals for one thread over a range. */\nexport interface ThreadSpendRow {\n threadId: string;\n title: string;\n actorRef: string;\n requests: number;\n totalTokens: number;\n costUsd: number;\n}\n\n/** One point on the daily usage/cost trend. */\nexport interface UsageTrendPoint {\n day: string;\n totalTokens: number;\n costUsd: number;\n}\n\n/** A recent tool-call for the activity feed. */\nexport interface ToolCallActivityRow {\n toolCallId: string;\n toolName: string;\n toolType: string;\n status: string;\n threadId: string;\n createdAt: string;\n /** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */\n runId: string | null;\n}\n\n/** A recent thread with rolled-up activity. */\nexport interface ThreadActivityRow {\n threadId: string;\n title: string;\n actorRef: string;\n messageCount: number;\n totalTokens: number;\n lastActivityAt: string;\n}\n\n/** Aggregated run reliability over a range. */\nexport interface RunMetrics {\n runs: number;\n completed: number;\n failed: number;\n /** completed / runs, 0 when runs = 0. */\n successRate: number;\n /** Total llm-step retries across the range's runs. */\n retries: number;\n durationP50Ms: number | null;\n durationP95Ms: number | null;\n}\n\n/** Run/failure/retry rollup for one agent over a range. */\nexport interface RunAgentBreakdownRow {\n /** '(default)' when the run had none. */\n agentName: string;\n runs: number;\n failed: number;\n retries: number;\n}\n\n/** Failed-run count for one error code over a range. */\nexport interface RunErrorBreakdownRow {\n errorCode: string;\n count: number;\n}\n\n/** One point on the daily run/failure trend. */\nexport interface RunTrendPoint {\n day: string;\n runs: number;\n failed: number;\n}\n\n/** A recent run for the reliability feed. */\nexport interface RecentRunRow {\n runId: string;\n threadId: string;\n actorRef: string;\n agentName: string | null;\n /** 'running' | 'completed' | 'failed'. */\n status: string;\n durationMs: number | null;\n errorCode: string | null;\n errorMessage: string | null;\n retries: number;\n /** ISO timestamp. */\n startedAt: string;\n /** sha256 hex of the run's resolved (pre-RAG) system prompt; `null` for a run recorded before this shipped. */\n promptHash: string | null;\n}\n\n/** One tool call awaiting a HITL decision, for the cross-thread approvals inbox. */\nexport interface PendingApprovalRow {\n toolCallId: string;\n toolName: string;\n input: unknown;\n threadId: string;\n threadTitle: string;\n /** Who asked — the run's actor. */\n actorRef: string;\n agentName: string | null;\n /** ISO timestamp. */\n requestedAt: string;\n /** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */\n runId: string | null;\n}\n\n/** Governance rollup for one tool over a range. */\nexport interface ToolStatRow {\n toolName: string;\n toolType: string;\n calls: number;\n failed: number;\n rejected: number;\n /**\n * p50 (median) of executionMs across calls that recorded one; null when none carry it. Reported\n * alongside p95 rather than a mean: tool latency is long-tailed (a retry or a slow upstream drags\n * an average somewhere no single call ever was), so the pair \"typical / tail\" is what an operator\n * can actually act on.\n */\n p50ExecutionMs: number | null;\n /** p95 of executionMs across executed calls; null when none carry it. */\n p95ExecutionMs: number | null;\n}\n\n/**\n * Neutral paged query for the governance list reads (`toolCallsPage`/`threadsPage`/`runsPage`). The\n * WIRE format a host exposes over HTTP mirrors `@dudousxd/nestjs-filter`'s conventions (`page`,\n * `limit`, `where[field][op]`) so consumers see one grammar across the ecosystem, but this SPI stays\n * neutral/typed — no filter-builder or ORM coupling here.\n */\nexport interface GovernancePageQuery<TWhere> {\n /** 1-based. */\n page: number;\n /** Rows per page, already clamped by the caller (the dashboard clamps to 200). */\n pageSize: number;\n /** Equality/range filters; absent field = no constraint. */\n where?: TWhere;\n}\n\n/** One page of a governance list read, with the total row count for prev/next + \"page X of Y\" UI. */\nexport interface GovernancePage<TRow> {\n rows: TRow[];\n total: number;\n page: number;\n pageSize: number;\n}\n\n/** Filters for {@link AgentGovernanceQueries.toolCallsPage}. */\nexport interface ToolCallWhere {\n toolName?: string;\n toolType?: string;\n status?: string;\n threadId?: string;\n /** Inclusive UTC day bounds, `YYYY-MM-DD`. */\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.threadsPage}. */\nexport interface ThreadWhere {\n actorRef?: string;\n /** Substring match on the title (case-insensitive). */\n title?: string;\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.runsPage}. */\nexport interface RunWhere {\n agentName?: string;\n status?: string;\n errorCode?: string;\n threadId?: string;\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.approvalsPage}. */\nexport interface ApprovalWhere {\n toolName?: string;\n threadId?: string;\n /** The requesting thread's owner. */\n actorRef?: string;\n agentName?: string;\n /** Inclusive UTC day bounds on when the approval was requested, `YYYY-MM-DD`. */\n fromDay?: string;\n toDay?: string;\n}\n\n// ─── Drill-down details ──────────────────────────────────────────────────────\n//\n// The list reads above answer \"what happened\"; these two answer \"what happened HERE\". Each is ONE\n// call returning everything the corresponding drill-down renders, so a console never fans out a\n// query per row it just drew. Both return `null` for an id that doesn't exist — the caller decides\n// whether that's a 404 or an empty panel.\n\n/** One tool call inside a {@link GovernanceRunDetail}, with the execution outcome a list row can't afford to carry. */\nexport interface RunToolCallRow {\n toolCallId: string;\n toolName: string;\n toolType: string;\n status: string;\n /** Wall time of the execution; null for a call that never executed (rejected/still pending). */\n executionMs: number | null;\n /** Who executed/decided it, when the store recorded an attribution. */\n executedByRef: string | null;\n /** The failure text for a `failed` call; null otherwise. */\n error: string | null;\n /** ISO timestamp. */\n createdAt: string;\n}\n\n/** The owning thread's headline, carried on a drill-down so it can be named without a second read. */\nexport interface DetailThreadRef {\n threadId: string;\n title: string;\n actorRef: string;\n /** True when the thread is soft-deleted — its history is still readable, the thread is not. */\n deleted: boolean;\n}\n\n/**\n * Everything a run drill-down renders: the run row itself, its owning thread's headline, and the\n * tool calls attributed to it.\n *\n * `toolCalls` is empty for a run recorded before tool calls carried a `runId` (the column is\n * nullable and pre-rollout rows have none) — indistinguishable, from here, from a run that called\n * no tools. There is deliberately no cost figure: the token ledger has no run column, so per-run\n * spend is not attributable without a store migration.\n */\nexport interface GovernanceRunDetail {\n run: RecentRunRow;\n thread: DetailThreadRef;\n /** The run's tool calls, oldest first — the order they were requested in. */\n toolCalls: RunToolCallRow[];\n}\n\n/** One message inside a {@link GovernanceThreadDetail}. `content` is capped server-side. */\nexport interface ThreadMessageRow {\n messageId: string;\n role: string;\n /** Message text, cut to {@link THREAD_DETAIL_CONTENT_CHARS}; see `truncated`. */\n content: string;\n /** True when `content` was cut — the console shows an explicit \"…\" rather than implying the tail. */\n truncated: boolean;\n agentName: string | null;\n /** How many tool calls this message requested. */\n toolCallCount: number;\n /** ISO timestamp. */\n createdAt: string;\n}\n\n/** Token/cost rollup across a thread's whole ledger (not range-scoped — a thread's lifetime). */\nexport interface ThreadUsageRollup {\n /** Ledger rows, i.e. billed turns. */\n requests: number;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n costUsd: number;\n}\n\n/** Everything a thread drill-down renders, in one call. */\nexport interface GovernanceThreadDetail {\n /** The thread's own activity row (`messageCount` is the thread total, not the page below). */\n thread: ThreadActivityRow;\n /** True when the thread is soft-deleted. */\n deleted: boolean;\n usage: ThreadUsageRollup;\n /** The thread's runs, newest first, capped at the query's `runLimit`. */\n runs: RecentRunRow[];\n /** Runs on this thread in total — `runs.length < runTotal` means the cap bit. */\n runTotal: number;\n /** The thread's messages, newest first, capped at the query's `messageLimit`. */\n messages: ThreadMessageRow[];\n}\n\n/** Row caps for {@link AgentGovernanceQueries.threadDetail}, already clamped by the caller. */\nexport interface GovernanceThreadDetailQuery {\n threadId: string;\n /** Max messages returned, newest first. */\n messageLimit: number;\n /** Max runs returned, newest first. */\n runLimit: number;\n}\n\n/**\n * Per-message content cap for {@link ThreadMessageRow.content}. A drill-down is a triage view, not a\n * transcript reader: capping here keeps one response bounded regardless of how long an assistant\n * turn ran. Shared by every adapter so the cut is identical wherever the console is served from.\n */\nexport const THREAD_DETAIL_CONTENT_CHARS = 2000;\n\n/**\n * Cut a message body to {@link THREAD_DETAIL_CONTENT_CHARS}, reporting whether it was cut. Lives\n * next to the cap so every adapter truncates at the same boundary — a console comparing two stores\n * must not see two different \"…\".\n */\nexport function truncateDetailContent(content: string): {\n content: string;\n truncated: boolean;\n} {\n if (content.length <= THREAD_DETAIL_CONTENT_CHARS) {\n return { content, truncated: false };\n }\n return { content: content.slice(0, THREAD_DETAIL_CONTENT_CHARS), truncated: true };\n}\n\n/**\n * The governance read-model. Cost is `inputTokens/1e6 * inputPricePer1m + outputTokens/1e6 *\n * outputPricePer1m` against the current pricing row per model; an unpriced model contributes 0 cost\n * (its tokens still count).\n */\nexport interface AgentGovernanceQueries {\n spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]>;\n spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]>;\n /** Top threads by spend within the range, highest cost first, capped at `limit`. */\n spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]>;\n usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;\n recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;\n recentThreads(limit: number): Promise<ThreadActivityRow[]>;\n // Run reliability. An adapter backed by a store without run recording (no `recordRunStart`)\n // returns zeros/empty from all five (plus `runsPage`, below) — the dashboard renders an empty\n // reliability surface.\n runMetrics(range: GovernanceRange): Promise<RunMetrics>;\n runsByAgent(range: GovernanceRange): Promise<RunAgentBreakdownRow[]>;\n runErrors(range: GovernanceRange): Promise<RunErrorBreakdownRow[]>;\n runTrend(range: GovernanceRange): Promise<RunTrendPoint[]>;\n recentRuns(limit: number): Promise<RecentRunRow[]>;\n /**\n * Tool calls sitting `pending_approval`, oldest first — an inbox drains from the back. Capped at\n * `limit`, with NO total: a caller that needs to know whether the cap hid anything wants\n * {@link approvalsPage} instead.\n */\n pendingApprovals(limit: number): Promise<PendingApprovalRow[]>;\n /**\n * Paged, filterable approvals inbox, oldest first (same ordering as `pendingApprovals`). Unlike\n * that method this reports `total`, so a console can page a backlog and say how much of it is\n * off-screen — the one failure this surface cannot afford is a pending approval nobody sees.\n * An adapter without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n approvalsPage(\n query: GovernancePageQuery<ApprovalWhere>,\n ): Promise<GovernancePage<PendingApprovalRow>>;\n /** Per-tool call/failure/rejection/latency rollup over the range, highest call count first. */\n toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;\n /**\n * Paged, filterable tool-call activity, newest-first (same ordering as `recentToolCalls`). An\n * adapter without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n toolCallsPage(\n query: GovernancePageQuery<ToolCallWhere>,\n ): Promise<GovernancePage<ToolCallActivityRow>>;\n /**\n * Paged, filterable thread activity, newest-first (same ordering as `recentThreads`). An adapter\n * without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n threadsPage(query: GovernancePageQuery<ThreadWhere>): Promise<GovernancePage<ThreadActivityRow>>;\n /**\n * Paged, filterable run activity, newest-first (same ordering as `recentRuns`). An adapter backed\n * by a store without run recording (no `recordRunStart`) returns an empty page (`total: 0`).\n */\n runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;\n /**\n * One run with its owning thread and its tool calls — the drill-down behind a row in the runs\n * table. `null` when no run has that id. ONE call, not one per tool call: a failed run is the\n * thing an operator opens first and it should not cost a query per step.\n *\n * An adapter backed by a store without run recording returns `null` for every id.\n */\n runDetail(runId: string): Promise<GovernanceRunDetail | null>;\n /**\n * One thread with its lifetime usage rollup, its recent runs and its recent messages — the\n * drill-down behind a row in the threads table. `null` when no thread has that id; a soft-deleted\n * thread IS returned (with `deleted: true`), because \"what did the thread we just deleted do\" is\n * exactly the question an audit asks.\n */\n threadDetail(query: GovernanceThreadDetailQuery): Promise<GovernanceThreadDetail | null>;\n}\n","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\n ThreadUsageRollup,\n UsageTrendPoint,\n} from '../spi/governance-queries.js';\n\n/**\n * The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}\n * adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the\n * cost formula, the group→sort bucketing, and the day-bounds math live here so all three surfaces\n * report identical numbers.\n */\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\nexport interface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/** The token split of one turn needed to estimate its cost. */\nexport interface CostUsage {\n inputTokens: number;\n outputTokens: number;\n cacheWriteTokens?: number | null | undefined;\n cacheReadTokens?: number | null | undefined;\n}\n\n/**\n * A normalized usage row the bucketers consume. Each adapter maps its raw DB row into this shape\n * (MikroORM reads `thread.id` + `createdAt`, Drizzle/in-memory read the flat `threadId` + `day`).\n */\nexport interface GovernanceUsageInput extends CostUsage {\n modelId: string;\n actorRef: string;\n threadId: string;\n /** The `YYYY-MM-DD` UTC day the row belongs to (its trend bucket). */\n day: string;\n /** Provider-reported spend for the row; wins over the token estimate when present. */\n costUsd?: number | null | undefined;\n}\n\n/** Thread metadata joined onto a spend bucket. */\nexport interface ThreadMeta {\n title: string;\n actorRef: string;\n}\n\n/**\n * Token-ledger estimate for one turn against a pricing row: the uncached input at the input rate,\n * cache-write/cache-read tokens at their own rates (falling back to the input rate when unpriced),\n * plus output at the output rate. An unpriced model (`price === undefined`) contributes 0 — its\n * tokens still count. Cache token counts are subsets of `inputTokens`, so the uncached remainder is\n * the difference.\n */\nexport function estimateCost(usage: CostUsage, price: ModelPrice | undefined): number {\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = usage.cacheWriteTokens ?? 0;\n const cacheReadTokens = usage.cacheReadTokens ?? 0;\n const uncachedInputTokens = usage.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (usage.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/** Provider-reported cost wins per row; otherwise the cache-aware token estimate. */\nfunction rowCost(row: GovernanceUsageInput, prices: ReadonlyMap<string, ModelPrice>): number {\n return row.costUsd ?? estimateCost(row, prices.get(row.modelId));\n}\n\n/** Aggregate usage rows into per-model spend, highest cost first then modelId ascending. */\nexport function bucketByModel(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ModelSpendRow[] {\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n}\n\n/** Aggregate usage rows into per-actor spend (with distinct thread counts), highest cost first. */\nexport function bucketByActor(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ActorSpendRow[] {\n const byActor = new Map<\n string,\n { requests: number; totalTokens: number; costUsd: number; threadIds: Set<string> }\n >();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? {\n requests: 0,\n totalTokens: 0,\n costUsd: 0,\n threadIds: new Set<string>(),\n };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n bucket.threadIds.add(row.threadId);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n threadCount: bucket.threadIds.size,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n}\n\n/**\n * Aggregate usage rows into per-thread spend, highest cost first then threadId ascending, capped at\n * `limit`. A thread absent from `threads` is dropped when `includeUnknownThreads` is false (the SQL\n * adapters fetch only non-deleted threads, so a soft-deleted thread's rows vanish from the ranking);\n * when true it is kept with blank title/actor (the in-memory adapter's semantics).\n */\nexport function bucketByThread(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n threads: ReadonlyMap<string, ThreadMeta>,\n options: { limit: number; includeUnknownThreads: boolean },\n): ThreadSpendRow[] {\n const byThread = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byThread.get(row.threadId) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byThread.set(row.threadId, bucket);\n }\n const result: ThreadSpendRow[] = [];\n for (const [threadId, bucket] of byThread) {\n const thread = threads.get(threadId);\n if (thread === undefined && !options.includeUnknownThreads) {\n continue;\n }\n result.push({\n threadId,\n title: thread?.title ?? '',\n actorRef: thread?.actorRef ?? '',\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId),\n );\n return result.slice(0, options.limit);\n}\n\n/**\n * Sum an already-scoped set of usage rows into one rollup — the thread drill-down's headline. Same\n * `rowCost` as every bucketer above (provider-reported cost wins, else the cache-aware estimate), so\n * a thread's detail cost and its row in the by-thread ranking can never disagree.\n */\nexport function rollupThreadUsage(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ThreadUsageRollup {\n const rollup: ThreadUsageRollup = {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n costUsd: 0,\n };\n for (const row of rows) {\n rollup.requests += 1;\n rollup.inputTokens += row.inputTokens;\n rollup.outputTokens += row.outputTokens;\n rollup.totalTokens += row.inputTokens + row.outputTokens;\n rollup.costUsd += rowCost(row, prices);\n }\n return rollup;\n}\n\n/** Aggregate usage rows into a daily token/cost trend, ascending by day. */\nexport function bucketUsageTrend(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): UsageTrendPoint[] {\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byDay.get(row.day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byDay.set(row.day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n}\n\n/** Turn an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used to filter usage rows. */\nexport function dayBoundsUtc(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n","import type { RolesPolicy } from './spi/roles-policy.js';\nimport type { Actor, ToolSpec } from './types.js';\n\n/** First filter layer: drop tools the actor's role may not invoke. `can` may be async (authz). */\nexport async function filterToolsByRole(\n tools: ToolSpec[],\n actor: Actor,\n policy: RolesPolicy,\n): Promise<ToolSpec[]> {\n const checked = await Promise.all(\n tools.map(async (tool) => ({ tool, allowed: await policy.can(actor, tool) })),\n );\n return checked.filter((entry) => entry.allowed).map((entry) => entry.tool);\n}\n\n/** Second filter layer: if the agent pins an allow-list, keep only those tool names. */\nexport function filterToolsByAllowList(\n tools: ToolSpec[],\n allowedTools: string[] | undefined,\n): ToolSpec[] {\n if (allowedTools === undefined) {\n return tools;\n }\n const allowed = new Set(allowedTools);\n return tools.filter((tool) => allowed.has(tool.name));\n}\n","import type { AgentDefinition } from './types.js';\n\n/** Holds the named agent definitions registered via `AgentModule.forFeature([...])`. */\nexport class AgentRegistry {\n private readonly definitions = new Map<string, AgentDefinition>();\n\n register(definition: AgentDefinition): void {\n this.definitions.set(definition.name, definition);\n }\n\n get(name: string): AgentDefinition | undefined {\n return this.definitions.get(name);\n }\n\n has(name: string): boolean {\n return this.definitions.has(name);\n }\n\n list(): AgentDefinition[] {\n return [...this.definitions.values()];\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { RolesPolicy } from './spi/roles-policy.js';\nimport type { AiToolCtx, ToolHandler } from './spi/tool.js';\nimport { filterToolsByAllowList, filterToolsByRole } from './tool-filters.js';\nimport type { Actor, ToolDefinition, ToolSpec } from './types.js';\n\n/** Thrown when an actor invokes a tool their role is not allowed. */\nexport class ToolForbiddenError extends Error {\n constructor(public readonly toolName: string) {\n super(`Tool \"${toolName}\" is not allowed for this role`);\n this.name = 'ToolForbiddenError';\n }\n}\n\n/** Thrown when a tool is invoked that was never registered. */\nexport class ToolNotFoundError extends Error {\n constructor(public readonly toolName: string) {\n super(`Tool \"${toolName}\" is not registered`);\n this.name = 'ToolNotFoundError';\n }\n}\n\n/** Thrown when a tool's input fails its Standard Schema validation. */\nexport class ToolInputInvalidError extends Error {\n constructor(\n public readonly toolName: string,\n public readonly issues: readonly StandardSchemaV1.Issue[],\n ) {\n super(\n `Invalid input for tool \"${toolName}\": ${issues.map((issue) => issue.message).join('; ')}`,\n );\n this.name = 'ToolInputInvalidError';\n }\n}\n\ninterface Entry {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/**\n * Holds every registered tool and gates invocation.\n *\n * Note: `definitionsFor` returns NEUTRAL definitions (no `execute`). The agent loop runs\n * each tool itself as a (durable) step — so even read tools are not auto-executed by the\n * model. `action` tools additionally require HITL approval before the loop runs them.\n */\nexport class ToolRegistry {\n private readonly entries = new Map<string, Entry>();\n\n register(spec: ToolSpec, handler: ToolHandler): void {\n this.entries.set(spec.name, { spec, handler });\n }\n\n has(name: string): boolean {\n return this.entries.has(name);\n }\n\n spec(name: string): ToolSpec | undefined {\n return this.entries.get(name)?.spec;\n }\n\n allSpecs(): ToolSpec[] {\n return [...this.entries.values()].map((entry) => entry.spec);\n }\n\n /** The tools to offer the model for this actor+agent, after the two filter layers. */\n async definitionsFor(\n actor: Actor,\n policy: RolesPolicy,\n allowedTools?: string[],\n ): Promise<ToolDefinition[]> {\n const roleScoped = await filterToolsByRole(this.allSpecs(), actor, policy);\n const allowScoped = filterToolsByAllowList(roleScoped, allowedTools);\n return allowScoped.map((spec) => ({\n name: spec.name,\n kind: spec.kind,\n description: spec.description,\n inputSchema: spec.inputSchema,\n }));\n }\n\n /** Run a tool. Re-checks the role (defense-in-depth) and re-parses the input via Zod. */\n async invoke(\n name: string,\n input: unknown,\n ctx: AiToolCtx,\n policy: RolesPolicy,\n ): Promise<unknown> {\n const entry = this.entries.get(name);\n if (entry === undefined) {\n throw new ToolNotFoundError(name);\n }\n if (!(await policy.can(ctx.actor, entry.spec))) {\n throw new ToolForbiddenError(name);\n }\n const validation = await entry.spec.inputSchema['~standard'].validate(input);\n if (validation.issues !== undefined) {\n throw new ToolInputInvalidError(name, validation.issues);\n }\n return entry.handler.execute(validation.value, ctx);\n }\n}\n\n/** Default gate: one of the actor's roles must be in spec.roles (defaulting to ADMIN-only). */\nexport class DefaultRolesPolicy implements RolesPolicy {\n constructor(private readonly defaultRoles: string[] = ['ADMIN']) {}\n\n can(actor: Actor, tool: ToolSpec): boolean {\n const allowed = tool.roles ?? this.defaultRoles;\n return (actor.roles ?? []).some((role) => allowed.includes(role));\n }\n}\n","import { createHash } from 'node:crypto';\nimport { trace } from '@dudousxd/nestjs-diagnostics';\nimport type { PayloadOf } from '@dudousxd/nestjs-diagnostics';\nimport {\n type AgentSpanEvent,\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n publishAgentToolRetry,\n} from './diagnostics.js';\nimport { estimateCost } from './governance/compute.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider, ModelTurnResult } from './spi/model-provider.js';\nimport type { AgentPricingStore, CurrentModelPrice } from './spi/pricing-store.js';\nimport type { QuotaStore } from './spi/quota-store.js';\nimport type { Passage, Retriever } from './spi/retriever.js';\nimport type { RolesPolicy } from './spi/roles-policy.js';\nimport type { SinkWriter } from './spi/token-stream-sink.js';\nimport type { AiToolCtx } from './spi/tool.js';\nimport { encodeStreamEvent } from './stream-events.js';\nimport type { ToolRegistry } from './tool-registry.js';\nimport { invokeWithTransientRetry, resolveToolTransientRetryNumbers } from './tool-retry.js';\nimport type { ToolTransientRetrySetting } from './tool-retry.js';\nimport type {\n AgentRunInput,\n Decision,\n LlmStepEnvelope,\n MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\n ToolStepCtx,\n ToolStepEnvelope,\n} from './types.js';\n\nexport interface AgentLoopDeps {\n model: ModelProvider;\n store: AgentStore;\n registry: ToolRegistry;\n rolesPolicy: RolesPolicy;\n quota?: QuotaStore;\n /**\n * Fallback accounting label when the provider's turn result doesn't report a `modelId`.\n * Optional — a provider that reports its own model makes this unnecessary.\n */\n modelId?: string;\n /** Pre-computed (YYYY-MM-DD) so the loop body stays deterministic under durable replay. */\n day: string;\n /** The agent's base prompt. A flat string, or a {@link PromptBuilder} resolved per turn. */\n systemPrompt: string | PromptBuilder;\n /**\n * Cross-agent system-prompt contributors, applied in order AFTER the agent's base prompt. Each\n * returns a section to append (or `null` to skip this turn). The app registers them via\n * `@SystemPromptContributor()`; the loop composes base + contributors into the effective prompt.\n */\n promptContributors?: PromptContributor[];\n maxSteps?: number;\n /** Optional host handle threaded to tool ctx (e.g. an ORM EntityManager). */\n host?: unknown;\n /** Agent-level tool allow-list. Undefined → all tools (after role filtering). */\n toolAllowList?: string[];\n /**\n * Per-tool execution timeout in ms. A tool that runs longer is aborted and recorded as failed\n * (the model gets the timeout as its result and can adapt) rather than hanging the turn.\n * Undefined → no timeout.\n */\n toolTimeoutMs?: number;\n /**\n * Retries a tool's own invocation, in place, when it throws a classified-transient error (a DB\n * deadlock, a lock-wait timeout, a serialization failure — see `isTransientToolError`) — never a\n * new durable step/checkpoint, just repeated attempts inside the same `tool:<call.id>` step body.\n * Default ON (`{ attempts: 2, backoffMs: 150 }` with the default classifier) when undefined; set\n * `{ classify }` to widen/narrow which errors count as transient, or `false` to disable entirely.\n * A tool's other (non-transient) failures are unaffected — they remain a one-shot business\n * outcome, exactly as before.\n */\n toolTransientRetry?: ToolTransientRetrySetting;\n /**\n * When set, after the final turn the loop makes one extra model call to propose up to this many\n * short follow-up questions, stored on the assistant message's `followUps`. Costs an extra call\n * (recorded as `follow_ups` usage). Undefined/0 → disabled.\n */\n followUpsCount?: number;\n /**\n * Enables always-on (\"inject\") RAG: before the turn, retrieve passages for the user message and\n * augment the system prompt with them. Its presence IS inject mode — agentic (tool) retrieval sets\n * no retriever here (it rides a normal `read` tool). Undefined → no injection.\n */\n retriever?: Retriever;\n /** How many passages inject-mode retrieval requests. Undefined → 5. */\n retrievalTopK?: number;\n /**\n * Prices each step's token usage into `costUsd` (on the `step-finish` stream frame and the\n * persisted assistant message's `usage`). The current price list is fetched ONCE per run (not per\n * message/step) and reused for every step's estimate. Undefined → `costUsd` is always `null`.\n */\n pricingStore?: AgentPricingStore;\n}\n\n/**\n * A step's cost: the provider's own reported figure when it has one (a gateway), else an estimate\n * from `price` when the model has one, else `null` — never a fabricated `0` for \"we don't know\".\n */\nfunction resolveCostUsd(\n usage: MessageUsage,\n reportedCostUsd: number | undefined,\n price: CurrentModelPrice | undefined,\n): number | null {\n if (reportedCostUsd !== undefined) {\n return reportedCostUsd;\n }\n return price === undefined ? null : estimateCost(usage, price);\n}\n\n/** Renders retrieved passages as a numbered, citable context block for the system prompt. */\nfunction buildContextBlock(passages: Passage[]): string {\n const items = passages\n .map((passage, index) => {\n const label = passage.source !== undefined ? ` (${passage.source})` : '';\n return `[${index + 1}]${label} ${passage.text}`;\n })\n .join('\\n\\n');\n return `<retrieved_context>\\n${items}\\n</retrieved_context>\\nUse the retrieved context above to answer when relevant, and cite sources by their bracket number.`;\n}\n\nexport interface AgentLoopHooks {\n runId: string;\n /** A writer for this run's live token stream (data plane). */\n openSink(): SinkWriter | Promise<SinkWriter>;\n /** HITL gate for an action tool. Inline resolves a pending promise; durable awaits a signal. */\n awaitApproval(call: ToolCallRequest, ctx: AiToolCtx): Promise<Decision>;\n /**\n * Run another named agent and return its answer. Provided only when the host wired multi-agent\n * support (durable → child workflow, inline → nested loop). Exposed to tools as `ctx.runAgent`.\n */\n runAgent?(agentName: string, task: string): Promise<{ text: string }>;\n /**\n * Checkpoint wrapper. Inline = call fn directly; durable = ctx.localStep(name, fn) — the\n * in-process checkpointed primitive (`name` is a checkpoint identity, not a worker group).\n * EVERY side-effect and control-flow read goes through this so durable replay returns\n * cached results (stable ids, no double-write, no re-streaming).\n */\n step<T>(name: string, fn: () => Promise<T>): Promise<T>;\n /**\n * Dispatch the model turn as a routed remote step. When present the loop uses it INSTEAD of\n * running the model inline under hooks.step. Must resolve to exactly what deps.model.runTurn\n * resolves. The durable runner enriches the envelope with sink routing (sinkRunId/childSink)\n * on its side — core stays sink-topology-agnostic.\n */\n dispatchLlm?(index: number, envelope: LlmStepEnvelope): Promise<ModelTurnResult>;\n /**\n * Dispatch one tool execution as a routed remote step. Replaces ONLY the registry.invoke call\n * (+ its timeout, applied handler-side); all persist steps around it stay local.\n */\n dispatchTool?(call: ToolCallRequest, envelope: ToolStepEnvelope): Promise<unknown>;\n /**\n * Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so the loop\n * rethrows them untouched instead of recording a failure. Inline runners omit it — they have no\n * control-flow exceptions.\n */\n isControlFlowError?(error: unknown): boolean;\n}\n\nexport class QuotaExceededError extends Error {\n constructor() {\n super('Daily token quota exceeded');\n this.name = 'QuotaExceededError';\n }\n}\n\n/**\n * How deep agent→agent delegation may nest before the loop refuses further hops. A cap, not a\n * tuning knob: it stops a mis-wired `delegatesTo` cycle (A→B→A) from spawning runs unbounded.\n */\nexport const MAX_DELEGATION_DEPTH = 5;\n\n/** Resolve a prompt that may be a flat string or a {@link PromptBuilder}. */\nasync function resolvePrompt(prompt: string | PromptBuilder, ctx: PromptContext): Promise<string> {\n return typeof prompt === 'function' ? prompt(ctx) : prompt;\n}\n\n/**\n * The effective system prompt for a turn: the agent's own base prompt, then each cross-agent\n * contributor's section appended in order (skipping any that return `null`/empty this turn). This is\n * resolved from stable inputs (actor / agent / pageContext) once per turn; contributors should be\n * derived from those rather than from uncached I/O so it stays replay-safe.\n */\nasync function resolveSystemPrompt(deps: AgentLoopDeps, input: AgentRunInput): Promise<string> {\n const ctx: PromptContext = {\n actor: input.actor,\n agentName: input.agentName ?? 'default',\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n };\n const sections = [await resolvePrompt(deps.systemPrompt, ctx)];\n for (const contribute of deps.promptContributors ?? []) {\n const section = await contribute(ctx);\n if (section !== null && section.length > 0) {\n sections.push(section);\n }\n }\n return sections.join('\\n\\n');\n}\n\n/** An `agent`-kind tool's input is `{ task }` by convention; fall back to a JSON dump. */\nfunction extractTask(input: unknown): string {\n if (typeof input === 'object' && input !== null && 'task' in input) {\n const task = (input as { task: unknown }).task;\n if (typeof task === 'string') {\n return task;\n }\n }\n return JSON.stringify(input);\n}\n\nfunction deriveTitle(userText: string): string {\n const trimmed = userText.trim().replace(/\\s+/g, ' ');\n return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed || 'New chat';\n}\n\n/** Thrown when a tool exceeds `toolTimeoutMs`; caught by the loop and recorded as a failed call. */\nclass ToolTimeoutError extends Error {\n constructor(toolName: string, ms: number) {\n super(`Tool \"${toolName}\" exceeded its ${ms}ms timeout`);\n this.name = 'ToolTimeoutError';\n }\n}\n\n/** Reject if `work` doesn't settle within `ms`. The underlying work is left to finish on its own. */\nexport function withToolTimeout<T>(work: Promise<T>, ms: number, toolName: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);\n work.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\n/** Best-effort parse of the follow-ups model reply: a bare JSON array, tolerating code fences/prose. */\nfunction parseFollowUps(text: string, count: number): string[] {\n const source = text.match(/\\[[\\s\\S]*\\]/)?.[0] ?? text;\n try {\n const parsed: unknown = JSON.parse(source);\n if (Array.isArray(parsed)) {\n return parsed.filter((item): item is string => typeof item === 'string').slice(0, count);\n }\n } catch {\n /* not JSON — no follow-ups this turn */\n }\n return [];\n}\n\n/**\n * One extra, non-streamed model call that proposes short follow-up questions. Writes to a discarding\n * sink so its tokens never reach the user's live stream; the reply is parsed as a JSON string array.\n */\nasync function generateFollowUps(\n model: ModelProvider,\n messages: ModelMessage[],\n count: number,\n): Promise<{ followUps: string[]; usage: MessageUsage; modelId?: string }> {\n const discard: SinkWriter = { write: () => {}, end: () => {}, fail: () => {} };\n const turn = await model.runTurn({\n system: `Based on the conversation so far, propose up to ${count} short, distinct follow-up questions the user is likely to ask next. Respond with ONLY a JSON array of strings — no prose, no code fences.`,\n messages,\n tools: [],\n sink: discard,\n });\n return {\n followUps: parseFollowUps(turn.text, count),\n usage: turn.usage,\n ...(turn.modelId !== undefined ? { modelId: turn.modelId } : {}),\n };\n}\n\n/**\n * Wrap a genuinely-executing operation in an `aviary:agent:<event>` span (the diagnostics\n * `trace()` API — five `:start`/`:end`/`:asyncStart`/`:asyncEnd`/`:error` sub-channels),\n * correlated to its run by `traceId = runId`, WITHOUT letting the operation's raw return value\n * ride the span envelope: `trace` publishes the traced fn's return as the span's `result`, so the\n * traced fn returns only `summarize`d metadata (token counts / lengths / names — never prompt or\n * output text, the point events' redaction posture) while the real value is handed back to the\n * caller through the closure. Zero-cost when no span sub-channel has a subscriber.\n *\n * REPLAY SAFETY: call sites MUST sit INSIDE a `hooks.step` body (or another genuinely-executed\n * path). Durable replay skips step bodies and returns checkpoints, which is exactly what keeps a\n * replayed run from re-emitting spans. Never wrap a `hooks.step(...)`/`hooks.dispatch*(...)`\n * CALL — those run (and resolve from cache) on every replay.\n */\nasync function spanned<TEvent extends AgentSpanEvent, T>(\n event: TEvent,\n runId: string,\n payload: PayloadOf<'agent', TEvent>,\n run: () => Promise<T>,\n summarize: (value: T) => Record<string, unknown>,\n): Promise<T> {\n let value!: T;\n await trace(\n 'agent',\n event,\n async () => {\n value = await run();\n return summarize(value);\n },\n payload,\n { traceId: runId },\n );\n return value;\n}\n\n/**\n * Span-wrap one model call (`aviary:agent:llm.turn`). Exported so the durable dispatched-step\n * handler (which executes the genuine remote llm step) can emit the same span — core cannot wrap\n * `hooks.dispatchLlm` itself, because that call also runs (from cache) on replay.\n */\nexport function traceLlmTurn(\n runId: string,\n step: number,\n run: () => Promise<ModelTurnResult>,\n): Promise<ModelTurnResult> {\n return spanned('llm.turn', runId, { runId, step }, run, (turn) => ({\n ...(turn.modelId !== undefined ? { modelId: turn.modelId } : {}),\n inputTokens: turn.usage.inputTokens,\n outputTokens: turn.usage.outputTokens,\n textLength: turn.text.length,\n toolCalls: turn.toolCalls.length,\n }));\n}\n\n/**\n * Span-wrap one tool invocation (`aviary:agent:tool.execution`). The tool's raw output never\n * rides the span (only the start payload's name/type metadata + duration). Exported for the\n * durable dispatched-step handler, like {@link traceLlmTurn}.\n */\nexport function traceToolExecution<T>(\n runId: string,\n call: { toolCallId: string; toolName: string; toolType: 'read' | 'action' },\n run: () => Promise<T>,\n): Promise<T> {\n return spanned('tool.execution', runId, { runId, ...call }, run, () => ({}));\n}\n\n/**\n * The provider-agnostic agent turn, reused by both the inline and durable runners.\n * It drives the model→tools→model iteration; the runner supplies the `step`/`awaitApproval`\n * hooks that make the same loop body either in-process or a replay-safe durable workflow.\n */\nexport async function runAgentLoop(\n deps: AgentLoopDeps,\n input: AgentRunInput,\n hooks: AgentLoopHooks,\n): Promise<{ text: string }> {\n const maxSteps = deps.maxSteps ?? 8;\n let system = await resolveSystemPrompt(deps, input);\n\n if (deps.quota !== undefined) {\n const quota = deps.quota;\n const state = await hooks.step('quota:check', () => quota.check(input.actor.id, deps.day));\n if (!state.withinLimit) {\n publishAgentQuotaExceeded({\n actorId: input.actor.id,\n usedTokens: state.usedTokens,\n limitTokens: state.limitTokens,\n });\n throw new QuotaExceededError();\n }\n }\n\n if (input.regenerate === true) {\n // Re-run the last exchange: drop every message after the thread's last user message (keeping\n // it), then answer it again. No new user message is appended.\n await hooks.step('regenerate:truncate', async () => {\n const existing = await deps.store.getThread(input.threadId);\n const messages = existing?.messages ?? [];\n let lastUserIndex = -1;\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index]?.role === 'user') {\n lastUserIndex = index;\n break;\n }\n }\n const firstDropped = messages[lastUserIndex + 1];\n if (firstDropped !== undefined) {\n await deps.store.truncateFrom(input.threadId, firstDropped.id);\n }\n });\n } else {\n await hooks.step('persist:user', () =>\n deps.store.appendMessage({\n threadId: input.threadId,\n role: 'user',\n content: input.userText,\n ...(input.attachments !== undefined ? { attachments: input.attachments } : {}),\n }),\n );\n }\n\n const thread = await hooks.step('load:thread', () => deps.store.getThread(input.threadId));\n const modelMessages: ModelMessage[] = (thread?.messages ?? []).map((message) => ({\n role: message.role,\n content: message.content,\n ...(message.toolCalls !== undefined ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults !== undefined ? { toolResults: message.toolResults } : {}),\n ...(message.attachments !== undefined ? { attachments: message.attachments } : {}),\n }));\n\n const writer = await hooks.openSink();\n let lastText = '';\n let steps = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n publishAgentRunStarted({\n runId: hooks.runId,\n threadId: input.threadId,\n actorId: input.actor.id,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n });\n\n // Its own step so durable replay reuses the ORIGINAL wall-clock start — durationMs stays honest\n // across suspend/resume.\n const startedAt = await hooks.step('run:started-at', () => Promise.resolve(Date.now()));\n // Optional-chained: a store without run recording makes this (and persist:run:end) a no-op.\n await hooks.step('persist:run:start', async () => {\n // Hashed BEFORE the retrieved-context block is folded in below, so the hash identifies the\n // prompt VERSION (agent base + contributors), not a given turn's retrieval.\n const promptHash = createHash('sha256').update(system).digest('hex');\n await deps.store.recordRunStart?.({\n runId: hooks.runId,\n threadId: input.threadId,\n actorRef: input.actor.id,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n promptHash,\n });\n });\n\n // Inject-mode RAG: retrieve once for the user message and fold the passages into the system prompt\n // (a `ctx.step` so it's replay-cached under durable). Recorded below as a synthetic tool call on\n // the first assistant message, so citations surface through the same machinery as agentic search.\n let injectedPassages: Passage[] | undefined;\n if (deps.retriever !== undefined) {\n const retriever = deps.retriever;\n const topK = deps.retrievalTopK ?? 5;\n const passages = await hooks.step('retrieve', () =>\n spanned(\n 'retrieval',\n hooks.runId,\n { runId: hooks.runId, queryLength: input.userText.length, topK },\n () => retriever.retrieve(input.userText, { topK }),\n (retrieved) => ({ count: retrieved.length }),\n ),\n );\n if (passages.length > 0) {\n injectedPassages = passages;\n system = `${system}\\n\\n${buildContextBlock(passages)}`;\n }\n publishAgentRetrieved({ runId: hooks.runId, query: input.userText, count: passages.length });\n }\n\n // Fetched ONCE per run (not per step/message) and reused for every step's cost estimate below.\n // Returned as a plain array (not the Map built from it) so durable replay can JSON-cache the step.\n let prices: CurrentModelPrice[] = [];\n if (deps.pricingStore !== undefined) {\n const pricingStore = deps.pricingStore;\n prices = await hooks.step('pricing:list', () => pricingStore.listCurrentPrices());\n }\n const priceByModel = new Map(prices.map((price) => [price.modelId, price]));\n\n // NOTE: no try/finally around this loop. A durable runner suspends by THROWING through the stack\n // at `awaitApproval` (ctx.waitForSignal); a finally would then call writer.end() on every suspend\n // and prematurely close the live stream. We only end on normal completion — the throw propagates\n // to the engine, and the resumed replay reaches the writer.end() below.\n for (let i = 0; i < maxSteps; i += 1) {\n // Open a UI step spanning this model call AND its tool execution — matching the AI SDK's own\n // step semantics, so tool-output lands inside the step that made the call. Wrapped in a durable\n // step so replay doesn't re-emit it (a no-op for the inline runner).\n await hooks.step(`stream:step-start:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-start' }));\n });\n\n let turn: ModelTurnResult;\n if (hooks.dispatchLlm) {\n // No definitionsFor here: the envelope carries only wire-safe data (a ToolDefinition holds a\n // live schema instance) — the serving handler re-derives tool definitions from the actor.\n turn = await hooks.dispatchLlm(i, {\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n system,\n messages: modelMessages,\n actor: input.actor,\n });\n } else {\n const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n turn = await hooks.step(`llm:${i}`, () =>\n traceLlmTurn(hooks.runId, i, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n ),\n );\n }\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n const resolvedModelId = turn.modelId ?? deps.modelId ?? 'unknown';\n // Provider-reported spend wins; else an estimate from the (once-per-run cached) price list; else\n // `null` — surfaced on the stream's step-finish frame and the persisted assistant message below.\n const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));\n // Stamp each call's declared kind from the registry so thread-read consumers (and the stream\n // frames the model adapter writes) know a call's kind without hardcoding a tool-name allowlist.\n const toolCallsWithKind: ToolCallRequest[] = turn.toolCalls.map((call) => ({\n ...call,\n kind: deps.registry.spec(call.name)?.kind ?? 'read',\n }));\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n modelId: resolvedModelId,\n purpose: 'chat',\n usage: turn.usage,\n // persist the provider's actual cost when reported; the read-model prefers it over pricing\n ...(turn.costUsd !== undefined ? { costUsd: turn.costUsd } : {}),\n }),\n );\n if (deps.quota !== undefined) {\n const quota = deps.quota;\n await hooks.step(`quota:bump:${i}`, () =>\n quota.bump(input.actor.id, deps.day, turn.usage.inputTokens + turn.usage.outputTokens),\n );\n }\n\n steps += 1;\n totalInput += turn.usage.inputTokens;\n totalOutput += turn.usage.outputTokens;\n lastText = turn.text;\n publishAgentMessage({\n runId: hooks.runId,\n threadId: input.threadId,\n role: 'assistant',\n textLength: turn.text.length,\n });\n\n // A turn with no tool calls is the last one. Generate follow-up suggestions here (before the\n // append) so they land on the final assistant message, and stop after.\n const isFinalTurn = turn.toolCalls.length === 0;\n let followUps: string[] | undefined;\n if (isFinalTurn && deps.followUpsCount !== undefined && deps.followUpsCount > 0) {\n const count = deps.followUpsCount;\n // Stays on hooks.step (not dispatchLlm) — a short, non-streamed call, deliberately not\n // dispatched as a routed remote step.\n const generated = await hooks.step(`followups:${i}`, () =>\n spanned(\n 'follow-ups',\n hooks.runId,\n { runId: hooks.runId, step: i, count },\n () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\n ),\n (result) => ({\n followUps: result.followUps.length,\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n ...(result.modelId !== undefined ? { modelId: result.modelId } : {}),\n }),\n ),\n );\n if (generated.followUps.length > 0) {\n followUps = generated.followUps;\n }\n await hooks.step(`persist:usage:followups:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n modelId: generated.modelId ?? deps.modelId ?? 'unknown',\n purpose: 'follow_ups',\n usage: generated.usage,\n }),\n );\n }\n\n const assistant = await hooks.step(`persist:assistant:${i}`, () =>\n deps.store.appendMessage({\n threadId: input.threadId,\n role: 'assistant',\n content: turn.text,\n usage: { ...turn.usage, costUsd },\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(toolCallsWithKind.length > 0 ? { toolCalls: toolCallsWithKind } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n }),\n );\n // Tool results ride on the same assistant message that made the calls — the compact shape the\n // store persists and `mapMessages` (in every model adapter) expands into an assistant + tool\n // message pair. We keep the reference and attach `toolResults` below once the tools have run.\n const assistantMessage: ModelMessage = {\n role: 'assistant',\n content: turn.text,\n ...(toolCallsWithKind.length > 0 ? { toolCalls: toolCallsWithKind } : {}),\n };\n modelMessages.push(assistantMessage);\n\n // Record inject-mode retrieval as a synthetic auto-executed `retrieve` tool call on the assistant\n // message it informed — so its passages persist and render as citations exactly like an agentic\n // search would, without a new message field.\n if (i === 0 && injectedPassages !== undefined) {\n const passages = injectedPassages;\n const toolCallId = `retrieve-${assistant.id}`;\n await hooks.step(`persist:retrieval:${assistant.id}`, async () => {\n await deps.store.recordToolCall({\n toolCallId,\n messageId: assistant.id,\n toolName: 'retrieve',\n toolType: 'read',\n input: { query: input.userText },\n status: 'auto_executed',\n runId: hooks.runId,\n });\n await deps.store.updateToolCall({ toolCallId, status: 'executed', output: { passages } });\n });\n }\n\n if (isFinalTurn) {\n await hooks.step(`stream:step-finish:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-finish', usage: turn.usage, costUsd }));\n });\n break;\n }\n\n const results: ToolResult[] = [];\n for (const call of toolCallsWithKind) {\n const spec = deps.registry.spec(call.name);\n const toolType = call.kind ?? 'read';\n const ctx: AiToolCtx = {\n actor: input.actor,\n threadId: input.threadId,\n runId: hooks.runId,\n requestId: hooks.runId,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n ...(deps.host !== undefined ? { host: deps.host } : {}),\n };\n\n // Delegation: an `agent`-kind tool runs another agent. Handled at the LOOP level (not in a\n // step) because the durable runner maps it to `ctx.child`, a ctx-level suspend point.\n if (toolType === 'agent') {\n const targetAgent = spec?.targetAgent ?? call.name;\n const task = extractTask(call.input);\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'read',\n input: call.input,\n status: 'auto_executed',\n runId: hooks.runId,\n }),\n );\n // Cap nesting so a mis-wired delegation cycle can't spawn runs without bound.\n const overDepth = (input.delegationDepth ?? 0) >= MAX_DELEGATION_DEPTH;\n publishAgentDelegated({\n runId: hooks.runId,\n toAgent: targetAgent,\n ...(input.agentName !== undefined ? { fromAgent: input.agentName } : {}),\n });\n let sub: { text: string };\n if (overDepth) {\n sub = { text: `(delegation depth limit of ${MAX_DELEGATION_DEPTH} reached)` };\n } else if (hooks.runAgent) {\n sub = await hooks.runAgent(targetAgent, task);\n } else {\n sub = { text: `(no multi-agent support wired; cannot reach \"${targetAgent}\")` };\n }\n await hooks.step(`persist:toolexec:${call.id}`, () =>\n deps.store.updateToolCall({ toolCallId: call.id, status: 'executed', output: sub }),\n );\n results.push({ id: call.id, name: call.name, output: sub });\n continue;\n }\n\n // WHO settled an action tool: the Decision's ref (a console admin) when it carries one, else\n // the run's own actor (the chat flow). Stamped on both the executed and rejected persists.\n let deciderRef = input.actor.id;\n if (toolType === 'action') {\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'action',\n input: call.input,\n status: 'pending_approval',\n runId: hooks.runId,\n }),\n );\n const decision = await hooks.awaitApproval(call, ctx);\n deciderRef = decision.executedByRef ?? input.actor.id;\n if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\n executedByRef: deciderRef,\n ...(decision.reason !== undefined ? { error: decision.reason } : {}),\n }),\n );\n results.push({\n id: call.id,\n name: call.name,\n output: { rejected: true, reason: decision.reason ?? 'rejected by user' },\n error: 'rejected',\n });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'rejected',\n });\n continue;\n }\n } else {\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'read',\n input: call.input,\n status: 'auto_executed',\n runId: hooks.runId,\n }),\n );\n }\n\n const startedAt = Date.now();\n try {\n let output: unknown;\n if (hooks.dispatchTool) {\n const stepCtx: ToolStepCtx = {\n actor: input.actor,\n threadId: input.threadId,\n runId: hooks.runId,\n requestId: hooks.runId,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n };\n const envelope: ToolStepEnvelope = {\n toolName: call.name,\n input: call.input,\n ctx: stepCtx,\n ...(deps.toolTimeoutMs !== undefined ? { timeoutMs: deps.toolTimeoutMs } : {}),\n // Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see\n // ToolStepEnvelope.transientRetry.\n transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry),\n };\n // The handler applies withToolTimeout (and the retry loop) itself — no loop-side wrap for\n // a dispatched call.\n output = await hooks.dispatchTool(call, envelope);\n } else {\n const invocation = hooks.step(`tool:${call.id}`, () =>\n traceToolExecution(\n hooks.runId,\n { toolCallId: call.id, toolName: call.name, toolType },\n () =>\n invokeWithTransientRetry(\n () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n deps.toolTransientRetry ?? {},\n {\n ...(hooks.isControlFlowError !== undefined\n ? { isControlFlowError: hooks.isControlFlowError }\n : {}),\n onRetry: (attempt, retryError) => {\n publishAgentToolRetry({\n toolName: call.name,\n toolCallId: call.id,\n attempt,\n message:\n retryError instanceof Error ? retryError.message : String(retryError),\n });\n },\n },\n ),\n ),\n );\n output =\n deps.toolTimeoutMs !== undefined\n ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\n }\n const executionMs = Date.now() - startedAt;\n await hooks.step(`persist:toolexec:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'executed',\n output,\n executionMs,\n ...(toolType === 'action' ? { executedByRef: deciderRef } : {}),\n }),\n );\n results.push({ id: call.id, name: call.name, output });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'executed',\n durationMs: executionMs,\n });\n } catch (error) {\n // Runner control-flow (durable suspend / continue-as-new) is not a tool failure — it must\n // propagate untouched, like awaitApproval's suspend does. Persisting a toolfail checkpoint\n // here would diverge from the replay's real result (NonDeterminismError).\n if (hooks.isControlFlowError?.(error) === true) {\n throw error;\n }\n const executionMs = Date.now() - startedAt;\n const message = error instanceof Error ? error.message : String(error);\n await hooks.step(`persist:toolfail:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'failed',\n error: message,\n executionMs,\n }),\n );\n results.push({ id: call.id, name: call.name, output: null, error: message });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'failed',\n durationMs: executionMs,\n });\n }\n }\n\n assistantMessage.toolResults = results;\n\n // Stream each tool's result so the client flips its live tool card from \"running\" to the\n // rendered output (renderResult → DataTable/Chart, executeSql → rows). One durable step keeps\n // replay from re-emitting. `error` covers both a thrown tool and a rejected action.\n await hooks.step(`stream:tool-outputs:${i}`, async () => {\n for (const result of results) {\n await writer.write(\n encodeStreamEvent(\n result.error !== undefined\n ? { kind: 'tool-output-error', id: result.id, error: result.error }\n : { kind: 'tool-output', id: result.id, output: result.output },\n ),\n );\n }\n });\n\n await hooks.step(`stream:step-finish:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-finish', usage: turn.usage, costUsd }));\n });\n }\n\n if (thread !== null && (thread.title === '' || thread.title === 'New chat')) {\n await hooks.step('persist:title', () =>\n deps.store.setTitle(input.threadId, deriveTitle(input.userText)),\n );\n }\n\n // Normal completion only. The loop never records 'failed' — it doesn't catch its own crash;\n // failure recording is the RUNNER's job. A checkpointed step, so a resumed replay settles once.\n await hooks.step('persist:run:end', async () => {\n await deps.store.recordRunEnd?.({\n runId: hooks.runId,\n status: 'completed',\n durationMs: Date.now() - startedAt,\n });\n });\n\n await writer.end();\n publishAgentRunFinished({\n runId: hooks.runId,\n threadId: input.threadId,\n steps,\n inputTokens: totalInput,\n outputTokens: totalOutput,\n });\n return { text: lastText };\n}\n","import { emit } from '@dudousxd/nestjs-diagnostics';\nimport type { ChannelRegistry } from '@dudousxd/nestjs-diagnostics';\n\n/** Payloads carried on each `aviary:agent:*` channel. */\nexport interface AgentRunStarted {\n runId: string;\n threadId: string;\n actorId: string;\n /** Which agent is handling the run. */\n agentName?: string;\n}\nexport interface AgentMessageEvent {\n runId: string;\n threadId: string;\n role: 'user' | 'assistant';\n textLength: number;\n}\nexport interface AgentToolCallEvent {\n runId: string;\n toolName: string;\n toolType: 'read' | 'action';\n status: string;\n durationMs?: number;\n}\nexport interface AgentQuotaExceeded {\n actorId: string;\n usedTokens: number;\n limitTokens: number;\n}\nexport interface AgentRunFinished {\n runId: string;\n threadId: string;\n steps: number;\n inputTokens: number;\n outputTokens: number;\n}\nexport interface AgentRunFailed {\n runId: string;\n /** Stable failure slug, e.g. `quota_exceeded` or `run_failed`. */\n code: string;\n message: string;\n}\nexport interface AgentDelegated {\n runId: string;\n fromAgent?: string;\n toAgent: string;\n}\nexport interface AgentRetrieved {\n runId: string;\n query: string;\n /** How many passages the retriever returned. */\n count: number;\n}\n/**\n * A transient-classified tool error being retried in place (no new checkpoint) — see\n * `invokeWithTransientRetry`. Emitted once per retry (not for the final, non-retried outcome).\n */\nexport interface AgentToolRetry {\n toolName: string;\n toolCallId: string;\n /** 1-based ordinal of the attempt that just failed and is about to be retried. */\n attempt: number;\n /** The failed attempt's error message. */\n message: string;\n}\n\n// --- Span (trace) payloads — the START-phase payload of each traced operation. Metadata only:\n// token counts / lengths / names, never prompt or output text (the point events' redaction\n// posture). The traced result rides the `end`/`asyncEnd` envelope; see agent-loop's span helpers.\n\n/** START payload of an `aviary:agent:llm.turn:*` span — one model call within a run. */\nexport interface AgentLlmTurnSpan {\n runId: string;\n /** Zero-based model-call index within the run (the loop's step counter). */\n step: number;\n}\n/** START payload of an `aviary:agent:tool.execution:*` span — one tool invocation. */\nexport interface AgentToolExecutionSpan {\n runId: string;\n toolCallId: string;\n toolName: string;\n toolType: 'read' | 'action';\n}\n/** START payload of an `aviary:agent:retrieval:*` span — inject-mode RAG retrieval. */\nexport interface AgentRetrievalSpan {\n runId: string;\n /** Length of the retrieval query in characters — never the query text itself. */\n queryLength: number;\n topK: number;\n}\n/** START payload of an `aviary:agent:follow-ups:*` span — the extra follow-up-suggestions call. */\nexport interface AgentFollowUpsSpan {\n runId: string;\n /** Zero-based model-call index of the final turn the follow-ups ride on. */\n step: number;\n /** How many follow-up questions were requested. */\n count: number;\n}\n\n/** Declaration-merge so `emit('agent', ...)`, `trace('agent', ...)` and telescope infer the agent payloads. */\ndeclare module '@dudousxd/nestjs-diagnostics' {\n interface ChannelRegistry {\n agent: {\n 'run.started': AgentRunStarted;\n message: AgentMessageEvent;\n 'tool-call': AgentToolCallEvent;\n 'quota.exceeded': AgentQuotaExceeded;\n 'run.finished': AgentRunFinished;\n 'run.failed': AgentRunFailed;\n delegated: AgentDelegated;\n retrieved: AgentRetrieved;\n 'tool.retry': AgentToolRetry;\n // Span-only events (published via trace() on :start/:end/:asyncStart/:asyncEnd/:error\n // sub-channels, never as point events) — see AgentSpanEvent below.\n 'llm.turn': AgentLlmTurnSpan;\n 'tool.execution': AgentToolExecutionSpan;\n retrieval: AgentRetrievalSpan;\n 'follow-ups': AgentFollowUpsSpan;\n };\n }\n}\n\nexport function publishAgentRunStarted(payload: AgentRunStarted): void {\n emit('agent', 'run.started', payload);\n}\nexport function publishAgentMessage(payload: AgentMessageEvent): void {\n emit('agent', 'message', payload);\n}\nexport function publishAgentToolCall(payload: AgentToolCallEvent): void {\n emit('agent', 'tool-call', payload);\n}\nexport function publishAgentQuotaExceeded(payload: AgentQuotaExceeded): void {\n emit('agent', 'quota.exceeded', payload);\n}\nexport function publishAgentRunFinished(payload: AgentRunFinished): void {\n emit('agent', 'run.finished', payload);\n}\nexport function publishAgentRunFailed(payload: AgentRunFailed): void {\n emit('agent', 'run.failed', payload);\n}\nexport function publishAgentDelegated(payload: AgentDelegated): void {\n emit('agent', 'delegated', payload);\n}\nexport function publishAgentRetrieved(payload: AgentRetrieved): void {\n emit('agent', 'retrieved', payload);\n}\nexport function publishAgentToolRetry(payload: AgentToolRetry): void {\n emit('agent', 'tool.retry', payload);\n}\n\n/**\n * Events published ONLY as spans — via `trace('agent', ...)` on the five `:start`/`:end`/\n * `:asyncStart`/`:asyncEnd`/`:error` sub-channels — never as point events on the base channel.\n * They are deliberately NOT in {@link AGENT_DIAGNOSTIC_EVENTS}: the point-event watcher has\n * nothing to subscribe to on their base channels, and claiming their keys would be meaningless\n * (the generic bridge only records point traffic).\n */\nexport type AgentSpanEvent = 'llm.turn' | 'tool.execution' | 'retrieval' | 'follow-ups';\n\n/** All span-only events, in a stable order — for a future span recorder to derive sub-channels from. */\nexport const AGENT_SPAN_EVENTS: readonly AgentSpanEvent[] = [\n 'llm.turn',\n 'tool.execution',\n 'retrieval',\n 'follow-ups',\n];\n\n/** Compile-time-only check: every span event must be declared on `ChannelRegistry['agent']`. */\ntype AgentSpanEventsAreRegistered = [AgentSpanEvent] extends [keyof ChannelRegistry['agent']]\n ? true\n : [\"AGENT_SPAN_EVENTS names an event not declared on ChannelRegistry['agent']\"];\nconst agentSpanEventsAreRegistered: AgentSpanEventsAreRegistered = true;\nvoid agentSpanEventsAreRegistered;\n\n/** Every POINT event key declared on `ChannelRegistry['agent']` above — derived, not hand-copied. */\nexport type AgentDiagnosticEvent = Exclude<keyof ChannelRegistry['agent'], AgentSpanEvent>;\n\n/**\n * All 9 point events on `ChannelRegistry['agent']`, in a stable order — handy for wiring\n * subscribers (mirrors nestjs-media's `MEDIA_DIAGNOSTIC_EVENTS`). Span-only events (see\n * {@link AgentSpanEvent}) are excluded. A drift between this list and the registry is a compile\n * error in both directions: an extra/misspelled entry fails this array's own\n * `readonly AgentDiagnosticEvent[]` annotation immediately; a missing entry fails the\n * {@link AgentDiagnosticEventsCoverAllKeys} check below.\n */\nexport const AGENT_DIAGNOSTIC_EVENTS: readonly AgentDiagnosticEvent[] = [\n 'run.started',\n 'message',\n 'tool-call',\n 'quota.exceeded',\n 'run.finished',\n 'run.failed',\n 'delegated',\n 'retrieved',\n 'tool.retry',\n];\n\n/** Compile-time-only check: every point event of `ChannelRegistry['agent']` must appear above. */\ntype AgentDiagnosticEventsCoverAllKeys = [AgentDiagnosticEvent] extends [\n (typeof AGENT_DIAGNOSTIC_EVENTS)[number],\n]\n ? true\n : [\"AGENT_DIAGNOSTIC_EVENTS is missing a key declared on ChannelRegistry['agent']\"];\n\n// If this line stops typechecking, an event was added to (or renamed on) ChannelRegistry['agent']\n// without a matching update to AGENT_DIAGNOSTIC_EVENTS (point events) or AgentSpanEvent (spans).\nconst agentDiagnosticEventsCoverAllKeys: AgentDiagnosticEventsCoverAllKeys = true;\nvoid agentDiagnosticEventsCoverAllKeys;\n\n/**\n * The telescope key for an agent diagnostics channel — `agent:<event>`. This is the key the\n * `@dudousxd/nestjs-diagnostics-telescope` generic bridge matches its `exclude` option against,\n * and the label its \"Busiest events\" panel shows. Distinct from the `aviary:agent:<event>` channel\n * name used on the wire. Mirrors `mediaDiagnosticKey`.\n */\nexport type AgentDiagnosticKey = `agent:${AgentDiagnosticEvent}`;\n\n/**\n * Compose the telescope key for an agent event, typed against {@link AgentDiagnosticEvent} so a\n * misspelled event is a compile error. Feed the result to `nestjsDiagnosticsTelescope({ exclude:\n * [...] })` to mute a noisy channel, e.g. `agentDiagnosticKey('message')`.\n */\nexport function agentDiagnosticKey(event: AgentDiagnosticEvent): AgentDiagnosticKey {\n return `agent:${event}`;\n}\n","/**\n * Transient tool-error classification + the retry loop that wraps a tool's own invocation. A\n * classified-transient error (a DB deadlock, a lock-wait timeout, a serialization failure) means\n * the server rolled the tool's work back — retrying THAT class is safe, unlike a tool's general\n * business failure, which stays a one-shot outcome (no durable step retries: a tool may not be\n * idempotent). See `runAgentLoop`'s `tool:<call.id>` step body and `AgentRunSteps.tool` — both wrap\n * `registry.invoke(...)` with {@link invokeWithTransientRetry} so a retry never becomes a new\n * checkpoint; history still shows exactly one step per tool call.\n */\n\n/** Narrow, structural check for a MySQL/Postgres/SQLite transient error shape — no casts. */\nfunction hasTransientShape(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const code = 'code' in error ? (error as { code: unknown }).code : undefined;\n const errno = 'errno' in error ? (error as { errno: unknown }).errno : undefined;\n const sqlState = 'sqlState' in error ? (error as { sqlState: unknown }).sqlState : undefined;\n if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {\n return true; // MySQL ER_LOCK_DEADLOCK / ER_LOCK_WAIT_TIMEOUT numeric codes\n }\n if (code === 'ER_LOCK_DEADLOCK' || code === 'ER_LOCK_WAIT_TIMEOUT') {\n return true; // MySQL driver string codes\n }\n if (code === '40001' || code === '40P01' || sqlState === '40001' || sqlState === '40P01') {\n return true; // Postgres serialization_failure / deadlock_detected SQLSTATEs\n }\n if (code === 'SQLITE_BUSY') {\n return true;\n }\n const message = 'message' in error ? (error as { message: unknown }).message : undefined;\n return (\n typeof message === 'string' && /deadlock|lock wait timeout|serialization failure/i.test(message)\n );\n}\n\n/**\n * Default transient-tool-error classifier: true for a recognized MySQL/Postgres/SQLite\n * lock-contention shape (by driver `code`/`errno`/`sqlState`, or a matching message), checked on\n * the error itself and one level of `cause` (drivers commonly wrap the original error). A plain\n * `Error` with none of these markers — any other business failure — is `false`.\n */\nexport function isTransientToolError(error: unknown): boolean {\n if (hasTransientShape(error)) {\n return true;\n }\n if (typeof error === 'object' && error !== null && 'cause' in error) {\n const cause = (error as { cause: unknown }).cause;\n if (cause !== undefined && cause !== error && hasTransientShape(cause)) {\n return true;\n }\n }\n return false;\n}\n\n/** Total attempts (initial try + retries) when `toolTransientRetry` doesn't set `attempts`. */\nexport const DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;\n/** Backoff base in ms — the wait between attempt N and N+1 is `backoffMs * N`. */\nexport const DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;\n\n/** The host-configurable half of the policy — everything except the (non-wire-safe) `classify` fn. */\nexport interface ToolTransientRetryOptions {\n /** Total attempts (initial try + retries). Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS}. */\n attempts?: number;\n /** Backoff base in ms. Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS}. */\n backoffMs?: number;\n /** Overrides the default classifier — widen or narrow which errors are treated as transient. */\n classify?: (error: unknown) => boolean;\n}\n\n/** `false` disables transient retry entirely — a tool's own thrown error surfaces immediately. */\nexport type ToolTransientRetrySetting = ToolTransientRetryOptions | false;\n\n/** Just the wire-safe (numeric) half of a resolved policy — what a dispatched envelope carries. */\nexport interface ToolTransientRetryNumbers {\n attempts: number;\n backoffMs: number;\n}\n\n/**\n * Resolves the numeric half of `toolTransientRetry` for the dispatched wire envelope: `false` when\n * explicitly disabled, else concrete `{ attempts, backoffMs }` (defaults filled in) — never\n * `undefined`, so the dispatched handler always gets a definite answer instead of re-deriving its\n * own default. The `classify` function never rides this — it isn't wire-safe; the dispatched\n * handler resolves its own `classify` from its local module options (see `AgentRunSteps.tool`).\n */\nexport function resolveToolTransientRetryNumbers(\n setting: ToolTransientRetrySetting | undefined,\n): ToolTransientRetryNumbers | false {\n if (setting === false) {\n return false;\n }\n return {\n attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,\n backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,\n };\n}\n\nexport interface InvokeWithTransientRetryOptions {\n /**\n * Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so a retry\n * never swallows one — same rule the loop's tool catch already applies. Undefined for a call site\n * with no such notion (e.g. the dispatched step handler, which has no workflow ctx of its own).\n */\n isControlFlowError?: (error: unknown) => boolean;\n /**\n * Called before each wait-and-retry, with the 1-based ordinal of the attempt that just failed and\n * the error it threw. The call site uses this to emit the `tool.retry` diagnostics point event —\n * `invokeWithTransientRetry` itself carries no tool identity (name/callId), only the thunk.\n */\n onRetry?: (attempt: number, error: unknown) => void;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Retries `fn` in place — never a new durable step/checkpoint, just repeated attempts inside\n * whichever step body already wraps this call. `setting: false` runs `fn` once, unwrapped (no\n * classify/backoff bookkeeping at all). Otherwise: try; on a thrown error, rethrow immediately if\n * it's a recognized control-flow signal, else if the (possibly custom) classifier calls it\n * transient AND attempts remain, wait `backoffMs * attemptNumber` and retry; otherwise rethrow the\n * error as-is.\n */\nexport async function invokeWithTransientRetry<T>(\n fn: () => Promise<T>,\n setting: ToolTransientRetrySetting,\n options?: InvokeWithTransientRetryOptions,\n): Promise<T> {\n if (setting === false) {\n return fn();\n }\n const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;\n const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;\n const classify = setting.classify ?? isTransientToolError;\n\n let attempt = 1;\n for (;;) {\n try {\n return await fn();\n } catch (error) {\n if (options?.isControlFlowError?.(error) === true) {\n throw error;\n }\n const attemptsRemain = attempt < attempts;\n if (!attemptsRemain || !classify(error)) {\n throw error;\n }\n options?.onRetry?.(attempt, error);\n await delay(backoffMs * attempt);\n attempt += 1;\n }\n }\n}\n"],"mappings":";;;;AAWO,IAAMA,gBAAgBC,OAAOC,IAAI,gCAAA;AACjC,IAAMC,cAAcF,OAAOC,IAAI,8BAAA;AAC/B,IAAME,eAAeH,OAAOC,IAAI,+BAAA;AAMhC,IAAMG,uBAAuBJ,OAAOC,IAAI,uCAAA;AACxC,IAAMI,aAAaL,OAAOC,IAAI,6BAAA;AAC9B,IAAMK,cAAcN,OAAOC,IAAI,8BAAA;AAC/B,IAAMM,qBAAqBP,OAAOC,IAAI,qCAAA;AACtC,IAAMO,oBAAoBR,OAAOC,IAAI,oCAAA;AACrC,IAAMQ,sBAAsBT,OAAOC,IAAI,sCAAA;AACvC,IAAMS,iBAAiBV,OAAOC,IAAI,uCAAA;AAClC,IAAMU,uBAAuBX,OAAOC,IAAI,uCAAA;AAExC,IAAMW,2BAA2BZ,OAAOC,IAAI,2CAAA;AAE5C,IAAMY,sBAAsBb,OAAOC,IAAI,sCAAA;AAEvC,IAAMa,kBAAkBd,OAAOC,IAAI,kCAAA;AAEnC,IAAMc,2BAA2Bf,OAAOC,IAAI,2CAAA;AAG5C,IAAMe,qBAAqBhB,OAAOC,IAAI,qCAAA;AAEtC,IAAMgB,4BAA4BjB,OAAOC,IAAI,4CAAA;AAK7C,IAAMiB,wBAAwBlB,OAAOC,IAAI,wCAAA;AAMzC,IAAMkB,2BAA2BnB,OAAOC,IAAI,2CAAA;AAK5C,IAAMmB,sBAAsBpB,OAAOC,IAAI,sCAAA;;;ACzBvC,IAAMoB,mBAAN,cAA+BC,MAAAA;EA9BtC,OA8BsCA;;;EAC3BC;EACT,YAAYC,OAAoB;AAC9B,UAAMA,MAAMC,OAAO;AACnB,SAAKC,OAAO;AACZ,SAAKH,OAAOC,MAAMD;EACpB;AACF;;;ACCA,IAAMI,UAAU,IAAIC,YAAAA;AAGb,SAASC,kBAAkBC,OAAuB;AACvD,SAAOH,QAAQI,OAAO,GAAGC,KAAKC,UAAUH,KAAAA,CAAAA;CAAU;AACpD;AAFgBD;;;ACNhB,eAAsBK,gBACpBC,OACAC,QAAyB;AAEzB,aAAWC,SAASD,QAAQ;AAC1B,UAAMD,MAAMG,iBAAiBD,KAAAA;EAC/B;AACF;AAPsBH;;;ACySf,IAAMK,8BAA8B;AAOpC,SAASC,sBAAsBC,SAAe;AAInD,MAAIA,QAAQC,UAAUH,6BAA6B;AACjD,WAAO;MAAEE;MAASE,WAAW;IAAM;EACrC;AACA,SAAO;IAAEF,SAASA,QAAQG,MAAM,GAAGL,2BAAAA;IAA8BI,WAAW;EAAK;AACnF;AARgBH;;;ACxRT,SAASK,aAAaC,OAAkBC,OAA6B;AAC1E,MAAIA,UAAUC,QAAW;AACvB,WAAO;EACT;AACA,QAAMC,mBAAmBH,MAAMG,oBAAoB;AACnD,QAAMC,kBAAkBJ,MAAMI,mBAAmB;AACjD,QAAMC,sBAAsBL,MAAMM,cAAcH,mBAAmBC;AACnE,SACGC,sBAAsB,MAAaJ,MAAMM,kBACzCJ,mBAAmB,OAAcF,MAAMO,wBAAwBP,MAAMM,mBACrEH,kBAAkB,OAAcH,MAAMQ,uBAAuBR,MAAMM,mBACnEP,MAAMU,eAAe,MAAaT,MAAMU;AAE7C;AAbgBZ;AAgBhB,SAASa,QAAQC,KAA2BC,QAAuC;AACjF,SAAOD,IAAIE,WAAWhB,aAAac,KAAKC,OAAOE,IAAIH,IAAII,OAAO,CAAA;AAChE;AAFSL;AAKF,SAASM,cACdC,MACAL,QAAuC;AAEvC,QAAMM,UAAU,oBAAIC,IAAAA;AAIpB,aAAWR,OAAOM,MAAM;AACtB,UAAMG,SAASF,QAAQJ,IAAIH,IAAII,OAAO,KAAK;MACzCM,UAAU;MACVjB,aAAa;MACbI,cAAc;MACdK,SAAS;IACX;AACAO,WAAOC,YAAY;AACnBD,WAAOhB,eAAeO,IAAIP;AAC1BgB,WAAOZ,gBAAgBG,IAAIH;AAC3BY,WAAOP,WAAWH,QAAQC,KAAKC,MAAAA;AAC/BM,YAAQI,IAAIX,IAAII,SAASK,MAAAA;EAC3B;AACA,QAAMG,SAA0B,CAAA;AAChC,aAAW,CAACR,SAASK,MAAAA,KAAWF,SAAS;AACvCK,WAAOC,KAAK;MACVT;MACAM,UAAUD,OAAOC;MACjBjB,aAAagB,OAAOhB;MACpBI,cAAcY,OAAOZ;MACrBK,SAASO,OAAOP;IAClB,CAAA;EACF;AACAU,SAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMd,UAAUa,KAAKb,WAAWa,KAAKX,QAAQa,cAAcD,MAAMZ,OAAO,CAAA;AAE3F,SAAOQ;AACT;AAnCgBP;AAsCT,SAASa,cACdZ,MACAL,QAAuC;AAEvC,QAAMkB,UAAU,oBAAIX,IAAAA;AAIpB,aAAWR,OAAOM,MAAM;AACtB,UAAMG,SAASU,QAAQhB,IAAIH,IAAIoB,QAAQ,KAAK;MAC1CV,UAAU;MACVW,aAAa;MACbnB,SAAS;MACToB,WAAW,oBAAIC,IAAAA;IACjB;AACAd,WAAOC,YAAY;AACnBD,WAAOY,eAAerB,IAAIP,cAAcO,IAAIH;AAC5CY,WAAOP,WAAWH,QAAQC,KAAKC,MAAAA;AAC/BQ,WAAOa,UAAUE,IAAIxB,IAAIyB,QAAQ;AACjCN,YAAQR,IAAIX,IAAIoB,UAAUX,MAAAA;EAC5B;AACA,QAAMG,SAA0B,CAAA;AAChC,aAAW,CAACQ,UAAUX,MAAAA,KAAWU,SAAS;AACxCP,WAAOC,KAAK;MACVO;MACAV,UAAUD,OAAOC;MACjBW,aAAaZ,OAAOY;MACpBnB,SAASO,OAAOP;MAChBwB,aAAajB,OAAOa,UAAUK;IAChC,CAAA;EACF;AACAf,SAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMd,UAAUa,KAAKb,WAAWa,KAAKK,SAASH,cAAcD,MAAMI,QAAQ,CAAA;AAE7F,SAAOR;AACT;AAnCgBM;AA2CT,SAASU,eACdtB,MACAL,QACA4B,SACAC,SAA0D;AAE1D,QAAMC,WAAW,oBAAIvB,IAAAA;AACrB,aAAWR,OAAOM,MAAM;AACtB,UAAMG,SAASsB,SAAS5B,IAAIH,IAAIyB,QAAQ,KAAK;MAAEf,UAAU;MAAGW,aAAa;MAAGnB,SAAS;IAAE;AACvFO,WAAOC,YAAY;AACnBD,WAAOY,eAAerB,IAAIP,cAAcO,IAAIH;AAC5CY,WAAOP,WAAWH,QAAQC,KAAKC,MAAAA;AAC/B8B,aAASpB,IAAIX,IAAIyB,UAAUhB,MAAAA;EAC7B;AACA,QAAMG,SAA2B,CAAA;AACjC,aAAW,CAACa,UAAUhB,MAAAA,KAAWsB,UAAU;AACzC,UAAMC,SAASH,QAAQ1B,IAAIsB,QAAAA;AAC3B,QAAIO,WAAW3C,UAAa,CAACyC,QAAQG,uBAAuB;AAC1D;IACF;AACArB,WAAOC,KAAK;MACVY;MACAS,OAAOF,QAAQE,SAAS;MACxBd,UAAUY,QAAQZ,YAAY;MAC9BV,UAAUD,OAAOC;MACjBW,aAAaZ,OAAOY;MACpBnB,SAASO,OAAOP;IAClB,CAAA;EACF;AACAU,SAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMd,UAAUa,KAAKb,WAAWa,KAAKU,SAASR,cAAcD,MAAMS,QAAQ,CAAA;AAE7F,SAAOb,OAAOuB,MAAM,GAAGL,QAAQM,KAAK;AACtC;AAjCgBR;AAwCT,SAASS,kBACd/B,MACAL,QAAuC;AAEvC,QAAMqC,SAA4B;IAChC5B,UAAU;IACVjB,aAAa;IACbI,cAAc;IACdwB,aAAa;IACbnB,SAAS;EACX;AACA,aAAWF,OAAOM,MAAM;AACtBgC,WAAO5B,YAAY;AACnB4B,WAAO7C,eAAeO,IAAIP;AAC1B6C,WAAOzC,gBAAgBG,IAAIH;AAC3ByC,WAAOjB,eAAerB,IAAIP,cAAcO,IAAIH;AAC5CyC,WAAOpC,WAAWH,QAAQC,KAAKC,MAAAA;EACjC;AACA,SAAOqC;AACT;AAnBgBD;AAsBT,SAASE,iBACdjC,MACAL,QAAuC;AAEvC,QAAMuC,QAAQ,oBAAIhC,IAAAA;AAClB,aAAWR,OAAOM,MAAM;AACtB,UAAMG,SAAS+B,MAAMrC,IAAIH,IAAIyC,GAAG,KAAK;MAAEpB,aAAa;MAAGnB,SAAS;IAAE;AAClEO,WAAOY,eAAerB,IAAIP,cAAcO,IAAIH;AAC5CY,WAAOP,WAAWH,QAAQC,KAAKC,MAAAA;AAC/BuC,UAAM7B,IAAIX,IAAIyC,KAAKhC,MAAAA;EACrB;AACA,QAAMG,SAA4B,CAAA;AAClC,aAAW,CAAC6B,KAAKhC,MAAAA,KAAW+B,OAAO;AACjC5B,WAAOC,KAAK;MAAE4B;MAAKpB,aAAaZ,OAAOY;MAAanB,SAASO,OAAOP;IAAQ,CAAA;EAC9E;AACAU,SAAOE,KAAK,CAACC,MAAMC,UAAUD,KAAK0B,IAAIxB,cAAcD,MAAMyB,GAAG,CAAA;AAC7D,SAAO7B;AACT;AAjBgB2B;AAoBT,SAASG,aAAaC,OAAsB;AACjD,SAAO;IACLC,OAAO,oBAAIC,KAAK,GAAGF,MAAMG,OAAO,gBAAgB;IAChDC,KAAK,oBAAIF,KAAK,GAAGF,MAAMK,KAAK,gBAAgB;EAC9C;AACF;AALgBN;;;AC/OhB,eAAsBO,kBACpBC,OACAC,OACAC,QAAmB;AAEnB,QAAMC,UAAU,MAAMC,QAAQC,IAC5BL,MAAMM,IAAI,OAAOC,UAAU;IAAEA;IAAMC,SAAS,MAAMN,OAAOO,IAAIR,OAAOM,IAAAA;EAAM,EAAA,CAAA;AAE5E,SAAOJ,QAAQO,OAAO,CAACC,UAAUA,MAAMH,OAAO,EAAEF,IAAI,CAACK,UAAUA,MAAMJ,IAAI;AAC3E;AATsBR;AAYf,SAASa,uBACdZ,OACAa,cAAkC;AAElC,MAAIA,iBAAiBC,QAAW;AAC9B,WAAOd;EACT;AACA,QAAMQ,UAAU,IAAIO,IAAIF,YAAAA;AACxB,SAAOb,MAAMU,OAAO,CAACH,SAASC,QAAQQ,IAAIT,KAAKU,IAAI,CAAA;AACrD;AATgBL;;;ACbT,IAAMM,gBAAN,MAAMA;EADb,OACaA;;;EACMC,cAAc,oBAAIC,IAAAA;EAEnCC,SAASC,YAAmC;AAC1C,SAAKH,YAAYI,IAAID,WAAWE,MAAMF,UAAAA;EACxC;EAEAG,IAAID,MAA2C;AAC7C,WAAO,KAAKL,YAAYM,IAAID,IAAAA;EAC9B;EAEAE,IAAIF,MAAuB;AACzB,WAAO,KAAKL,YAAYO,IAAIF,IAAAA;EAC9B;EAEAG,OAA0B;AACxB,WAAO;SAAI,KAAKR,YAAYS,OAAM;;EACpC;AACF;;;ACdO,IAAMC,qBAAN,cAAiCC,MAAAA;EAJxC,OAIwCA;;;;EACtC,YAA4BC,UAAkB;AAC5C,UAAM,SAASA,QAAAA,gCAAwC,GAAA,KAD7BA,WAAAA;AAE1B,SAAKC,OAAO;EACd;AACF;AAGO,IAAMC,oBAAN,cAAgCH,MAAAA;EAZvC,OAYuCA;;;;EACrC,YAA4BC,UAAkB;AAC5C,UAAM,SAASA,QAAAA,qBAA6B,GAAA,KADlBA,WAAAA;AAE1B,SAAKC,OAAO;EACd;AACF;AAGO,IAAME,wBAAN,cAAoCJ,MAAAA;EApB3C,OAoB2CA;;;;;EACzC,YACkBC,UACAI,QAChB;AACA,UACE,2BAA2BJ,QAAAA,MAAcI,OAAOC,IAAI,CAACC,UAAUA,MAAMC,OAAO,EAAEC,KAAK,IAAA,CAAA,EAAO,GAAA,KAJ5ER,WAAAA,UAAAA,KACAI,SAAAA;AAKhB,SAAKH,OAAO;EACd;AACF;AAcO,IAAMQ,eAAN,MAAMA;EA5Cb,OA4CaA;;;EACMC,UAAU,oBAAIC,IAAAA;EAE/BC,SAASC,MAAgBC,SAA4B;AACnD,SAAKJ,QAAQK,IAAIF,KAAKZ,MAAM;MAAEY;MAAMC;IAAQ,CAAA;EAC9C;EAEAE,IAAIf,MAAuB;AACzB,WAAO,KAAKS,QAAQM,IAAIf,IAAAA;EAC1B;EAEAY,KAAKZ,MAAoC;AACvC,WAAO,KAAKS,QAAQO,IAAIhB,IAAAA,GAAOY;EACjC;EAEAK,WAAuB;AACrB,WAAO;SAAI,KAAKR,QAAQS,OAAM;MAAId,IAAI,CAACe,UAAUA,MAAMP,IAAI;EAC7D;;EAGA,MAAMQ,eACJC,OACAC,QACAC,cAC2B;AAC3B,UAAMC,aAAa,MAAMC,kBAAkB,KAAKR,SAAQ,GAAII,OAAOC,MAAAA;AACnE,UAAMI,cAAcC,uBAAuBH,YAAYD,YAAAA;AACvD,WAAOG,YAAYtB,IAAI,CAACQ,UAAU;MAChCZ,MAAMY,KAAKZ;MACX4B,MAAMhB,KAAKgB;MACXC,aAAajB,KAAKiB;MAClBC,aAAalB,KAAKkB;IACpB,EAAA;EACF;;EAGA,MAAMC,OACJ/B,MACAgC,OACAC,KACAX,QACkB;AAClB,UAAMH,QAAQ,KAAKV,QAAQO,IAAIhB,IAAAA;AAC/B,QAAImB,UAAUe,QAAW;AACvB,YAAM,IAAIjC,kBAAkBD,IAAAA;IAC9B;AACA,QAAI,CAAE,MAAMsB,OAAOa,IAAIF,IAAIZ,OAAOF,MAAMP,IAAI,GAAI;AAC9C,YAAM,IAAIf,mBAAmBG,IAAAA;IAC/B;AACA,UAAMoC,aAAa,MAAMjB,MAAMP,KAAKkB,YAAY,WAAA,EAAaO,SAASL,KAAAA;AACtE,QAAII,WAAWjC,WAAW+B,QAAW;AACnC,YAAM,IAAIhC,sBAAsBF,MAAMoC,WAAWjC,MAAM;IACzD;AACA,WAAOgB,MAAMN,QAAQyB,QAAQF,WAAWG,OAAON,GAAAA;EACjD;AACF;AAGO,IAAMO,qBAAN,MAAMA;EAtGb,OAsGaA;;;;EACX,YAA6BC,eAAyB;IAAC;KAAU;SAApCA,eAAAA;EAAqC;EAElEN,IAAId,OAAcqB,MAAyB;AACzC,UAAMC,UAAUD,KAAKE,SAAS,KAAKH;AACnC,YAAQpB,MAAMuB,SAAS,CAAA,GAAIC,KAAK,CAACC,SAASH,QAAQI,SAASD,IAAAA,CAAAA;EAC7D;AACF;;;AChHA,SAASE,kBAAkB;AAC3B,SAASC,aAAa;;;ACDtB,SAASC,YAAY;AA0Hd,SAASC,uBAAuBC,SAAwB;AAC7DC,OAAK,SAAS,eAAeD,OAAAA;AAC/B;AAFgBD;AAGT,SAASG,oBAAoBF,SAA0B;AAC5DC,OAAK,SAAS,WAAWD,OAAAA;AAC3B;AAFgBE;AAGT,SAASC,qBAAqBH,SAA2B;AAC9DC,OAAK,SAAS,aAAaD,OAAAA;AAC7B;AAFgBG;AAGT,SAASC,0BAA0BJ,SAA2B;AACnEC,OAAK,SAAS,kBAAkBD,OAAAA;AAClC;AAFgBI;AAGT,SAASC,wBAAwBL,SAAyB;AAC/DC,OAAK,SAAS,gBAAgBD,OAAAA;AAChC;AAFgBK;AAGT,SAASC,sBAAsBN,SAAuB;AAC3DC,OAAK,SAAS,cAAcD,OAAAA;AAC9B;AAFgBM;AAGT,SAASC,sBAAsBP,SAAuB;AAC3DC,OAAK,SAAS,aAAaD,OAAAA;AAC7B;AAFgBO;AAGT,SAASC,sBAAsBR,SAAuB;AAC3DC,OAAK,SAAS,aAAaD,OAAAA;AAC7B;AAFgBQ;AAGT,SAASC,sBAAsBT,SAAuB;AAC3DC,OAAK,SAAS,cAAcD,OAAAA;AAC9B;AAFgBS;AAcT,IAAMC,oBAA+C;EAC1D;EACA;EACA;EACA;;AAqBK,IAAMC,0BAA2D;EACtE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AA4BK,SAASC,mBAAmBC,OAA2B;AAC5D,SAAO,SAASA,KAAAA;AAClB;AAFgBD;;;ACnNhB,SAASE,kBAAkBC,OAAc;AACvC,MAAI,OAAOA,UAAU,YAAYA,UAAU,MAAM;AAC/C,WAAO;EACT;AACA,QAAMC,OAAO,UAAUD,QAASA,MAA4BC,OAAOC;AACnE,QAAMC,QAAQ,WAAWH,QAASA,MAA6BG,QAAQD;AACvE,QAAME,WAAW,cAAcJ,QAASA,MAAgCI,WAAWF;AACnF,MAAID,SAAS,QAAQA,SAAS,QAAQE,UAAU,QAAQA,UAAU,MAAM;AACtE,WAAO;EACT;AACA,MAAIF,SAAS,sBAAsBA,SAAS,wBAAwB;AAClE,WAAO;EACT;AACA,MAAIA,SAAS,WAAWA,SAAS,WAAWG,aAAa,WAAWA,aAAa,SAAS;AACxF,WAAO;EACT;AACA,MAAIH,SAAS,eAAe;AAC1B,WAAO;EACT;AACA,QAAMI,UAAU,aAAaL,QAASA,MAA+BK,UAAUH;AAC/E,SACE,OAAOG,YAAY,YAAY,oDAAoDC,KAAKD,OAAAA;AAE5F;AAvBSN;AA+BF,SAASQ,qBAAqBP,OAAc;AACjD,MAAID,kBAAkBC,KAAAA,GAAQ;AAC5B,WAAO;EACT;AACA,MAAI,OAAOA,UAAU,YAAYA,UAAU,QAAQ,WAAWA,OAAO;AACnE,UAAMQ,QAASR,MAA6BQ;AAC5C,QAAIA,UAAUN,UAAaM,UAAUR,SAASD,kBAAkBS,KAAAA,GAAQ;AACtE,aAAO;IACT;EACF;AACA,SAAO;AACT;AAXgBD;AAcT,IAAME,wCAAwC;AAE9C,IAAMC,0CAA0C;AA4BhD,SAASC,iCACdC,SAA8C;AAE9C,MAAIA,YAAY,OAAO;AACrB,WAAO;EACT;AACA,SAAO;IACLC,UAAUD,SAASC,YAAYJ;IAC/BK,WAAWF,SAASE,aAAaJ;EACnC;AACF;AAVgBC;AA2BhB,SAASI,MAAMC,IAAU;AACvB,SAAO,IAAIC,QAAQ,CAACC,YAAAA;AAClBC,eAAWD,SAASF,EAAAA;EACtB,CAAA;AACF;AAJSD;AAcT,eAAsBK,yBACpBC,IACAT,SACAU,SAAyC;AAEzC,MAAIV,YAAY,OAAO;AACrB,WAAOS,GAAAA;EACT;AACA,QAAMR,WAAWD,QAAQC,YAAYJ;AACrC,QAAMK,YAAYF,QAAQE,aAAaJ;AACvC,QAAMa,WAAWX,QAAQW,YAAYhB;AAErC,MAAIiB,UAAU;AACd,aAAS;AACP,QAAI;AACF,aAAO,MAAMH,GAAAA;IACf,SAASrB,OAAO;AACd,UAAIsB,SAASG,qBAAqBzB,KAAAA,MAAW,MAAM;AACjD,cAAMA;MACR;AACA,YAAM0B,iBAAiBF,UAAUX;AACjC,UAAI,CAACa,kBAAkB,CAACH,SAASvB,KAAAA,GAAQ;AACvC,cAAMA;MACR;AACAsB,eAASK,UAAUH,SAASxB,KAAAA;AAC5B,YAAMe,MAAMD,YAAYU,OAAAA;AACxBA,iBAAW;IACb;EACF;AACF;AA7BsBJ;;;AFjBtB,SAASQ,eACPC,OACAC,iBACAC,OAAoC;AAEpC,MAAID,oBAAoBE,QAAW;AACjC,WAAOF;EACT;AACA,SAAOC,UAAUC,SAAY,OAAOC,aAAaJ,OAAOE,KAAAA;AAC1D;AATSH;AAYT,SAASM,kBAAkBC,UAAmB;AAC5C,QAAMC,QAAQD,SACXE,IAAI,CAACC,SAASC,UAAAA;AACb,UAAMC,QAAQF,QAAQG,WAAWT,SAAY,KAAKM,QAAQG,MAAM,MAAM;AACtE,WAAO,IAAIF,QAAQ,CAAA,IAAKC,KAAAA,IAASF,QAAQI,IAAI;EAC/C,CAAA,EACCC,KAAK,MAAA;AACR,SAAO;EAAwBP,KAAAA;;;AACjC;AARSF;AAgDF,IAAMU,qBAAN,cAAiCC,MAAAA;EA1KxC,OA0KwCA;;;EACtC,cAAc;AACZ,UAAM,4BAAA;AACN,SAAKC,OAAO;EACd;AACF;AAMO,IAAMC,uBAAuB;AAGpC,eAAeC,cAAcC,QAAgCC,KAAkB;AAC7E,SAAO,OAAOD,WAAW,aAAaA,OAAOC,GAAAA,IAAOD;AACtD;AAFeD;AAUf,eAAeG,oBAAoBC,MAAqBC,OAAoB;AAC1E,QAAMH,MAAqB;IACzBI,OAAOD,MAAMC;IACbC,WAAWF,MAAME,aAAa;IAC9B,GAAIF,MAAMG,gBAAgBxB,SAAY;MAAEwB,aAAaH,MAAMG;IAAY,IAAI,CAAC;EAC9E;AACA,QAAMC,WAAW;IAAC,MAAMT,cAAcI,KAAKM,cAAcR,GAAAA;;AACzD,aAAWS,cAAcP,KAAKQ,sBAAsB,CAAA,GAAI;AACtD,UAAMC,UAAU,MAAMF,WAAWT,GAAAA;AACjC,QAAIW,YAAY,QAAQA,QAAQC,SAAS,GAAG;AAC1CL,eAASM,KAAKF,OAAAA;IAChB;EACF;AACA,SAAOJ,SAASd,KAAK,MAAA;AACvB;AAdeQ;AAiBf,SAASa,YAAYX,OAAc;AACjC,MAAI,OAAOA,UAAU,YAAYA,UAAU,QAAQ,UAAUA,OAAO;AAClE,UAAMY,OAAQZ,MAA4BY;AAC1C,QAAI,OAAOA,SAAS,UAAU;AAC5B,aAAOA;IACT;EACF;AACA,SAAOC,KAAKC,UAAUd,KAAAA;AACxB;AARSW;AAUT,SAASI,YAAYC,UAAgB;AACnC,QAAMC,UAAUD,SAASE,KAAI,EAAGC,QAAQ,QAAQ,GAAA;AAChD,SAAOF,QAAQR,SAAS,KAAK,GAAGQ,QAAQG,MAAM,GAAG,EAAA,CAAA,QAAWH,WAAW;AACzE;AAHSF;AAMT,IAAMM,mBAAN,MAAMA,0BAAyB7B,MAAAA;EAnO/B,OAmO+BA;;;EAC7B,YAAY8B,UAAkBC,IAAY;AACxC,UAAM,SAASD,QAAAA,kBAA0BC,EAAAA,YAAc;AACvD,SAAK9B,OAAO;EACd;AACF;AAGO,SAAS+B,gBAAmBC,MAAkBF,IAAYD,UAAgB;AAC/E,SAAO,IAAII,QAAW,CAACC,SAASC,WAAAA;AAC9B,UAAMC,QAAQC,WAAW,MAAMF,OAAO,IAAIP,iBAAiBC,UAAUC,EAAAA,CAAAA,GAAMA,EAAAA;AAC3EE,SAAKM,KACH,CAACC,UAAAA;AACCC,mBAAaJ,KAAAA;AACbF,cAAQK,KAAAA;IACV,GACA,CAACE,UAAAA;AACCD,mBAAaJ,KAAAA;AACbD,aAAOM,KAAAA;IACT,CAAA;EAEJ,CAAA;AACF;AAdgBV;AAiBhB,SAASW,eAAe9C,MAAc+C,OAAa;AACjD,QAAMhD,SAASC,KAAKgD,MAAM,aAAA,IAAiB,CAAA,KAAMhD;AACjD,MAAI;AACF,UAAMiD,SAAkBzB,KAAK0B,MAAMnD,MAAAA;AACnC,QAAIoD,MAAMC,QAAQH,MAAAA,GAAS;AACzB,aAAOA,OAAOI,OAAO,CAACC,SAAyB,OAAOA,SAAS,QAAA,EAAUvB,MAAM,GAAGgB,KAAAA;IACpF;EACF,QAAQ;EAER;AACA,SAAO,CAAA;AACT;AAXSD;AAiBT,eAAeS,kBACbC,OACAC,UACAV,OAAa;AAEb,QAAMW,UAAsB;IAAEC,OAAO,6BAAA;IAAO,GAAP;IAAUC,KAAK,6BAAA;IAAO,GAAP;IAAUC,MAAM,6BAAA;IAAO,GAAP;EAAS;AAC7E,QAAMC,OAAO,MAAMN,MAAMO,QAAQ;IAC/BC,QAAQ,mDAAmDjB,KAAAA;IAC3DU;IACAQ,OAAO,CAAA;IACPC,MAAMR;EACR,CAAA;AACA,SAAO;IACLS,WAAWrB,eAAegB,KAAK9D,MAAM+C,KAAAA;IACrC5D,OAAO2E,KAAK3E;IACZ,GAAI2E,KAAKM,YAAY9E,SAAY;MAAE8E,SAASN,KAAKM;IAAQ,IAAI,CAAC;EAChE;AACF;AAjBeb;AAiCf,eAAec,QACbC,OACAC,OACAC,SACAC,KACAC,WAAgD;AAEhD,MAAI/B;AACJ,QAAMgC,MACJ,SACAL,OACA,YAAA;AACE3B,YAAQ,MAAM8B,IAAAA;AACd,WAAOC,UAAU/B,KAAAA;EACnB,GACA6B,SACA;IAAEI,SAASL;EAAM,CAAA;AAEnB,SAAO5B;AACT;AAnBe0B;AA0BR,SAASQ,aACdN,OACAO,MACAL,KAAmC;AAEnC,SAAOJ,QAAQ,YAAYE,OAAO;IAAEA;IAAOO;EAAK,GAAGL,KAAK,CAACX,UAAU;IACjE,GAAIA,KAAKM,YAAY9E,SAAY;MAAE8E,SAASN,KAAKM;IAAQ,IAAI,CAAC;IAC9DW,aAAajB,KAAK3E,MAAM4F;IACxBC,cAAclB,KAAK3E,MAAM6F;IACzBC,YAAYnB,KAAK9D,KAAKoB;IACtB8D,WAAWpB,KAAKoB,UAAU9D;EAC5B,EAAA;AACF;AAZgByD;AAmBT,SAASM,mBACdZ,OACAa,MACAX,KAAqB;AAErB,SAAOJ,QAAQ,kBAAkBE,OAAO;IAAEA;IAAO,GAAGa;EAAK,GAAGX,KAAK,OAAO,CAAC,EAAA;AAC3E;AANgBU;AAahB,eAAsBE,aACpB3E,MACAC,OACA2E,OAAqB;AAErB,QAAMC,WAAW7E,KAAK6E,YAAY;AAClC,MAAIvB,SAAS,MAAMvD,oBAAoBC,MAAMC,KAAAA;AAE7C,MAAID,KAAK8E,UAAUlG,QAAW;AAC5B,UAAMkG,QAAQ9E,KAAK8E;AACnB,UAAMC,QAAQ,MAAMH,MAAMR,KAAK,eAAe,MAAMU,MAAME,MAAM/E,MAAMC,MAAM+E,IAAIjF,KAAKkF,GAAG,CAAA;AACxF,QAAI,CAACH,MAAMI,aAAa;AACtBC,gCAA0B;QACxBC,SAASpF,MAAMC,MAAM+E;QACrBK,YAAYP,MAAMO;QAClBC,aAAaR,MAAMQ;MACrB,CAAA;AACA,YAAM,IAAI/F,mBAAAA;IACZ;EACF;AAEA,MAAIS,MAAMuF,eAAe,MAAM;AAG7B,UAAMZ,MAAMR,KAAK,uBAAuB,YAAA;AACtC,YAAMqB,WAAW,MAAMzF,KAAK0F,MAAMC,UAAU1F,MAAM2F,QAAQ;AAC1D,YAAM7C,WAAW0C,UAAU1C,YAAY,CAAA;AACvC,UAAI8C,gBAAgB;AACpB,eAAS1G,QAAQ4D,SAASrC,SAAS,GAAGvB,SAAS,GAAGA,SAAS,GAAG;AAC5D,YAAI4D,SAAS5D,KAAAA,GAAQ2G,SAAS,QAAQ;AACpCD,0BAAgB1G;AAChB;QACF;MACF;AACA,YAAM4G,eAAehD,SAAS8C,gBAAgB,CAAA;AAC9C,UAAIE,iBAAiBnH,QAAW;AAC9B,cAAMoB,KAAK0F,MAAMM,aAAa/F,MAAM2F,UAAUG,aAAad,EAAE;MAC/D;IACF,CAAA;EACF,OAAO;AACL,UAAML,MAAMR,KAAK,gBAAgB,MAC/BpE,KAAK0F,MAAMO,cAAc;MACvBL,UAAU3F,MAAM2F;MAChBE,MAAM;MACNI,SAASjG,MAAMgB;MACf,GAAIhB,MAAMkG,gBAAgBvH,SAAY;QAAEuH,aAAalG,MAAMkG;MAAY,IAAI,CAAC;IAC9E,CAAA,CAAA;EAEJ;AAEA,QAAMC,SAAS,MAAMxB,MAAMR,KAAK,eAAe,MAAMpE,KAAK0F,MAAMC,UAAU1F,MAAM2F,QAAQ,CAAA;AACxF,QAAMS,iBAAiCD,QAAQrD,YAAY,CAAA,GAAI9D,IAAI,CAACqH,aAAa;IAC/ER,MAAMQ,QAAQR;IACdI,SAASI,QAAQJ;IACjB,GAAII,QAAQ9B,cAAc5F,SAAY;MAAE4F,WAAW8B,QAAQ9B;IAAU,IAAI,CAAC;IAC1E,GAAI8B,QAAQC,gBAAgB3H,SAAY;MAAE2H,aAAaD,QAAQC;IAAY,IAAI,CAAC;IAChF,GAAID,QAAQH,gBAAgBvH,SAAY;MAAEuH,aAAaG,QAAQH;IAAY,IAAI,CAAC;EAClF,EAAA;AAEA,QAAMK,SAAS,MAAM5B,MAAM6B,SAAQ;AACnC,MAAIC,WAAW;AACf,MAAIC,QAAQ;AACZ,MAAIC,aAAa;AACjB,MAAIC,cAAc;AAElBC,yBAAuB;IACrBjD,OAAOe,MAAMf;IACb+B,UAAU3F,MAAM2F;IAChBP,SAASpF,MAAMC,MAAM+E;IACrB,GAAIhF,MAAME,cAAcvB,SAAY;MAAEuB,WAAWF,MAAME;IAAU,IAAI,CAAC;EACxE,CAAA;AAIA,QAAM4G,YAAY,MAAMnC,MAAMR,KAAK,kBAAkB,MAAMzC,QAAQC,QAAQoF,KAAKC,IAAG,CAAA,CAAA;AAEnF,QAAMrC,MAAMR,KAAK,qBAAqB,YAAA;AAGpC,UAAM8C,aAAaC,WAAW,QAAA,EAAUC,OAAO9D,MAAAA,EAAQ+D,OAAO,KAAA;AAC9D,UAAMrH,KAAK0F,MAAM4B,iBAAiB;MAChCzD,OAAOe,MAAMf;MACb+B,UAAU3F,MAAM2F;MAChB2B,UAAUtH,MAAMC,MAAM+E;MACtB,GAAIhF,MAAME,cAAcvB,SAAY;QAAEuB,WAAWF,MAAME;MAAU,IAAI,CAAC;MACtE+G;IACF,CAAA;EACF,CAAA;AAKA,MAAIM;AACJ,MAAIxH,KAAKyH,cAAc7I,QAAW;AAChC,UAAM6I,YAAYzH,KAAKyH;AACvB,UAAMC,OAAO1H,KAAK2H,iBAAiB;AACnC,UAAM5I,WAAW,MAAM6F,MAAMR,KAAK,YAAY,MAC5CT,QACE,aACAiB,MAAMf,OACN;MAAEA,OAAOe,MAAMf;MAAO+D,aAAa3H,MAAMgB,SAASP;MAAQgH;IAAK,GAC/D,MAAMD,UAAUI,SAAS5H,MAAMgB,UAAU;MAAEyG;IAAK,CAAA,GAChD,CAACI,eAAe;MAAEzF,OAAOyF,UAAUpH;IAAO,EAAA,CAAA;AAG9C,QAAI3B,SAAS2B,SAAS,GAAG;AACvB8G,yBAAmBzI;AACnBuE,eAAS,GAAGA,MAAAA;;EAAaxE,kBAAkBC,QAAAA,CAAAA;IAC7C;AACAgJ,0BAAsB;MAAElE,OAAOe,MAAMf;MAAOmE,OAAO/H,MAAMgB;MAAUoB,OAAOtD,SAAS2B;IAAO,CAAA;EAC5F;AAIA,MAAIuH,SAA8B,CAAA;AAClC,MAAIjI,KAAKkI,iBAAiBtJ,QAAW;AACnC,UAAMsJ,eAAelI,KAAKkI;AAC1BD,aAAS,MAAMrD,MAAMR,KAAK,gBAAgB,MAAM8D,aAAaC,kBAAiB,CAAA;EAChF;AACA,QAAMC,eAAe,IAAIC,IAAIJ,OAAOhJ,IAAI,CAACN,UAAU;IAACA,MAAM+E;IAAS/E;GAAM,CAAA;AAMzE,WAAS2J,IAAI,GAAGA,IAAIzD,UAAUyD,KAAK,GAAG;AAIpC,UAAM1D,MAAMR,KAAK,qBAAqBkE,CAAAA,IAAK,YAAA;AACzC,YAAM9B,OAAOvD,MAAMsF,kBAAkB;QAAEC,MAAM;MAAa,CAAA,CAAA;IAC5D,CAAA;AAEA,QAAIpF;AACJ,QAAIwB,MAAM6D,aAAa;AAGrBrF,aAAO,MAAMwB,MAAM6D,YAAYH,GAAG;QAChC,GAAIrI,MAAME,cAAcvB,SAAY;UAAEuB,WAAWF,MAAME;QAAU,IAAI,CAAC;QACtEmD;QACAP,UAAUsD;QACVnG,OAAOD,MAAMC;MACf,CAAA;IACF,OAAO;AACL,YAAMqD,QAAQ,MAAMvD,KAAK0I,SAASC,eAChC1I,MAAMC,OACNF,KAAK4I,aACL5I,KAAK6I,aAAa;AAEpBzF,aAAO,MAAMwB,MAAMR,KAAK,OAAOkE,CAAAA,IAAK,MAClCnE,aAAaS,MAAMf,OAAOyE,GAAG,MAC3BtI,KAAK8C,MAAMO,QAAQ;QAAEC;QAAQP,UAAUsD;QAAe9C;QAAOC,MAAMgD;MAAO,CAAA,CAAA,CAAA;IAGhF;AAEA,UAAMsC,kBAAkB1F,KAAKM,WAAW1D,KAAK0D,WAAW;AAGxD,UAAMqF,UAAUvK,eAAe4E,KAAK3E,OAAO2E,KAAK2F,SAASX,aAAaY,IAAIF,eAAAA,CAAAA;AAG1E,UAAMG,oBAAuC7F,KAAKoB,UAAUvF,IAAI,CAACyF,UAAU;MACzE,GAAGA;MACH8D,MAAMxI,KAAK0I,SAASQ,KAAKxE,KAAKhF,IAAI,GAAG8I,QAAQ;IAC/C,EAAA;AAEA,UAAM5D,MAAMR,KAAK,iBAAiBkE,CAAAA,IAAK,MACrCtI,KAAK0F,MAAMyD,YAAY;MACrBvD,UAAU3F,MAAM2F;MAChB2B,UAAUtH,MAAMC,MAAM+E;MACtBvB,SAASoF;MACTM,SAAS;MACT3K,OAAO2E,KAAK3E;;MAEZ,GAAI2E,KAAK2F,YAAYnK,SAAY;QAAEmK,SAAS3F,KAAK2F;MAAQ,IAAI,CAAC;IAChE,CAAA,CAAA;AAEF,QAAI/I,KAAK8E,UAAUlG,QAAW;AAC5B,YAAMkG,QAAQ9E,KAAK8E;AACnB,YAAMF,MAAMR,KAAK,cAAckE,CAAAA,IAAK,MAClCxD,MAAMuE,KAAKpJ,MAAMC,MAAM+E,IAAIjF,KAAKkF,KAAK9B,KAAK3E,MAAM4F,cAAcjB,KAAK3E,MAAM6F,YAAY,CAAA;IAEzF;AAEAqC,aAAS;AACTC,kBAAcxD,KAAK3E,MAAM4F;AACzBwC,mBAAezD,KAAK3E,MAAM6F;AAC1BoC,eAAWtD,KAAK9D;AAChBgK,wBAAoB;MAClBzF,OAAOe,MAAMf;MACb+B,UAAU3F,MAAM2F;MAChBE,MAAM;MACNvB,YAAYnB,KAAK9D,KAAKoB;IACxB,CAAA;AAIA,UAAM6I,cAAcnG,KAAKoB,UAAU9D,WAAW;AAC9C,QAAI+C;AACJ,QAAI8F,eAAevJ,KAAKwJ,mBAAmB5K,UAAaoB,KAAKwJ,iBAAiB,GAAG;AAC/E,YAAMnH,QAAQrC,KAAKwJ;AAGnB,YAAMC,YAAY,MAAM7E,MAAMR,KAAK,aAAakE,CAAAA,IAAK,MACnD3E,QACE,cACAiB,MAAMf,OACN;QAAEA,OAAOe,MAAMf;QAAOO,MAAMkE;QAAGjG;MAAM,GACrC,MACEQ,kBACE7C,KAAK8C,OACL;WAAIuD;QAAe;UAAEP,MAAM;UAAaI,SAAS9C,KAAK9D;QAAK;SAC3D+C,KAAAA,GAEJ,CAACqH,YAAY;QACXjG,WAAWiG,OAAOjG,UAAU/C;QAC5B2D,aAAaqF,OAAOjL,MAAM4F;QAC1BC,cAAcoF,OAAOjL,MAAM6F;QAC3B,GAAIoF,OAAOhG,YAAY9E,SAAY;UAAE8E,SAASgG,OAAOhG;QAAQ,IAAI,CAAC;MACpE,EAAA,CAAA;AAGJ,UAAI+F,UAAUhG,UAAU/C,SAAS,GAAG;AAClC+C,oBAAYgG,UAAUhG;MACxB;AACA,YAAMmB,MAAMR,KAAK,2BAA2BkE,CAAAA,IAAK,MAC/CtI,KAAK0F,MAAMyD,YAAY;QACrBvD,UAAU3F,MAAM2F;QAChB2B,UAAUtH,MAAMC,MAAM+E;QACtBvB,SAAS+F,UAAU/F,WAAW1D,KAAK0D,WAAW;QAC9C0F,SAAS;QACT3K,OAAOgL,UAAUhL;MACnB,CAAA,CAAA;IAEJ;AAEA,UAAMkL,YAAY,MAAM/E,MAAMR,KAAK,qBAAqBkE,CAAAA,IAAK,MAC3DtI,KAAK0F,MAAMO,cAAc;MACvBL,UAAU3F,MAAM2F;MAChBE,MAAM;MACNI,SAAS9C,KAAK9D;MACdb,OAAO;QAAE,GAAG2E,KAAK3E;QAAOsK;MAAQ;MAChC,GAAI9I,MAAME,cAAcvB,SAAY;QAAEuB,WAAWF,MAAME;MAAU,IAAI,CAAC;MACtE,GAAI8I,kBAAkBvI,SAAS,IAAI;QAAE8D,WAAWyE;MAAkB,IAAI,CAAC;MACvE,GAAIxF,cAAc7E,SAAY;QAAE6E;MAAU,IAAI,CAAC;IACjD,CAAA,CAAA;AAKF,UAAMmG,mBAAiC;MACrC9D,MAAM;MACNI,SAAS9C,KAAK9D;MACd,GAAI2J,kBAAkBvI,SAAS,IAAI;QAAE8D,WAAWyE;MAAkB,IAAI,CAAC;IACzE;AACA5C,kBAAc1F,KAAKiJ,gBAAAA;AAKnB,QAAItB,MAAM,KAAKd,qBAAqB5I,QAAW;AAC7C,YAAMG,WAAWyI;AACjB,YAAMqC,aAAa,YAAYF,UAAU1E,EAAE;AAC3C,YAAML,MAAMR,KAAK,qBAAqBuF,UAAU1E,EAAE,IAAI,YAAA;AACpD,cAAMjF,KAAK0F,MAAMoE,eAAe;UAC9BD;UACAE,WAAWJ,UAAU1E;UACrB1D,UAAU;UACVyI,UAAU;UACV/J,OAAO;YAAE+H,OAAO/H,MAAMgB;UAAS;UAC/BgJ,QAAQ;UACRpG,OAAOe,MAAMf;QACf,CAAA;AACA,cAAM7D,KAAK0F,MAAMwE,eAAe;UAAEL;UAAYI,QAAQ;UAAYE,QAAQ;YAAEpL;UAAS;QAAE,CAAA;MACzF,CAAA;IACF;AAEA,QAAIwK,aAAa;AACf,YAAM3E,MAAMR,KAAK,sBAAsBkE,CAAAA,IAAK,YAAA;AAC1C,cAAM9B,OAAOvD,MAAMsF,kBAAkB;UAAEC,MAAM;UAAe/J,OAAO2E,KAAK3E;UAAOsK;QAAQ,CAAA,CAAA;MACzF,CAAA;AACA;IACF;AAEA,UAAMqB,UAAwB,CAAA;AAC9B,eAAW1F,QAAQuE,mBAAmB;AACpC,YAAMC,OAAOlJ,KAAK0I,SAASQ,KAAKxE,KAAKhF,IAAI;AACzC,YAAMsK,WAAWtF,KAAK8D,QAAQ;AAC9B,YAAM1I,MAAiB;QACrBI,OAAOD,MAAMC;QACb0F,UAAU3F,MAAM2F;QAChB/B,OAAOe,MAAMf;QACbwG,WAAWzF,MAAMf;QACjB,GAAI5D,MAAME,cAAcvB,SAAY;UAAEuB,WAAWF,MAAME;QAAU,IAAI,CAAC;QACtE,GAAIF,MAAMG,gBAAgBxB,SAAY;UAAEwB,aAAaH,MAAMG;QAAY,IAAI,CAAC;QAC5E,GAAIJ,KAAKsK,SAAS1L,SAAY;UAAE0L,MAAMtK,KAAKsK;QAAK,IAAI,CAAC;MACvD;AAIA,UAAIN,aAAa,SAAS;AACxB,cAAMO,cAAcrB,MAAMqB,eAAe7F,KAAKhF;AAC9C,cAAMmB,OAAOD,YAAY8D,KAAKzE,KAAK;AACnC,cAAM2E,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMoE,eAAe;UACxBD,YAAYnF,KAAKO;UACjB8E,WAAWJ,UAAU1E;UACrB1D,UAAUmD,KAAKhF;UACfsK,UAAU;UACV/J,OAAOyE,KAAKzE;UACZgK,QAAQ;UACRpG,OAAOe,MAAMf;QACf,CAAA,CAAA;AAGF,cAAM2G,aAAavK,MAAMwK,mBAAmB,MAAM9K;AAClD+K,8BAAsB;UACpB7G,OAAOe,MAAMf;UACb8G,SAASJ;UACT,GAAItK,MAAME,cAAcvB,SAAY;YAAEgM,WAAW3K,MAAME;UAAU,IAAI,CAAC;QACxE,CAAA;AACA,YAAI0K;AACJ,YAAIL,WAAW;AACbK,gBAAM;YAAEvL,MAAM,8BAA8BK,oBAAAA;UAAgC;QAC9E,WAAWiF,MAAMkG,UAAU;AACzBD,gBAAM,MAAMjG,MAAMkG,SAASP,aAAa1J,IAAAA;QAC1C,OAAO;AACLgK,gBAAM;YAAEvL,MAAM,gDAAgDiL,WAAAA;UAAgB;QAChF;AACA,cAAM3F,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMwE,eAAe;UAAEL,YAAYnF,KAAKO;UAAIgF,QAAQ;UAAYE,QAAQU;QAAI,CAAA,CAAA;AAEnFT,gBAAQzJ,KAAK;UAAEsE,IAAIP,KAAKO;UAAIvF,MAAMgF,KAAKhF;UAAMyK,QAAQU;QAAI,CAAA;AACzD;MACF;AAIA,UAAIE,aAAa9K,MAAMC,MAAM+E;AAC7B,UAAI+E,aAAa,UAAU;AACzB,cAAMpF,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMoE,eAAe;UACxBD,YAAYnF,KAAKO;UACjB8E,WAAWJ,UAAU1E;UACrB1D,UAAUmD,KAAKhF;UACfsK,UAAU;UACV/J,OAAOyE,KAAKzE;UACZgK,QAAQ;UACRpG,OAAOe,MAAMf;QACf,CAAA,CAAA;AAEF,cAAMmH,WAAW,MAAMpG,MAAMqG,cAAcvG,MAAM5E,GAAAA;AACjDiL,qBAAaC,SAASE,iBAAiBjL,MAAMC,MAAM+E;AACnD,YAAI,CAAC+F,SAASG,UAAU;AACtB,gBAAMvG,MAAMR,KAAK,sBAAsBM,KAAKO,EAAE,IAAI,MAChDjF,KAAK0F,MAAMwE,eAAe;YACxBL,YAAYnF,KAAKO;YACjBgF,QAAQ;YACRiB,eAAeH;YACf,GAAIC,SAASI,WAAWxM,SAAY;cAAEuD,OAAO6I,SAASI;YAAO,IAAI,CAAC;UACpE,CAAA,CAAA;AAEFhB,kBAAQzJ,KAAK;YACXsE,IAAIP,KAAKO;YACTvF,MAAMgF,KAAKhF;YACXyK,QAAQ;cAAEkB,UAAU;cAAMD,QAAQJ,SAASI,UAAU;YAAmB;YACxEjJ,OAAO;UACT,CAAA;AACAmJ,+BAAqB;YACnBzH,OAAOe,MAAMf;YACbtC,UAAUmD,KAAKhF;YACfsK;YACAC,QAAQ;UACV,CAAA;AACA;QACF;MACF,OAAO;AACL,cAAMrF,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMoE,eAAe;UACxBD,YAAYnF,KAAKO;UACjB8E,WAAWJ,UAAU1E;UACrB1D,UAAUmD,KAAKhF;UACfsK,UAAU;UACV/J,OAAOyE,KAAKzE;UACZgK,QAAQ;UACRpG,OAAOe,MAAMf;QACf,CAAA,CAAA;MAEJ;AAEA,YAAMkD,aAAYC,KAAKC,IAAG;AAC1B,UAAI;AACF,YAAIkD;AACJ,YAAIvF,MAAM2G,cAAc;AACtB,gBAAMC,UAAuB;YAC3BtL,OAAOD,MAAMC;YACb0F,UAAU3F,MAAM2F;YAChB/B,OAAOe,MAAMf;YACbwG,WAAWzF,MAAMf;YACjB,GAAI5D,MAAME,cAAcvB,SAAY;cAAEuB,WAAWF,MAAME;YAAU,IAAI,CAAC;YACtE,GAAIF,MAAMG,gBAAgBxB,SAAY;cAAEwB,aAAaH,MAAMG;YAAY,IAAI,CAAC;UAC9E;AACA,gBAAMqL,WAA6B;YACjClK,UAAUmD,KAAKhF;YACfO,OAAOyE,KAAKzE;YACZH,KAAK0L;YACL,GAAIxL,KAAK0L,kBAAkB9M,SAAY;cAAE+M,WAAW3L,KAAK0L;YAAc,IAAI,CAAC;;;YAG5EE,gBAAgBC,iCAAiC7L,KAAK8L,kBAAkB;UAC1E;AAGA3B,mBAAS,MAAMvF,MAAM2G,aAAa7G,MAAM+G,QAAAA;QAC1C,OAAO;AACL,gBAAMM,aAAanH,MAAMR,KAAK,QAAQM,KAAKO,EAAE,IAAI,MAC/CR,mBACEG,MAAMf,OACN;YAAEgG,YAAYnF,KAAKO;YAAI1D,UAAUmD,KAAKhF;YAAMsK;UAAS,GACrD,MACEgC,yBACE,MAAMhM,KAAK0I,SAASuD,OAAOvH,KAAKhF,MAAMgF,KAAKzE,OAAOH,KAAKE,KAAK4I,WAAW,GACvE5I,KAAK8L,sBAAsB,CAAC,GAC5B;YACE,GAAIlH,MAAMsH,uBAAuBtN,SAC7B;cAAEsN,oBAAoBtH,MAAMsH;YAAmB,IAC/C,CAAC;YACLC,SAAS,wBAACC,SAASC,eAAAA;AACjBC,oCAAsB;gBACpB/K,UAAUmD,KAAKhF;gBACfmK,YAAYnF,KAAKO;gBACjBmH;gBACA9F,SACE+F,sBAAsB5M,QAAQ4M,WAAW/F,UAAUiG,OAAOF,UAAAA;cAC9D,CAAA;YACF,GARS;UASX,CAAA,CAAA,CAAA;AAIRlC,mBACEnK,KAAK0L,kBAAkB9M,SACnB,MAAM6C,gBAAgBsK,YAAY/L,KAAK0L,eAAehH,KAAKhF,IAAI,IAC/D,MAAMqM;QACd;AACA,cAAMS,cAAcxF,KAAKC,IAAG,IAAKF;AACjC,cAAMnC,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMwE,eAAe;UACxBL,YAAYnF,KAAKO;UACjBgF,QAAQ;UACRE;UACAqC;UACA,GAAIxC,aAAa,WAAW;YAAEkB,eAAeH;UAAW,IAAI,CAAC;QAC/D,CAAA,CAAA;AAEFX,gBAAQzJ,KAAK;UAAEsE,IAAIP,KAAKO;UAAIvF,MAAMgF,KAAKhF;UAAMyK;QAAO,CAAA;AACpDmB,6BAAqB;UACnBzH,OAAOe,MAAMf;UACbtC,UAAUmD,KAAKhF;UACfsK;UACAC,QAAQ;UACRwC,YAAYD;QACd,CAAA;MACF,SAASrK,OAAO;AAId,YAAIyC,MAAMsH,qBAAqB/J,KAAAA,MAAW,MAAM;AAC9C,gBAAMA;QACR;AACA,cAAMqK,cAAcxF,KAAKC,IAAG,IAAKF;AACjC,cAAMT,UAAUnE,iBAAiB1C,QAAQ0C,MAAMmE,UAAUiG,OAAOpK,KAAAA;AAChE,cAAMyC,MAAMR,KAAK,oBAAoBM,KAAKO,EAAE,IAAI,MAC9CjF,KAAK0F,MAAMwE,eAAe;UACxBL,YAAYnF,KAAKO;UACjBgF,QAAQ;UACR9H,OAAOmE;UACPkG;QACF,CAAA,CAAA;AAEFpC,gBAAQzJ,KAAK;UAAEsE,IAAIP,KAAKO;UAAIvF,MAAMgF,KAAKhF;UAAMyK,QAAQ;UAAMhI,OAAOmE;QAAQ,CAAA;AAC1EgF,6BAAqB;UACnBzH,OAAOe,MAAMf;UACbtC,UAAUmD,KAAKhF;UACfsK;UACAC,QAAQ;UACRwC,YAAYD;QACd,CAAA;MACF;IACF;AAEA5C,qBAAiBrD,cAAc6D;AAK/B,UAAMxF,MAAMR,KAAK,uBAAuBkE,CAAAA,IAAK,YAAA;AAC3C,iBAAWoB,UAAUU,SAAS;AAC5B,cAAM5D,OAAOvD,MACXsF,kBACEmB,OAAOvH,UAAUvD,SACb;UAAE4J,MAAM;UAAqBvD,IAAIyE,OAAOzE;UAAI9C,OAAOuH,OAAOvH;QAAM,IAChE;UAAEqG,MAAM;UAAevD,IAAIyE,OAAOzE;UAAIkF,QAAQT,OAAOS;QAAO,CAAA,CAAA;MAGtE;IACF,CAAA;AAEA,UAAMvF,MAAMR,KAAK,sBAAsBkE,CAAAA,IAAK,YAAA;AAC1C,YAAM9B,OAAOvD,MAAMsF,kBAAkB;QAAEC,MAAM;QAAe/J,OAAO2E,KAAK3E;QAAOsK;MAAQ,CAAA,CAAA;IACzF,CAAA;EACF;AAEA,MAAI3C,WAAW,SAASA,OAAOsG,UAAU,MAAMtG,OAAOsG,UAAU,aAAa;AAC3E,UAAM9H,MAAMR,KAAK,iBAAiB,MAChCpE,KAAK0F,MAAMiH,SAAS1M,MAAM2F,UAAU5E,YAAYf,MAAMgB,QAAQ,CAAA,CAAA;EAElE;AAIA,QAAM2D,MAAMR,KAAK,mBAAmB,YAAA;AAClC,UAAMpE,KAAK0F,MAAMkH,eAAe;MAC9B/I,OAAOe,MAAMf;MACboG,QAAQ;MACRwC,YAAYzF,KAAKC,IAAG,IAAKF;IAC3B,CAAA;EACF,CAAA;AAEA,QAAMP,OAAOtD,IAAG;AAChB2J,0BAAwB;IACtBhJ,OAAOe,MAAMf;IACb+B,UAAU3F,MAAM2F;IAChBe;IACAtC,aAAauC;IACbtC,cAAcuC;EAChB,CAAA;AACA,SAAO;IAAEvH,MAAMoH;EAAS;AAC1B;AA3hBsB/B;","names":["AGENT_OPTIONS","Symbol","for","AGENT_STORE","AGENT_RUNNER","AGENT_DURABLE_RUNNER","AGENT_SINK","AGENT_MODEL","AGENT_ROLES_POLICY","AGENT_QUOTA_STORE","AGENT_TOOL_REGISTRY","AGENT_REGISTRY","AGENT_ACTOR_RESOLVER","AGENT_GOVERNANCE_QUERIES","AGENT_PRICING_STORE","AGENT_RETRIEVER","AGENT_EMBEDDING_PROVIDER","AGENT_DEPS_FACTORY","AGENT_PROMPT_CONTRIBUTORS","AGENT_ACTOR_DIRECTORY","AGENT_ATTACHMENT_STAGING","AGENT_APPROVAL_PORT","AgentStreamError","Error","code","error","message","name","encoder","TextEncoder","encodeStreamEvent","event","encode","JSON","stringify","seedModelPrices","store","prices","price","upsertModelPrice","THREAD_DETAIL_CONTENT_CHARS","truncateDetailContent","content","length","truncated","slice","estimateCost","usage","price","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","row","prices","costUsd","get","modelId","bucketByModel","rows","byModel","Map","bucket","requests","set","result","push","sort","left","right","localeCompare","bucketByActor","byActor","actorRef","totalTokens","threadIds","Set","add","threadId","threadCount","size","bucketByThread","threads","options","byThread","thread","includeUnknownThreads","title","slice","limit","rollupThreadUsage","rollup","bucketUsageTrend","byDay","day","dayBoundsUtc","range","start","Date","fromDay","end","toDay","filterToolsByRole","tools","actor","policy","checked","Promise","all","map","tool","allowed","can","filter","entry","filterToolsByAllowList","allowedTools","undefined","Set","has","name","AgentRegistry","definitions","Map","register","definition","set","name","get","has","list","values","ToolForbiddenError","Error","toolName","name","ToolNotFoundError","ToolInputInvalidError","issues","map","issue","message","join","ToolRegistry","entries","Map","register","spec","handler","set","has","get","allSpecs","values","entry","definitionsFor","actor","policy","allowedTools","roleScoped","filterToolsByRole","allowScoped","filterToolsByAllowList","kind","description","inputSchema","invoke","input","ctx","undefined","can","validation","validate","execute","value","DefaultRolesPolicy","defaultRoles","tool","allowed","roles","some","role","includes","createHash","trace","emit","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","publishAgentToolRetry","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","hasTransientShape","error","code","undefined","errno","sqlState","message","test","isTransientToolError","cause","DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS","DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS","resolveToolTransientRetryNumbers","setting","attempts","backoffMs","delay","ms","Promise","resolve","setTimeout","invokeWithTransientRetry","fn","options","classify","attempt","isControlFlowError","attemptsRemain","onRetry","resolveCostUsd","usage","reportedCostUsd","price","undefined","estimateCost","buildContextBlock","passages","items","map","passage","index","label","source","text","join","QuotaExceededError","Error","name","MAX_DELEGATION_DEPTH","resolvePrompt","prompt","ctx","resolveSystemPrompt","deps","input","actor","agentName","pageContext","sections","systemPrompt","contribute","promptContributors","section","length","push","extractTask","task","JSON","stringify","deriveTitle","userText","trimmed","trim","replace","slice","ToolTimeoutError","toolName","ms","withToolTimeout","work","Promise","resolve","reject","timer","setTimeout","then","value","clearTimeout","error","parseFollowUps","count","match","parsed","parse","Array","isArray","filter","item","generateFollowUps","model","messages","discard","write","end","fail","turn","runTurn","system","tools","sink","followUps","modelId","spanned","event","runId","payload","run","summarize","trace","traceId","traceLlmTurn","step","inputTokens","outputTokens","textLength","toolCalls","traceToolExecution","call","runAgentLoop","hooks","maxSteps","quota","state","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","attachments","thread","modelMessages","message","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","startedAt","Date","now","promptHash","createHash","update","digest","recordRunStart","actorRef","injectedPassages","retriever","topK","retrievalTopK","queryLength","retrieve","retrieved","publishAgentRetrieved","query","prices","pricingStore","listCurrentPrices","priceByModel","Map","i","encodeStreamEvent","kind","dispatchLlm","registry","definitionsFor","rolesPolicy","toolAllowList","resolvedModelId","costUsd","get","toolCallsWithKind","spec","recordUsage","purpose","bump","publishAgentMessage","isFinalTurn","followUpsCount","generated","result","assistant","assistantMessage","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","deciderRef","decision","awaitApproval","executedByRef","approved","reason","rejected","publishAgentToolCall","dispatchTool","stepCtx","envelope","toolTimeoutMs","timeoutMs","transientRetry","resolveToolTransientRetryNumbers","toolTransientRetry","invocation","invokeWithTransientRetry","invoke","isControlFlowError","onRetry","attempt","retryError","publishAgentToolRetry","String","executionMs","durationMs","title","setTitle","recordRunEnd","publishAgentRunFinished"]}
|
|
1
|
+
{"version":3,"sources":["../src/tokens.ts","../src/spi/token-stream-sink.ts","../src/stream-events.ts","../src/spi/pricing-store.ts","../src/spi/governance-queries.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.ts","../src/tool-retry.ts"],"sourcesContent":["/**\n * Public, cross-lib-discoverable DI tokens.\n *\n * These use `Symbol.for(...)` (the global symbol registry) on purpose: pnpm peer\n * multiplexing + dual ESM/CJS can load `core` more than once, and a plain `Symbol()`\n * would mint a distinct token per copy and break DI across package boundaries. A\n * registered symbol collapses every copy onto the same token, and lets a sibling lib\n * resolve our injectables by name without importing our internals.\n *\n * Naming convention (ecosystem-wide): `@dudousxd/nestjs-<lib>:<name>`.\n */\nexport const AGENT_OPTIONS = Symbol.for('@dudousxd/nestjs-agent:options');\nexport const AGENT_STORE = Symbol.for('@dudousxd/nestjs-agent:store');\nexport const AGENT_RUNNER = Symbol.for('@dudousxd/nestjs-agent:runner');\n/**\n * The durable runner, provided ONLY by `AgentDurableModule`. When `durable: true`, the module\n * binds `AGENT_RUNNER` to this via an optional injection, so a missing `AgentDurableModule`\n * fails with a clear error instead of a cryptic unresolved-dependency one.\n */\nexport const AGENT_DURABLE_RUNNER = Symbol.for('@dudousxd/nestjs-agent:durable-runner');\nexport const AGENT_SINK = Symbol.for('@dudousxd/nestjs-agent:sink');\nexport const AGENT_MODEL = Symbol.for('@dudousxd/nestjs-agent:model');\nexport const AGENT_ROLES_POLICY = Symbol.for('@dudousxd/nestjs-agent:roles-policy');\nexport const AGENT_QUOTA_STORE = Symbol.for('@dudousxd/nestjs-agent:quota-store');\nexport const AGENT_TOOL_REGISTRY = Symbol.for('@dudousxd/nestjs-agent:tool-registry');\nexport const AGENT_REGISTRY = Symbol.for('@dudousxd/nestjs-agent:agent-registry');\nexport const AGENT_ACTOR_RESOLVER = Symbol.for('@dudousxd/nestjs-agent:actor-resolver');\n/** The governance read-model (usage/spend/threads), consumed by the dashboard + telescope surfaces. */\nexport const AGENT_GOVERNANCE_QUERIES = Symbol.for('@dudousxd/nestjs-agent:governance-queries');\n/** The pricing WRITE side (`AgentPricingStore`) — seeds/updates the per-model rates cost is priced against. */\nexport const AGENT_PRICING_STORE = Symbol.for('@dudousxd/nestjs-agent:pricing-store');\n/** The RAG retrieval seam (`Retriever`) — vector/keyword search behind the agentic tool or inject mode. */\nexport const AGENT_RETRIEVER = Symbol.for('@dudousxd/nestjs-agent:retriever');\n/** The embedding provider (`EmbeddingProvider`) — text→vector for retrieval + ingestion. */\nexport const AGENT_EMBEDDING_PROVIDER = Symbol.for('@dudousxd/nestjs-agent:embedding-provider');\n// Per-agent deps factory. A Symbol.for token (not the class) so DI survives tsup's dual\n// index/durable bundles, which each get their own copy of the AgentDepsFactory class.\nexport const AGENT_DEPS_FACTORY = Symbol.for('@dudousxd/nestjs-agent:deps-factory');\n/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */\nexport const AGENT_PROMPT_CONTRIBUTORS = Symbol.for('@dudousxd/nestjs-agent:prompt-contributors');\n/**\n * Resolves opaque store `actorRef`s to human display labels for governance/dashboard read surfaces.\n * Optional — see {@link import('./spi/actor-directory.js').ActorDirectory}.\n */\nexport const AGENT_ACTOR_DIRECTORY = Symbol.for('@dudousxd/nestjs-agent:actor-directory');\n/**\n * Persists an uploaded attachment somewhere the model can fetch it from and returns a\n * `MessageAttachment`. Optional — see\n * {@link import('./spi/attachment-staging.js').AttachmentStagingStore}.\n */\nexport const AGENT_ATTACHMENT_STAGING = Symbol.for('@dudousxd/nestjs-agent:attachment-staging');\n/**\n * Console-side HITL approve/reject for the cross-thread approvals inbox. Optional — see\n * {@link import('./spi/approval-port.js').AgentApprovalPort}.\n */\nexport const AGENT_APPROVAL_PORT = Symbol.for('@dudousxd/nestjs-agent:approval-port');\n","/**\n * The \"data plane\": live token transport, decoupled from the durable control plane.\n *\n * The model turn writes deltas to a `SinkWriter` keyed by runId; the HTTP layer\n * `subscribe`s by runId and pipes the chunks to the browser as SSE. A late subscriber\n * (reconnect/resume) replays buffered chunks first, then follows live — which is what\n * makes streaming survive a dropped connection or a pod restart.\n */\nexport interface SinkWriter {\n write(chunk: Uint8Array): void | Promise<void>;\n /** Mark the run's stream finished (no more chunks). */\n end(): void | Promise<void>;\n /**\n * Terminate the run's stream with an error instead of a normal end. Subscribers replay any\n * buffered chunks first, then throw an {@link AgentStreamError} carrying this `code`/`message`\n * — so the transport can surface a typed failure frame instead of leaking it as assistant text.\n */\n fail(error: StreamError): void | Promise<void>;\n}\n\n/** A machine-readable stream failure. `code` is a stable slug; `message` is human-facing. */\nexport interface StreamError {\n code: string;\n message: string;\n}\n\n/**\n * Thrown out of {@link TokenStreamSink.subscribe} when a run ended via {@link SinkWriter.fail}.\n * Carries the structured {@link StreamError} so the HTTP layer can emit an `event: error` frame.\n */\nexport class AgentStreamError extends Error {\n readonly code: string;\n constructor(error: StreamError) {\n super(error.message);\n this.name = 'AgentStreamError';\n this.code = error.code;\n }\n}\n\nexport interface TokenStreamSink {\n /** Open (or reopen) the writer for a run. */\n open(runId: string): SinkWriter | Promise<SinkWriter>;\n /**\n * Replay buffered chunks for the run, then yield live ones until `end()`. Throws\n * {@link AgentStreamError} if the run was terminated with {@link SinkWriter.fail}.\n */\n subscribe(runId: string): AsyncIterable<Uint8Array>;\n /** Drop any buffer/resources for the run. */\n close(runId: string): void | Promise<void>;\n}\n","/**\n * The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.\n *\n * The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one\n * `JSON.stringify(event)\\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an\n * SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk\n * protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same\n * rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the\n * client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).\n *\n * Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:\n * the adapter owns model-parts → event, the transport owns event → UI-chunk.\n */\nimport type { MessageUsage } from './types.js';\n\nexport type AgentStreamEvent =\n | { kind: 'step-start' }\n /**\n * Closes the step opened by the matching `step-start`. Carries the model call's token usage and\n * `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a\n * fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.\n */\n | { kind: 'step-finish'; usage?: MessageUsage; costUsd?: number | null }\n | { kind: 'text'; text: string }\n | { kind: 'reasoning'; text: string }\n /** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */\n | { kind: 'tool-input-start'; id: string; name: string; toolKind: 'read' | 'action' }\n | { kind: 'tool-input-delta'; id: string; delta: string }\n | {\n kind: 'tool-input-available';\n id: string;\n name: string;\n input: unknown;\n toolKind: 'read' | 'action';\n }\n | { kind: 'tool-output'; id: string; output: unknown }\n | { kind: 'tool-output-error'; id: string; error: string };\n\nconst encoder = new TextEncoder();\n\n/** Encode one event as an NDJSON line (`{...}\\n`) for {@link SinkWriter.write}. */\nexport function encodeStreamEvent(event: AgentStreamEvent): Uint8Array {\n return encoder.encode(`${JSON.stringify(event)}\\n`);\n}\n","/**\n * The WRITE side of the pricing table the {@link import('./governance-queries.js').AgentGovernanceQueries}\n * read-model prices usage against. Cost is $0 for an unpriced model, so an app seeds its models'\n * per-1M rates once (and re-`upsert`s when a provider changes prices). A store adapter implements\n * this; consumers inject via `AGENT_PRICING_STORE`. Use `seedModelPrices` for a one-shot batch.\n */\n\n/** A per-1M-token price for one model. Cache rates fall back to the input rate when omitted. */\nexport interface ModelPriceInput {\n modelId: string;\n inputPricePer1m: number;\n outputPricePer1m: number;\n /** Per-1M price for cache-write (prompt-cache) input tokens. Omit → priced at the input rate. */\n cacheWritePricePer1m?: number;\n /** Per-1M price for cache-read (prompt-cache) input tokens. Omit → priced at the input rate. */\n cacheReadPricePer1m?: number;\n}\n\n/** A current price row as read back, with the timestamp it took effect. */\nexport interface CurrentModelPrice extends ModelPriceInput {\n effectiveFrom: string;\n}\n\nexport interface AgentPricingStore {\n /**\n * Set the current price for a model. Atomic supersede: the model's prior `isCurrent` row (if any)\n * is retired and this one is inserted as current, effective now — so the read-model always joins\n * to exactly one live price per model, with no window where two rows race for `isCurrent`.\n */\n upsertModelPrice(input: ModelPriceInput): Promise<void>;\n /** The current price row per model (`isCurrent`), for a pricing admin view. */\n listCurrentPrices(): Promise<CurrentModelPrice[]>;\n}\n\n/** Seed (or refresh) a batch of model prices — one `upsertModelPrice` per row, in order. */\nexport async function seedModelPrices(\n store: AgentPricingStore,\n prices: ModelPriceInput[],\n): Promise<void> {\n for (const price of prices) {\n await store.upsertModelPrice(price);\n }\n}\n","/**\n * A read-model over the persisted agent data (usage ⋈ pricing, tool calls, threads) for the\n * governance surfaces — the standalone `-dashboard` SPA and the `-telescope` \"Agent\" tab both\n * consume this ONE interface, so cost/usage aggregation lives in a single place.\n *\n * Separate from {@link AgentStore} on purpose: that SPI owns the write/thread path, this owns the\n * read/analytics path. A store adapter implements both. Consumers inject via\n * `AGENT_GOVERNANCE_QUERIES`.\n *\n * Live activity (in-flight runs, streaming tool calls, delegations, forbidden attempts) is NOT here\n * — that comes off the `aviary:agent:*` diagnostics channel. This interface is the durable, restart-\n * surviving history.\n */\n\n/** Inclusive UTC day range, each `YYYY-MM-DD`. */\nexport interface GovernanceRange {\n fromDay: string;\n toDay: string;\n}\n\n/** Spend + token totals for one model over a range. */\nexport interface ModelSpendRow {\n modelId: string;\n requests: number;\n inputTokens: number;\n outputTokens: number;\n costUsd: number;\n}\n\n/** Spend + token totals for one acting ref (user/tenant) over a range. */\nexport interface ActorSpendRow {\n actorRef: string;\n requests: number;\n totalTokens: number;\n costUsd: number;\n /** Distinct threads the actor used in the range. */\n threadCount: number;\n}\n\n/** Spend + token totals for one thread over a range. */\nexport interface ThreadSpendRow {\n threadId: string;\n title: string;\n actorRef: string;\n requests: number;\n totalTokens: number;\n costUsd: number;\n}\n\n/** One point on the daily usage/cost trend. */\nexport interface UsageTrendPoint {\n day: string;\n totalTokens: number;\n costUsd: number;\n}\n\n/** A recent tool-call for the activity feed. */\nexport interface ToolCallActivityRow {\n toolCallId: string;\n toolName: string;\n toolType: string;\n status: string;\n threadId: string;\n createdAt: string;\n /** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */\n runId: string | null;\n}\n\n/** A recent thread with rolled-up activity. */\nexport interface ThreadActivityRow {\n threadId: string;\n title: string;\n actorRef: string;\n messageCount: number;\n totalTokens: number;\n lastActivityAt: string;\n}\n\n/** Aggregated run reliability over a range. */\nexport interface RunMetrics {\n runs: number;\n completed: number;\n failed: number;\n /** completed / runs, 0 when runs = 0. */\n successRate: number;\n /** Total llm-step retries across the range's runs. */\n retries: number;\n durationP50Ms: number | null;\n durationP95Ms: number | null;\n}\n\n/** Run/failure/retry rollup for one agent over a range. */\nexport interface RunAgentBreakdownRow {\n /** '(default)' when the run had none. */\n agentName: string;\n runs: number;\n failed: number;\n retries: number;\n}\n\n/** Failed-run count for one error code over a range. */\nexport interface RunErrorBreakdownRow {\n errorCode: string;\n count: number;\n}\n\n/** One point on the daily run/failure trend. */\nexport interface RunTrendPoint {\n day: string;\n runs: number;\n failed: number;\n}\n\n/** A recent run for the reliability feed. */\nexport interface RecentRunRow {\n runId: string;\n threadId: string;\n actorRef: string;\n agentName: string | null;\n /** 'running' | 'completed' | 'failed'. */\n status: string;\n durationMs: number | null;\n errorCode: string | null;\n errorMessage: string | null;\n retries: number;\n /** ISO timestamp. */\n startedAt: string;\n /** sha256 hex of the run's resolved (pre-RAG) system prompt; `null` for a run recorded before this shipped. */\n promptHash: string | null;\n}\n\n/** One tool call awaiting a HITL decision, for the cross-thread approvals inbox. */\nexport interface PendingApprovalRow {\n toolCallId: string;\n toolName: string;\n input: unknown;\n threadId: string;\n threadTitle: string;\n /** Who asked — the run's actor. */\n actorRef: string;\n agentName: string | null;\n /** ISO timestamp. */\n requestedAt: string;\n /** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */\n runId: string | null;\n}\n\n/** Governance rollup for one tool over a range. */\nexport interface ToolStatRow {\n toolName: string;\n toolType: string;\n calls: number;\n failed: number;\n rejected: number;\n /**\n * p50 (median) of executionMs across calls that recorded one; null when none carry it. Reported\n * alongside p95 rather than a mean: tool latency is long-tailed (a retry or a slow upstream drags\n * an average somewhere no single call ever was), so the pair \"typical / tail\" is what an operator\n * can actually act on.\n */\n p50ExecutionMs: number | null;\n /** p95 of executionMs across executed calls; null when none carry it. */\n p95ExecutionMs: number | null;\n}\n\n/**\n * Neutral paged query for the governance list reads (`toolCallsPage`/`threadsPage`/`runsPage`). The\n * WIRE format a host exposes over HTTP mirrors `@dudousxd/nestjs-filter`'s conventions (`page`,\n * `limit`, `where[field][op]`) so consumers see one grammar across the ecosystem, but this SPI stays\n * neutral/typed — no filter-builder or ORM coupling here.\n */\nexport interface GovernancePageQuery<TWhere> {\n /** 1-based. */\n page: number;\n /** Rows per page, already clamped by the caller (the dashboard clamps to 200). */\n pageSize: number;\n /** Equality/range filters; absent field = no constraint. */\n where?: TWhere;\n}\n\n/** One page of a governance list read, with the total row count for prev/next + \"page X of Y\" UI. */\nexport interface GovernancePage<TRow> {\n rows: TRow[];\n total: number;\n page: number;\n pageSize: number;\n}\n\n/** Filters for {@link AgentGovernanceQueries.toolCallsPage}. */\nexport interface ToolCallWhere {\n toolName?: string;\n toolType?: string;\n status?: string;\n threadId?: string;\n /** Inclusive UTC day bounds, `YYYY-MM-DD`. */\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.threadsPage}. */\nexport interface ThreadWhere {\n actorRef?: string;\n /** Substring match on the title (case-insensitive). */\n title?: string;\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.runsPage}. */\nexport interface RunWhere {\n agentName?: string;\n status?: string;\n errorCode?: string;\n threadId?: string;\n fromDay?: string;\n toDay?: string;\n}\n\n/** Filters for {@link AgentGovernanceQueries.approvalsPage}. */\nexport interface ApprovalWhere {\n toolName?: string;\n threadId?: string;\n /** The requesting thread's owner. */\n actorRef?: string;\n agentName?: string;\n /** Inclusive UTC day bounds on when the approval was requested, `YYYY-MM-DD`. */\n fromDay?: string;\n toDay?: string;\n}\n\n// ─── Drill-down details ──────────────────────────────────────────────────────\n//\n// The list reads above answer \"what happened\"; these two answer \"what happened HERE\". Each is ONE\n// call returning everything the corresponding drill-down renders, so a console never fans out a\n// query per row it just drew. Both return `null` for an id that doesn't exist — the caller decides\n// whether that's a 404 or an empty panel.\n\n/** One tool call inside a {@link GovernanceRunDetail}, with the execution outcome a list row can't afford to carry. */\nexport interface RunToolCallRow {\n toolCallId: string;\n toolName: string;\n toolType: string;\n status: string;\n /** Wall time of the execution; null for a call that never executed (rejected/still pending). */\n executionMs: number | null;\n /** Who executed/decided it, when the store recorded an attribution. */\n executedByRef: string | null;\n /** The failure text for a `failed` call; null otherwise. */\n error: string | null;\n /** ISO timestamp. */\n createdAt: string;\n}\n\n/** The owning thread's headline, carried on a drill-down so it can be named without a second read. */\nexport interface DetailThreadRef {\n threadId: string;\n title: string;\n actorRef: string;\n /** True when the thread is soft-deleted — its history is still readable, the thread is not. */\n deleted: boolean;\n}\n\n/**\n * Everything a run drill-down renders: the run row itself, its owning thread's headline, and the\n * tool calls attributed to it.\n *\n * `toolCalls` is empty for a run recorded before tool calls carried a `runId` (the column is\n * nullable and pre-rollout rows have none) — indistinguishable, from here, from a run that called\n * no tools. There is deliberately no cost figure: the token ledger has no run column, so per-run\n * spend is not attributable without a store migration.\n */\nexport interface GovernanceRunDetail {\n run: RecentRunRow;\n thread: DetailThreadRef;\n /** The run's tool calls, oldest first — the order they were requested in. */\n toolCalls: RunToolCallRow[];\n}\n\n/** One message inside a {@link GovernanceThreadDetail}. `content` is capped server-side. */\nexport interface ThreadMessageRow {\n messageId: string;\n role: string;\n /** Message text, cut to {@link THREAD_DETAIL_CONTENT_CHARS}; see `truncated`. */\n content: string;\n /** True when `content` was cut — the console shows an explicit \"…\" rather than implying the tail. */\n truncated: boolean;\n agentName: string | null;\n /** How many tool calls this message requested. */\n toolCallCount: number;\n /** ISO timestamp. */\n createdAt: string;\n}\n\n/** Token/cost rollup across a thread's whole ledger (not range-scoped — a thread's lifetime). */\nexport interface ThreadUsageRollup {\n /** Ledger rows, i.e. billed turns. */\n requests: number;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n costUsd: number;\n}\n\n/** Everything a thread drill-down renders, in one call. */\nexport interface GovernanceThreadDetail {\n /** The thread's own activity row (`messageCount` is the thread total, not the page below). */\n thread: ThreadActivityRow;\n /** True when the thread is soft-deleted. */\n deleted: boolean;\n usage: ThreadUsageRollup;\n /** The thread's runs, newest first, capped at the query's `runLimit`. */\n runs: RecentRunRow[];\n /** Runs on this thread in total — `runs.length < runTotal` means the cap bit. */\n runTotal: number;\n /** The thread's messages, newest first, capped at the query's `messageLimit`. */\n messages: ThreadMessageRow[];\n}\n\n/** Row caps for {@link AgentGovernanceQueries.threadDetail}, already clamped by the caller. */\nexport interface GovernanceThreadDetailQuery {\n threadId: string;\n /** Max messages returned, newest first. */\n messageLimit: number;\n /** Max runs returned, newest first. */\n runLimit: number;\n}\n\n/**\n * Per-message content cap for {@link ThreadMessageRow.content}. A drill-down is a triage view, not a\n * transcript reader: capping here keeps one response bounded regardless of how long an assistant\n * turn ran. Shared by every adapter so the cut is identical wherever the console is served from.\n */\nexport const THREAD_DETAIL_CONTENT_CHARS = 2000;\n\n/**\n * Cut a message body to {@link THREAD_DETAIL_CONTENT_CHARS}, reporting whether it was cut. Lives\n * next to the cap so every adapter truncates at the same boundary — a console comparing two stores\n * must not see two different \"…\".\n */\nexport function truncateDetailContent(content: string): {\n content: string;\n truncated: boolean;\n} {\n if (content.length <= THREAD_DETAIL_CONTENT_CHARS) {\n return { content, truncated: false };\n }\n return { content: content.slice(0, THREAD_DETAIL_CONTENT_CHARS), truncated: true };\n}\n\n/**\n * The governance read-model. Cost is `inputTokens/1e6 * inputPricePer1m + outputTokens/1e6 *\n * outputPricePer1m` against the current pricing row per model; an unpriced model contributes 0 cost\n * (its tokens still count).\n */\nexport interface AgentGovernanceQueries {\n spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]>;\n spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]>;\n /** Top threads by spend within the range, highest cost first, capped at `limit`. */\n spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]>;\n usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;\n recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;\n recentThreads(limit: number): Promise<ThreadActivityRow[]>;\n // Run reliability. An adapter backed by a store without run recording (no `recordRunStart`)\n // returns zeros/empty from all five (plus `runsPage`, below) — the dashboard renders an empty\n // reliability surface.\n runMetrics(range: GovernanceRange): Promise<RunMetrics>;\n runsByAgent(range: GovernanceRange): Promise<RunAgentBreakdownRow[]>;\n runErrors(range: GovernanceRange): Promise<RunErrorBreakdownRow[]>;\n runTrend(range: GovernanceRange): Promise<RunTrendPoint[]>;\n recentRuns(limit: number): Promise<RecentRunRow[]>;\n /**\n * Tool calls sitting `pending_approval`, oldest first — an inbox drains from the back. Capped at\n * `limit`, with NO total: a caller that needs to know whether the cap hid anything wants\n * {@link approvalsPage} instead.\n */\n pendingApprovals(limit: number): Promise<PendingApprovalRow[]>;\n /**\n * Paged, filterable approvals inbox, oldest first (same ordering as `pendingApprovals`). Unlike\n * that method this reports `total`, so a console can page a backlog and say how much of it is\n * off-screen — the one failure this surface cannot afford is a pending approval nobody sees.\n * An adapter without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n approvalsPage(\n query: GovernancePageQuery<ApprovalWhere>,\n ): Promise<GovernancePage<PendingApprovalRow>>;\n /** Per-tool call/failure/rejection/latency rollup over the range, highest call count first. */\n toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;\n /**\n * Paged, filterable tool-call activity, newest-first (same ordering as `recentToolCalls`). An\n * adapter without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n toolCallsPage(\n query: GovernancePageQuery<ToolCallWhere>,\n ): Promise<GovernancePage<ToolCallActivityRow>>;\n /**\n * Paged, filterable thread activity, newest-first (same ordering as `recentThreads`). An adapter\n * without the backing data returns an empty page (`total: 0`) rather than throwing.\n */\n threadsPage(query: GovernancePageQuery<ThreadWhere>): Promise<GovernancePage<ThreadActivityRow>>;\n /**\n * Paged, filterable run activity, newest-first (same ordering as `recentRuns`). An adapter backed\n * by a store without run recording (no `recordRunStart`) returns an empty page (`total: 0`).\n */\n runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;\n /**\n * One run with its owning thread and its tool calls — the drill-down behind a row in the runs\n * table. `null` when no run has that id. ONE call, not one per tool call: a failed run is the\n * thing an operator opens first and it should not cost a query per step.\n *\n * An adapter backed by a store without run recording returns `null` for every id.\n */\n runDetail(runId: string): Promise<GovernanceRunDetail | null>;\n /**\n * One thread with its lifetime usage rollup, its recent runs and its recent messages — the\n * drill-down behind a row in the threads table. `null` when no thread has that id; a soft-deleted\n * thread IS returned (with `deleted: true`), because \"what did the thread we just deleted do\" is\n * exactly the question an audit asks.\n */\n threadDetail(query: GovernanceThreadDetailQuery): Promise<GovernanceThreadDetail | null>;\n}\n","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\n ThreadUsageRollup,\n UsageTrendPoint,\n} from '../spi/governance-queries.js';\n\n/**\n * The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}\n * adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the\n * cost formula, the group→sort bucketing, and the day-bounds math live here so all three surfaces\n * report identical numbers.\n */\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\nexport interface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/** The token split of one turn needed to estimate its cost. */\nexport interface CostUsage {\n inputTokens: number;\n outputTokens: number;\n cacheWriteTokens?: number | null | undefined;\n cacheReadTokens?: number | null | undefined;\n}\n\n/**\n * A normalized usage row the bucketers consume. Each adapter maps its raw DB row into this shape\n * (MikroORM reads `thread.id` + `createdAt`, Drizzle/in-memory read the flat `threadId` + `day`).\n */\nexport interface GovernanceUsageInput extends CostUsage {\n modelId: string;\n actorRef: string;\n threadId: string;\n /** The `YYYY-MM-DD` UTC day the row belongs to (its trend bucket). */\n day: string;\n /** Provider-reported spend for the row; wins over the token estimate when present. */\n costUsd?: number | null | undefined;\n}\n\n/** Thread metadata joined onto a spend bucket. */\nexport interface ThreadMeta {\n title: string;\n actorRef: string;\n}\n\n/**\n * Token-ledger estimate for one turn against a pricing row: the uncached input at the input rate,\n * cache-write/cache-read tokens at their own rates (falling back to the input rate when unpriced),\n * plus output at the output rate. An unpriced model (`price === undefined`) contributes 0 — its\n * tokens still count. Cache token counts are subsets of `inputTokens`, so the uncached remainder is\n * the difference.\n */\nexport function estimateCost(usage: CostUsage, price: ModelPrice | undefined): number {\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = usage.cacheWriteTokens ?? 0;\n const cacheReadTokens = usage.cacheReadTokens ?? 0;\n const uncachedInputTokens = usage.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (usage.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/** Provider-reported cost wins per row; otherwise the cache-aware token estimate. */\nfunction rowCost(row: GovernanceUsageInput, prices: ReadonlyMap<string, ModelPrice>): number {\n return row.costUsd ?? estimateCost(row, prices.get(row.modelId));\n}\n\n/** Aggregate usage rows into per-model spend, highest cost first then modelId ascending. */\nexport function bucketByModel(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ModelSpendRow[] {\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n}\n\n/** Aggregate usage rows into per-actor spend (with distinct thread counts), highest cost first. */\nexport function bucketByActor(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ActorSpendRow[] {\n const byActor = new Map<\n string,\n { requests: number; totalTokens: number; costUsd: number; threadIds: Set<string> }\n >();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? {\n requests: 0,\n totalTokens: 0,\n costUsd: 0,\n threadIds: new Set<string>(),\n };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n bucket.threadIds.add(row.threadId);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n threadCount: bucket.threadIds.size,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n}\n\n/**\n * Aggregate usage rows into per-thread spend, highest cost first then threadId ascending, capped at\n * `limit`. A thread absent from `threads` is dropped when `includeUnknownThreads` is false (the SQL\n * adapters fetch only non-deleted threads, so a soft-deleted thread's rows vanish from the ranking);\n * when true it is kept with blank title/actor (the in-memory adapter's semantics).\n */\nexport function bucketByThread(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n threads: ReadonlyMap<string, ThreadMeta>,\n options: { limit: number; includeUnknownThreads: boolean },\n): ThreadSpendRow[] {\n const byThread = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byThread.get(row.threadId) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byThread.set(row.threadId, bucket);\n }\n const result: ThreadSpendRow[] = [];\n for (const [threadId, bucket] of byThread) {\n const thread = threads.get(threadId);\n if (thread === undefined && !options.includeUnknownThreads) {\n continue;\n }\n result.push({\n threadId,\n title: thread?.title ?? '',\n actorRef: thread?.actorRef ?? '',\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId),\n );\n return result.slice(0, options.limit);\n}\n\n/**\n * Sum an already-scoped set of usage rows into one rollup — the thread drill-down's headline. Same\n * `rowCost` as every bucketer above (provider-reported cost wins, else the cache-aware estimate), so\n * a thread's detail cost and its row in the by-thread ranking can never disagree.\n */\nexport function rollupThreadUsage(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): ThreadUsageRollup {\n const rollup: ThreadUsageRollup = {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n costUsd: 0,\n };\n for (const row of rows) {\n rollup.requests += 1;\n rollup.inputTokens += row.inputTokens;\n rollup.outputTokens += row.outputTokens;\n rollup.totalTokens += row.inputTokens + row.outputTokens;\n rollup.costUsd += rowCost(row, prices);\n }\n return rollup;\n}\n\n/** Aggregate usage rows into a daily token/cost trend, ascending by day. */\nexport function bucketUsageTrend(\n rows: GovernanceUsageInput[],\n prices: ReadonlyMap<string, ModelPrice>,\n): UsageTrendPoint[] {\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byDay.get(row.day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(row, prices);\n byDay.set(row.day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n}\n\n/** Turn an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used to filter usage rows. */\nexport function dayBoundsUtc(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n","import type { RolesPolicy } from './spi/roles-policy.js';\nimport type { ToolHandler } from './spi/tool.js';\nimport type { Actor, ToolSpec } from './types.js';\n\n/**\n * Is this tool part of this deployment right now? `ToolSpec.enabled` and the handler's\n * `isEnabled()` are ANDed — either one saying no is enough — and both default to yes.\n *\n * Resolved per turn rather than at registration, so the answer can come from configuration that\n * did not exist when the module was built.\n */\nexport async function isToolEnabled(spec: ToolSpec, handler?: ToolHandler): Promise<boolean> {\n const declared =\n typeof spec.enabled === 'function' ? await spec.enabled() : (spec.enabled ?? true);\n if (!declared) {\n return false;\n }\n return handler?.isEnabled === undefined ? true : await handler.isEnabled();\n}\n\n/**\n * Zeroth filter layer: drop tools this deployment has turned off, before anyone asks who may call\n * them. A disabled tool is absent, not forbidden — the difference matters, because \"forbidden\"\n * tells the model (and the user reading a refusal) that the capability exists.\n */\nexport async function filterToolsByEnabled<T extends { spec: ToolSpec; handler?: ToolHandler }>(\n entries: T[],\n): Promise<T[]> {\n const checked = await Promise.all(\n entries.map(async (entry) => ({\n entry,\n enabled: await isToolEnabled(entry.spec, entry.handler),\n })),\n );\n return checked.filter((row) => row.enabled).map((row) => row.entry);\n}\n\n/**\n * May this actor use this tool, per the tool's OWN gate? Tools without a `canUse` say yes and are\n * governed by the `RolesPolicy` alone.\n */\nexport async function canActorUseTool(actor: Actor, handler?: ToolHandler): Promise<boolean> {\n return handler?.canUse === undefined ? true : await handler.canUse(actor);\n}\n\n/**\n * Third filter layer: drop tools whose own `canUse` refuses this actor. Runs after the app-wide\n * `RolesPolicy`, and is additive to it — a tool can narrow who reaches it, never widen.\n */\nexport async function filterToolsByCanUse<T extends { spec: ToolSpec; handler?: ToolHandler }>(\n entries: T[],\n actor: Actor,\n): Promise<T[]> {\n const checked = await Promise.all(\n entries.map(async (entry) => ({\n entry,\n allowed: await canActorUseTool(actor, entry.handler),\n })),\n );\n return checked.filter((row) => row.allowed).map((row) => row.entry);\n}\n\n/** First filter layer: drop tools the actor's role may not invoke. `can` may be async (authz). */\nexport async function filterToolsByRole(\n tools: ToolSpec[],\n actor: Actor,\n policy: RolesPolicy,\n): Promise<ToolSpec[]> {\n const checked = await Promise.all(\n tools.map(async (tool) => ({ tool, allowed: await policy.can(actor, tool) })),\n );\n return checked.filter((entry) => entry.allowed).map((entry) => entry.tool);\n}\n\n/** Second filter layer: if the agent pins an allow-list, keep only those tool names. */\nexport function filterToolsByAllowList(\n tools: ToolSpec[],\n allowedTools: string[] | undefined,\n): ToolSpec[] {\n if (allowedTools === undefined) {\n return tools;\n }\n const allowed = new Set(allowedTools);\n return tools.filter((tool) => allowed.has(tool.name));\n}\n","import type { AgentDefinition } from './types.js';\n\n/** Holds the named agent definitions registered via `AgentModule.forFeature([...])`. */\nexport class AgentRegistry {\n private readonly definitions = new Map<string, AgentDefinition>();\n\n register(definition: AgentDefinition): void {\n this.definitions.set(definition.name, definition);\n }\n\n get(name: string): AgentDefinition | undefined {\n return this.definitions.get(name);\n }\n\n has(name: string): boolean {\n return this.definitions.has(name);\n }\n\n list(): AgentDefinition[] {\n return [...this.definitions.values()];\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { RolesPolicy } from './spi/roles-policy.js';\nimport type { AiToolCtx, ToolHandler } from './spi/tool.js';\nimport {\n canActorUseTool,\n filterToolsByAllowList,\n filterToolsByCanUse,\n filterToolsByEnabled,\n filterToolsByRole,\n isToolEnabled,\n} from './tool-filters.js';\nimport type { Actor, ToolDefinition, ToolSpec } from './types.js';\n\n/** Thrown when an actor invokes a tool their role is not allowed. */\nexport class ToolForbiddenError extends Error {\n constructor(public readonly toolName: string) {\n super(`Tool \"${toolName}\" is not allowed for this role`);\n this.name = 'ToolForbiddenError';\n }\n}\n\n/**\n * Thrown when a registered tool is invoked while this deployment has it turned off (`enabled` /\n * `isEnabled()`). Distinct from {@link ToolForbiddenError}, which is about the actor, and from\n * {@link ToolNotFoundError}, which is about a name nobody registered — an operator reading a log\n * needs to tell \"you flipped the flag\" apart from \"that tool does not exist in this build\".\n *\n * Reachable in normal operation, not just from a forged call: a HITL `action` approved before the\n * flag was turned off runs its tool afterwards.\n */\nexport class ToolDisabledError extends Error {\n constructor(public readonly toolName: string) {\n super(`Tool \"${toolName}\" is disabled in this deployment`);\n this.name = 'ToolDisabledError';\n }\n}\n\n/** Thrown when a tool is invoked that was never registered. */\nexport class ToolNotFoundError extends Error {\n constructor(public readonly toolName: string) {\n super(`Tool \"${toolName}\" is not registered`);\n this.name = 'ToolNotFoundError';\n }\n}\n\n/** Thrown when a tool's input fails its Standard Schema validation. */\nexport class ToolInputInvalidError extends Error {\n constructor(\n public readonly toolName: string,\n public readonly issues: readonly StandardSchemaV1.Issue[],\n ) {\n super(\n `Invalid input for tool \"${toolName}\": ${issues.map((issue) => issue.message).join('; ')}`,\n );\n this.name = 'ToolInputInvalidError';\n }\n}\n\ninterface Entry {\n spec: ToolSpec;\n handler: ToolHandler;\n}\n\n/**\n * Holds every registered tool and gates invocation.\n *\n * Note: `definitionsFor` returns NEUTRAL definitions (no `execute`). The agent loop runs\n * each tool itself as a (durable) step — so even read tools are not auto-executed by the\n * model. `action` tools additionally require HITL approval before the loop runs them.\n */\nexport class ToolRegistry {\n private readonly entries = new Map<string, Entry>();\n\n register(spec: ToolSpec, handler: ToolHandler): void {\n this.entries.set(spec.name, { spec, handler });\n }\n\n has(name: string): boolean {\n return this.entries.has(name);\n }\n\n spec(name: string): ToolSpec | undefined {\n return this.entries.get(name)?.spec;\n }\n\n allSpecs(): ToolSpec[] {\n return [...this.entries.values()].map((entry) => entry.spec);\n }\n\n /**\n * The tools to offer the model for this actor+agent, after the four filter layers: what this\n * deployment has enabled, what this actor's role allows, what each tool's own `canUse` allows\n * this actor, and finally what this agent pinned.\n *\n * Every layer only ever removes tools, so no arrangement of them can widen what a turn reaches.\n */\n async definitionsFor(\n actor: Actor,\n policy: RolesPolicy,\n allowedTools?: string[],\n ): Promise<ToolDefinition[]> {\n const live = await filterToolsByEnabled([...this.entries.values()]);\n const allowedByRole = new Set(\n (\n await filterToolsByRole(\n live.map((entry) => entry.spec),\n actor,\n policy,\n )\n ).map((spec) => spec.name),\n );\n const roleScoped = live.filter((entry) => allowedByRole.has(entry.spec.name));\n const actorScoped = await filterToolsByCanUse(roleScoped, actor);\n const allowScoped = filterToolsByAllowList(\n actorScoped.map((entry) => entry.spec),\n allowedTools,\n );\n return allowScoped.map((spec) => ({\n name: spec.name,\n kind: spec.kind,\n description: spec.description,\n inputSchema: spec.inputSchema,\n }));\n }\n\n /**\n * Run a tool. Re-checks that the tool is enabled and that the role allows it (defense-in-depth —\n * a call can reach here from a replayed durable step or an approval granted before the flag\n * moved, neither of which went through `definitionsFor` again) and re-parses the input via Zod.\n */\n async invoke(\n name: string,\n input: unknown,\n ctx: AiToolCtx,\n policy: RolesPolicy,\n ): Promise<unknown> {\n const entry = this.entries.get(name);\n if (entry === undefined) {\n throw new ToolNotFoundError(name);\n }\n if (!(await isToolEnabled(entry.spec, entry.handler))) {\n throw new ToolDisabledError(name);\n }\n if (!(await policy.can(ctx.actor, entry.spec))) {\n throw new ToolForbiddenError(name);\n }\n if (!(await canActorUseTool(ctx.actor, entry.handler))) {\n throw new ToolForbiddenError(name);\n }\n const validation = await entry.spec.inputSchema['~standard'].validate(input);\n if (validation.issues !== undefined) {\n throw new ToolInputInvalidError(name, validation.issues);\n }\n return entry.handler.execute(validation.value, ctx);\n }\n}\n\n/** Default gate: one of the actor's roles must be in spec.roles (defaulting to ADMIN-only). */\nexport class DefaultRolesPolicy implements RolesPolicy {\n constructor(private readonly defaultRoles: string[] = ['ADMIN']) {}\n\n can(actor: Actor, tool: ToolSpec): boolean {\n const allowed = tool.roles ?? this.defaultRoles;\n return (actor.roles ?? []).some((role) => allowed.includes(role));\n }\n}\n","import { createHash } from 'node:crypto';\nimport { trace } from '@dudousxd/nestjs-diagnostics';\nimport type { PayloadOf } from '@dudousxd/nestjs-diagnostics';\nimport {\n type AgentSpanEvent,\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n publishAgentToolRetry,\n} from './diagnostics.js';\nimport { estimateCost } from './governance/compute.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider, ModelTurnResult } from './spi/model-provider.js';\nimport type { AgentPricingStore, CurrentModelPrice } from './spi/pricing-store.js';\nimport type { QuotaStore } from './spi/quota-store.js';\nimport type { Passage, Retriever } from './spi/retriever.js';\nimport type { RolesPolicy } from './spi/roles-policy.js';\nimport type { SinkWriter } from './spi/token-stream-sink.js';\nimport type { AiToolCtx } from './spi/tool.js';\nimport { encodeStreamEvent } from './stream-events.js';\nimport type { ToolRegistry } from './tool-registry.js';\nimport { invokeWithTransientRetry, resolveToolTransientRetryNumbers } from './tool-retry.js';\nimport type { ToolTransientRetrySetting } from './tool-retry.js';\nimport type {\n AgentRunInput,\n Decision,\n LlmStepEnvelope,\n MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\n ToolStepCtx,\n ToolStepEnvelope,\n} from './types.js';\n\nexport interface AgentLoopDeps {\n model: ModelProvider;\n store: AgentStore;\n registry: ToolRegistry;\n rolesPolicy: RolesPolicy;\n quota?: QuotaStore;\n /**\n * Fallback accounting label when the provider's turn result doesn't report a `modelId`.\n * Optional — a provider that reports its own model makes this unnecessary.\n */\n modelId?: string;\n /** Pre-computed (YYYY-MM-DD) so the loop body stays deterministic under durable replay. */\n day: string;\n /** The agent's base prompt. A flat string, or a {@link PromptBuilder} resolved per turn. */\n systemPrompt: string | PromptBuilder;\n /**\n * Cross-agent system-prompt contributors, applied in order AFTER the agent's base prompt. Each\n * returns a section to append (or `null` to skip this turn). The app registers them via\n * `@SystemPromptContributor()`; the loop composes base + contributors into the effective prompt.\n */\n promptContributors?: PromptContributor[];\n maxSteps?: number;\n /** Optional host handle threaded to tool ctx (e.g. an ORM EntityManager). */\n host?: unknown;\n /** Agent-level tool allow-list. Undefined → all tools (after role filtering). */\n toolAllowList?: string[];\n /**\n * Per-tool execution timeout in ms. A tool that runs longer is aborted and recorded as failed\n * (the model gets the timeout as its result and can adapt) rather than hanging the turn.\n * Undefined → no timeout.\n */\n toolTimeoutMs?: number;\n /**\n * Retries a tool's own invocation, in place, when it throws a classified-transient error (a DB\n * deadlock, a lock-wait timeout, a serialization failure — see `isTransientToolError`) — never a\n * new durable step/checkpoint, just repeated attempts inside the same `tool:<call.id>` step body.\n * Default ON (`{ attempts: 2, backoffMs: 150 }` with the default classifier) when undefined; set\n * `{ classify }` to widen/narrow which errors count as transient, or `false` to disable entirely.\n * A tool's other (non-transient) failures are unaffected — they remain a one-shot business\n * outcome, exactly as before.\n */\n toolTransientRetry?: ToolTransientRetrySetting;\n /**\n * When set, after the final turn the loop makes one extra model call to propose up to this many\n * short follow-up questions, stored on the assistant message's `followUps`. Costs an extra call\n * (recorded as `follow_ups` usage). Undefined/0 → disabled.\n */\n followUpsCount?: number;\n /**\n * Enables always-on (\"inject\") RAG: before the turn, retrieve passages for the user message and\n * augment the system prompt with them. Its presence IS inject mode — agentic (tool) retrieval sets\n * no retriever here (it rides a normal `read` tool). Undefined → no injection.\n */\n retriever?: Retriever;\n /** How many passages inject-mode retrieval requests. Undefined → 5. */\n retrievalTopK?: number;\n /**\n * Prices each step's token usage into `costUsd` (on the `step-finish` stream frame and the\n * persisted assistant message's `usage`). The current price list is fetched ONCE per run (not per\n * message/step) and reused for every step's estimate. Undefined → `costUsd` is always `null`.\n */\n pricingStore?: AgentPricingStore;\n}\n\n/**\n * A step's cost: the provider's own reported figure when it has one (a gateway), else an estimate\n * from `price` when the model has one, else `null` — never a fabricated `0` for \"we don't know\".\n */\nfunction resolveCostUsd(\n usage: MessageUsage,\n reportedCostUsd: number | undefined,\n price: CurrentModelPrice | undefined,\n): number | null {\n if (reportedCostUsd !== undefined) {\n return reportedCostUsd;\n }\n return price === undefined ? null : estimateCost(usage, price);\n}\n\n/** Renders retrieved passages as a numbered, citable context block for the system prompt. */\nfunction buildContextBlock(passages: Passage[]): string {\n const items = passages\n .map((passage, index) => {\n const label = passage.source !== undefined ? ` (${passage.source})` : '';\n return `[${index + 1}]${label} ${passage.text}`;\n })\n .join('\\n\\n');\n return `<retrieved_context>\\n${items}\\n</retrieved_context>\\nUse the retrieved context above to answer when relevant, and cite sources by their bracket number.`;\n}\n\nexport interface AgentLoopHooks {\n runId: string;\n /** A writer for this run's live token stream (data plane). */\n openSink(): SinkWriter | Promise<SinkWriter>;\n /** HITL gate for an action tool. Inline resolves a pending promise; durable awaits a signal. */\n awaitApproval(call: ToolCallRequest, ctx: AiToolCtx): Promise<Decision>;\n /**\n * Run another named agent and return its answer. Provided only when the host wired multi-agent\n * support (durable → child workflow, inline → nested loop). Exposed to tools as `ctx.runAgent`.\n */\n runAgent?(agentName: string, task: string): Promise<{ text: string }>;\n /**\n * Checkpoint wrapper. Inline = call fn directly; durable = ctx.localStep(name, fn) — the\n * in-process checkpointed primitive (`name` is a checkpoint identity, not a worker group).\n * EVERY side-effect and control-flow read goes through this so durable replay returns\n * cached results (stable ids, no double-write, no re-streaming).\n */\n step<T>(name: string, fn: () => Promise<T>): Promise<T>;\n /**\n * Dispatch the model turn as a routed remote step. When present the loop uses it INSTEAD of\n * running the model inline under hooks.step. Must resolve to exactly what deps.model.runTurn\n * resolves. The durable runner enriches the envelope with sink routing (sinkRunId/childSink)\n * on its side — core stays sink-topology-agnostic.\n */\n dispatchLlm?(index: number, envelope: LlmStepEnvelope): Promise<ModelTurnResult>;\n /**\n * Dispatch one tool execution as a routed remote step. Replaces ONLY the registry.invoke call\n * (+ its timeout, applied handler-side); all persist steps around it stay local.\n */\n dispatchTool?(call: ToolCallRequest, envelope: ToolStepEnvelope): Promise<unknown>;\n /**\n * Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so the loop\n * rethrows them untouched instead of recording a failure. Inline runners omit it — they have no\n * control-flow exceptions.\n */\n isControlFlowError?(error: unknown): boolean;\n}\n\nexport class QuotaExceededError extends Error {\n constructor() {\n super('Daily token quota exceeded');\n this.name = 'QuotaExceededError';\n }\n}\n\n/**\n * How deep agent→agent delegation may nest before the loop refuses further hops. A cap, not a\n * tuning knob: it stops a mis-wired `delegatesTo` cycle (A→B→A) from spawning runs unbounded.\n */\nexport const MAX_DELEGATION_DEPTH = 5;\n\n/** Resolve a prompt that may be a flat string or a {@link PromptBuilder}. */\nasync function resolvePrompt(prompt: string | PromptBuilder, ctx: PromptContext): Promise<string> {\n return typeof prompt === 'function' ? prompt(ctx) : prompt;\n}\n\n/**\n * The effective system prompt for a turn: the agent's own base prompt, then each cross-agent\n * contributor's section appended in order (skipping any that return `null`/empty this turn). This is\n * resolved from stable inputs (actor / agent / pageContext) once per turn; contributors should be\n * derived from those rather than from uncached I/O so it stays replay-safe.\n */\nasync function resolveSystemPrompt(deps: AgentLoopDeps, input: AgentRunInput): Promise<string> {\n const ctx: PromptContext = {\n actor: input.actor,\n agentName: input.agentName ?? 'default',\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n };\n const sections = [await resolvePrompt(deps.systemPrompt, ctx)];\n for (const contribute of deps.promptContributors ?? []) {\n const section = await contribute(ctx);\n if (section !== null && section.length > 0) {\n sections.push(section);\n }\n }\n return sections.join('\\n\\n');\n}\n\n/** An `agent`-kind tool's input is `{ task }` by convention; fall back to a JSON dump. */\nfunction extractTask(input: unknown): string {\n if (typeof input === 'object' && input !== null && 'task' in input) {\n const task = (input as { task: unknown }).task;\n if (typeof task === 'string') {\n return task;\n }\n }\n return JSON.stringify(input);\n}\n\nfunction deriveTitle(userText: string): string {\n const trimmed = userText.trim().replace(/\\s+/g, ' ');\n return trimmed.length > 60 ? `${trimmed.slice(0, 57)}...` : trimmed || 'New chat';\n}\n\n/** Thrown when a tool exceeds `toolTimeoutMs`; caught by the loop and recorded as a failed call. */\nclass ToolTimeoutError extends Error {\n constructor(toolName: string, ms: number) {\n super(`Tool \"${toolName}\" exceeded its ${ms}ms timeout`);\n this.name = 'ToolTimeoutError';\n }\n}\n\n/** Reject if `work` doesn't settle within `ms`. The underlying work is left to finish on its own. */\nexport function withToolTimeout<T>(work: Promise<T>, ms: number, toolName: string): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);\n work.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\n/** Best-effort parse of the follow-ups model reply: a bare JSON array, tolerating code fences/prose. */\nfunction parseFollowUps(text: string, count: number): string[] {\n const source = text.match(/\\[[\\s\\S]*\\]/)?.[0] ?? text;\n try {\n const parsed: unknown = JSON.parse(source);\n if (Array.isArray(parsed)) {\n return parsed.filter((item): item is string => typeof item === 'string').slice(0, count);\n }\n } catch {\n /* not JSON — no follow-ups this turn */\n }\n return [];\n}\n\n/**\n * One extra, non-streamed model call that proposes short follow-up questions. Writes to a discarding\n * sink so its tokens never reach the user's live stream; the reply is parsed as a JSON string array.\n */\nasync function generateFollowUps(\n model: ModelProvider,\n messages: ModelMessage[],\n count: number,\n): Promise<{ followUps: string[]; usage: MessageUsage; modelId?: string }> {\n const discard: SinkWriter = { write: () => {}, end: () => {}, fail: () => {} };\n const turn = await model.runTurn({\n system: `Based on the conversation so far, propose up to ${count} short, distinct follow-up questions the user is likely to ask next. Respond with ONLY a JSON array of strings — no prose, no code fences.`,\n messages,\n tools: [],\n sink: discard,\n });\n return {\n followUps: parseFollowUps(turn.text, count),\n usage: turn.usage,\n ...(turn.modelId !== undefined ? { modelId: turn.modelId } : {}),\n };\n}\n\n/**\n * Wrap a genuinely-executing operation in an `aviary:agent:<event>` span (the diagnostics\n * `trace()` API — five `:start`/`:end`/`:asyncStart`/`:asyncEnd`/`:error` sub-channels),\n * correlated to its run by `traceId = runId`, WITHOUT letting the operation's raw return value\n * ride the span envelope: `trace` publishes the traced fn's return as the span's `result`, so the\n * traced fn returns only `summarize`d metadata (token counts / lengths / names — never prompt or\n * output text, the point events' redaction posture) while the real value is handed back to the\n * caller through the closure. Zero-cost when no span sub-channel has a subscriber.\n *\n * REPLAY SAFETY: call sites MUST sit INSIDE a `hooks.step` body (or another genuinely-executed\n * path). Durable replay skips step bodies and returns checkpoints, which is exactly what keeps a\n * replayed run from re-emitting spans. Never wrap a `hooks.step(...)`/`hooks.dispatch*(...)`\n * CALL — those run (and resolve from cache) on every replay.\n */\nasync function spanned<TEvent extends AgentSpanEvent, T>(\n event: TEvent,\n runId: string,\n payload: PayloadOf<'agent', TEvent>,\n run: () => Promise<T>,\n summarize: (value: T) => Record<string, unknown>,\n): Promise<T> {\n let value!: T;\n await trace(\n 'agent',\n event,\n async () => {\n value = await run();\n return summarize(value);\n },\n payload,\n { traceId: runId },\n );\n return value;\n}\n\n/**\n * Span-wrap one model call (`aviary:agent:llm.turn`). Exported so the durable dispatched-step\n * handler (which executes the genuine remote llm step) can emit the same span — core cannot wrap\n * `hooks.dispatchLlm` itself, because that call also runs (from cache) on replay.\n */\nexport function traceLlmTurn(\n runId: string,\n step: number,\n run: () => Promise<ModelTurnResult>,\n): Promise<ModelTurnResult> {\n return spanned('llm.turn', runId, { runId, step }, run, (turn) => ({\n ...(turn.modelId !== undefined ? { modelId: turn.modelId } : {}),\n inputTokens: turn.usage.inputTokens,\n outputTokens: turn.usage.outputTokens,\n textLength: turn.text.length,\n toolCalls: turn.toolCalls.length,\n }));\n}\n\n/**\n * Span-wrap one tool invocation (`aviary:agent:tool.execution`). The tool's raw output never\n * rides the span (only the start payload's name/type metadata + duration). Exported for the\n * durable dispatched-step handler, like {@link traceLlmTurn}.\n */\nexport function traceToolExecution<T>(\n runId: string,\n call: { toolCallId: string; toolName: string; toolType: 'read' | 'action' },\n run: () => Promise<T>,\n): Promise<T> {\n return spanned('tool.execution', runId, { runId, ...call }, run, () => ({}));\n}\n\n/**\n * The provider-agnostic agent turn, reused by both the inline and durable runners.\n * It drives the model→tools→model iteration; the runner supplies the `step`/`awaitApproval`\n * hooks that make the same loop body either in-process or a replay-safe durable workflow.\n */\nexport async function runAgentLoop(\n deps: AgentLoopDeps,\n input: AgentRunInput,\n hooks: AgentLoopHooks,\n): Promise<{ text: string }> {\n const maxSteps = deps.maxSteps ?? 8;\n let system = await resolveSystemPrompt(deps, input);\n\n if (deps.quota !== undefined) {\n const quota = deps.quota;\n const state = await hooks.step('quota:check', () => quota.check(input.actor.id, deps.day));\n if (!state.withinLimit) {\n publishAgentQuotaExceeded({\n actorId: input.actor.id,\n usedTokens: state.usedTokens,\n limitTokens: state.limitTokens,\n });\n throw new QuotaExceededError();\n }\n }\n\n if (input.regenerate === true) {\n // Re-run the last exchange: drop every message after the thread's last user message (keeping\n // it), then answer it again. No new user message is appended.\n await hooks.step('regenerate:truncate', async () => {\n const existing = await deps.store.getThread(input.threadId);\n const messages = existing?.messages ?? [];\n let lastUserIndex = -1;\n for (let index = messages.length - 1; index >= 0; index -= 1) {\n if (messages[index]?.role === 'user') {\n lastUserIndex = index;\n break;\n }\n }\n const firstDropped = messages[lastUserIndex + 1];\n if (firstDropped !== undefined) {\n await deps.store.truncateFrom(input.threadId, firstDropped.id);\n }\n });\n } else {\n await hooks.step('persist:user', () =>\n deps.store.appendMessage({\n threadId: input.threadId,\n role: 'user',\n content: input.userText,\n ...(input.attachments !== undefined ? { attachments: input.attachments } : {}),\n }),\n );\n }\n\n const thread = await hooks.step('load:thread', () => deps.store.getThread(input.threadId));\n const modelMessages: ModelMessage[] = (thread?.messages ?? []).map((message) => ({\n role: message.role,\n content: message.content,\n ...(message.toolCalls !== undefined ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults !== undefined ? { toolResults: message.toolResults } : {}),\n ...(message.attachments !== undefined ? { attachments: message.attachments } : {}),\n }));\n\n const writer = await hooks.openSink();\n let lastText = '';\n let steps = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n publishAgentRunStarted({\n runId: hooks.runId,\n threadId: input.threadId,\n actorId: input.actor.id,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n });\n\n // Its own step so durable replay reuses the ORIGINAL wall-clock start — durationMs stays honest\n // across suspend/resume.\n const startedAt = await hooks.step('run:started-at', () => Promise.resolve(Date.now()));\n // Optional-chained: a store without run recording makes this (and persist:run:end) a no-op.\n await hooks.step('persist:run:start', async () => {\n // Hashed BEFORE the retrieved-context block is folded in below, so the hash identifies the\n // prompt VERSION (agent base + contributors), not a given turn's retrieval.\n const promptHash = createHash('sha256').update(system).digest('hex');\n await deps.store.recordRunStart?.({\n runId: hooks.runId,\n threadId: input.threadId,\n actorRef: input.actor.id,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n promptHash,\n });\n });\n\n // Inject-mode RAG: retrieve once for the user message and fold the passages into the system prompt\n // (a `ctx.step` so it's replay-cached under durable). Recorded below as a synthetic tool call on\n // the first assistant message, so citations surface through the same machinery as agentic search.\n let injectedPassages: Passage[] | undefined;\n if (deps.retriever !== undefined) {\n const retriever = deps.retriever;\n const topK = deps.retrievalTopK ?? 5;\n const passages = await hooks.step('retrieve', () =>\n spanned(\n 'retrieval',\n hooks.runId,\n { runId: hooks.runId, queryLength: input.userText.length, topK },\n () => retriever.retrieve(input.userText, { topK }),\n (retrieved) => ({ count: retrieved.length }),\n ),\n );\n if (passages.length > 0) {\n injectedPassages = passages;\n system = `${system}\\n\\n${buildContextBlock(passages)}`;\n }\n publishAgentRetrieved({ runId: hooks.runId, query: input.userText, count: passages.length });\n }\n\n // Fetched ONCE per run (not per step/message) and reused for every step's cost estimate below.\n // Returned as a plain array (not the Map built from it) so durable replay can JSON-cache the step.\n let prices: CurrentModelPrice[] = [];\n if (deps.pricingStore !== undefined) {\n const pricingStore = deps.pricingStore;\n prices = await hooks.step('pricing:list', () => pricingStore.listCurrentPrices());\n }\n const priceByModel = new Map(prices.map((price) => [price.modelId, price]));\n\n // NOTE: no try/finally around this loop. A durable runner suspends by THROWING through the stack\n // at `awaitApproval` (ctx.waitForSignal); a finally would then call writer.end() on every suspend\n // and prematurely close the live stream. We only end on normal completion — the throw propagates\n // to the engine, and the resumed replay reaches the writer.end() below.\n for (let i = 0; i < maxSteps; i += 1) {\n // Open a UI step spanning this model call AND its tool execution — matching the AI SDK's own\n // step semantics, so tool-output lands inside the step that made the call. Wrapped in a durable\n // step so replay doesn't re-emit it (a no-op for the inline runner).\n await hooks.step(`stream:step-start:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-start' }));\n });\n\n let turn: ModelTurnResult;\n if (hooks.dispatchLlm) {\n // No definitionsFor here: the envelope carries only wire-safe data (a ToolDefinition holds a\n // live schema instance) — the serving handler re-derives tool definitions from the actor.\n turn = await hooks.dispatchLlm(i, {\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n system,\n messages: modelMessages,\n actor: input.actor,\n });\n } else {\n const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n turn = await hooks.step(`llm:${i}`, () =>\n traceLlmTurn(hooks.runId, i, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n ),\n );\n }\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n const resolvedModelId = turn.modelId ?? deps.modelId ?? 'unknown';\n // Provider-reported spend wins; else an estimate from the (once-per-run cached) price list; else\n // `null` — surfaced on the stream's step-finish frame and the persisted assistant message below.\n const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));\n // Stamp each call's declared kind from the registry so thread-read consumers (and the stream\n // frames the model adapter writes) know a call's kind without hardcoding a tool-name allowlist.\n const toolCallsWithKind: ToolCallRequest[] = turn.toolCalls.map((call) => ({\n ...call,\n kind: deps.registry.spec(call.name)?.kind ?? 'read',\n }));\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n modelId: resolvedModelId,\n purpose: 'chat',\n usage: turn.usage,\n // persist the provider's actual cost when reported; the read-model prefers it over pricing\n ...(turn.costUsd !== undefined ? { costUsd: turn.costUsd } : {}),\n }),\n );\n if (deps.quota !== undefined) {\n const quota = deps.quota;\n await hooks.step(`quota:bump:${i}`, () =>\n quota.bump(input.actor.id, deps.day, turn.usage.inputTokens + turn.usage.outputTokens),\n );\n }\n\n steps += 1;\n totalInput += turn.usage.inputTokens;\n totalOutput += turn.usage.outputTokens;\n lastText = turn.text;\n publishAgentMessage({\n runId: hooks.runId,\n threadId: input.threadId,\n role: 'assistant',\n textLength: turn.text.length,\n });\n\n // A turn with no tool calls is the last one. Generate follow-up suggestions here (before the\n // append) so they land on the final assistant message, and stop after.\n const isFinalTurn = turn.toolCalls.length === 0;\n let followUps: string[] | undefined;\n if (isFinalTurn && deps.followUpsCount !== undefined && deps.followUpsCount > 0) {\n const count = deps.followUpsCount;\n // Stays on hooks.step (not dispatchLlm) — a short, non-streamed call, deliberately not\n // dispatched as a routed remote step.\n const generated = await hooks.step(`followups:${i}`, () =>\n spanned(\n 'follow-ups',\n hooks.runId,\n { runId: hooks.runId, step: i, count },\n () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\n ),\n (result) => ({\n followUps: result.followUps.length,\n inputTokens: result.usage.inputTokens,\n outputTokens: result.usage.outputTokens,\n ...(result.modelId !== undefined ? { modelId: result.modelId } : {}),\n }),\n ),\n );\n if (generated.followUps.length > 0) {\n followUps = generated.followUps;\n }\n await hooks.step(`persist:usage:followups:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n modelId: generated.modelId ?? deps.modelId ?? 'unknown',\n purpose: 'follow_ups',\n usage: generated.usage,\n }),\n );\n }\n\n const assistant = await hooks.step(`persist:assistant:${i}`, () =>\n deps.store.appendMessage({\n threadId: input.threadId,\n role: 'assistant',\n content: turn.text,\n usage: { ...turn.usage, costUsd },\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(toolCallsWithKind.length > 0 ? { toolCalls: toolCallsWithKind } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n }),\n );\n // Tool results ride on the same assistant message that made the calls — the compact shape the\n // store persists and `mapMessages` (in every model adapter) expands into an assistant + tool\n // message pair. We keep the reference and attach `toolResults` below once the tools have run.\n const assistantMessage: ModelMessage = {\n role: 'assistant',\n content: turn.text,\n ...(toolCallsWithKind.length > 0 ? { toolCalls: toolCallsWithKind } : {}),\n };\n modelMessages.push(assistantMessage);\n\n // Record inject-mode retrieval as a synthetic auto-executed `retrieve` tool call on the assistant\n // message it informed — so its passages persist and render as citations exactly like an agentic\n // search would, without a new message field.\n if (i === 0 && injectedPassages !== undefined) {\n const passages = injectedPassages;\n const toolCallId = `retrieve-${assistant.id}`;\n await hooks.step(`persist:retrieval:${assistant.id}`, async () => {\n await deps.store.recordToolCall({\n toolCallId,\n messageId: assistant.id,\n toolName: 'retrieve',\n toolType: 'read',\n input: { query: input.userText },\n status: 'auto_executed',\n runId: hooks.runId,\n });\n await deps.store.updateToolCall({ toolCallId, status: 'executed', output: { passages } });\n });\n }\n\n if (isFinalTurn) {\n await hooks.step(`stream:step-finish:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-finish', usage: turn.usage, costUsd }));\n });\n break;\n }\n\n const results: ToolResult[] = [];\n for (const call of toolCallsWithKind) {\n const spec = deps.registry.spec(call.name);\n const toolType = call.kind ?? 'read';\n const ctx: AiToolCtx = {\n actor: input.actor,\n threadId: input.threadId,\n runId: hooks.runId,\n requestId: hooks.runId,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n ...(deps.host !== undefined ? { host: deps.host } : {}),\n };\n\n // Delegation: an `agent`-kind tool runs another agent. Handled at the LOOP level (not in a\n // step) because the durable runner maps it to `ctx.child`, a ctx-level suspend point.\n if (toolType === 'agent') {\n const targetAgent = spec?.targetAgent ?? call.name;\n const task = extractTask(call.input);\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'read',\n input: call.input,\n status: 'auto_executed',\n runId: hooks.runId,\n }),\n );\n // Cap nesting so a mis-wired delegation cycle can't spawn runs without bound.\n const overDepth = (input.delegationDepth ?? 0) >= MAX_DELEGATION_DEPTH;\n publishAgentDelegated({\n runId: hooks.runId,\n toAgent: targetAgent,\n ...(input.agentName !== undefined ? { fromAgent: input.agentName } : {}),\n });\n let sub: { text: string };\n if (overDepth) {\n sub = { text: `(delegation depth limit of ${MAX_DELEGATION_DEPTH} reached)` };\n } else if (hooks.runAgent) {\n sub = await hooks.runAgent(targetAgent, task);\n } else {\n sub = { text: `(no multi-agent support wired; cannot reach \"${targetAgent}\")` };\n }\n await hooks.step(`persist:toolexec:${call.id}`, () =>\n deps.store.updateToolCall({ toolCallId: call.id, status: 'executed', output: sub }),\n );\n results.push({ id: call.id, name: call.name, output: sub });\n continue;\n }\n\n // WHO settled an action tool: the Decision's ref (a console admin) when it carries one, else\n // the run's own actor (the chat flow). Stamped on both the executed and rejected persists.\n let deciderRef = input.actor.id;\n if (toolType === 'action') {\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'action',\n input: call.input,\n status: 'pending_approval',\n runId: hooks.runId,\n }),\n );\n const decision = await hooks.awaitApproval(call, ctx);\n deciderRef = decision.executedByRef ?? input.actor.id;\n if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\n executedByRef: deciderRef,\n ...(decision.reason !== undefined ? { error: decision.reason } : {}),\n }),\n );\n results.push({\n id: call.id,\n name: call.name,\n output: { rejected: true, reason: decision.reason ?? 'rejected by user' },\n error: 'rejected',\n });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'rejected',\n });\n continue;\n }\n } else {\n await hooks.step(`persist:toolcall:${call.id}`, () =>\n deps.store.recordToolCall({\n toolCallId: call.id,\n messageId: assistant.id,\n toolName: call.name,\n toolType: 'read',\n input: call.input,\n status: 'auto_executed',\n runId: hooks.runId,\n }),\n );\n }\n\n const startedAt = Date.now();\n try {\n let output: unknown;\n if (hooks.dispatchTool) {\n const stepCtx: ToolStepCtx = {\n actor: input.actor,\n threadId: input.threadId,\n runId: hooks.runId,\n requestId: hooks.runId,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(input.pageContext !== undefined ? { pageContext: input.pageContext } : {}),\n };\n const envelope: ToolStepEnvelope = {\n toolName: call.name,\n input: call.input,\n ctx: stepCtx,\n ...(deps.toolTimeoutMs !== undefined ? { timeoutMs: deps.toolTimeoutMs } : {}),\n // Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see\n // ToolStepEnvelope.transientRetry.\n transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry),\n };\n // The handler applies withToolTimeout (and the retry loop) itself — no loop-side wrap for\n // a dispatched call.\n output = await hooks.dispatchTool(call, envelope);\n } else {\n const invocation = hooks.step(`tool:${call.id}`, () =>\n traceToolExecution(\n hooks.runId,\n { toolCallId: call.id, toolName: call.name, toolType },\n () =>\n invokeWithTransientRetry(\n () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n deps.toolTransientRetry ?? {},\n {\n ...(hooks.isControlFlowError !== undefined\n ? { isControlFlowError: hooks.isControlFlowError }\n : {}),\n onRetry: (attempt, retryError) => {\n publishAgentToolRetry({\n toolName: call.name,\n toolCallId: call.id,\n attempt,\n message:\n retryError instanceof Error ? retryError.message : String(retryError),\n });\n },\n },\n ),\n ),\n );\n output =\n deps.toolTimeoutMs !== undefined\n ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\n }\n const executionMs = Date.now() - startedAt;\n await hooks.step(`persist:toolexec:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'executed',\n output,\n executionMs,\n ...(toolType === 'action' ? { executedByRef: deciderRef } : {}),\n }),\n );\n results.push({ id: call.id, name: call.name, output });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'executed',\n durationMs: executionMs,\n });\n } catch (error) {\n // Runner control-flow (durable suspend / continue-as-new) is not a tool failure — it must\n // propagate untouched, like awaitApproval's suspend does. Persisting a toolfail checkpoint\n // here would diverge from the replay's real result (NonDeterminismError).\n if (hooks.isControlFlowError?.(error) === true) {\n throw error;\n }\n const executionMs = Date.now() - startedAt;\n const message = error instanceof Error ? error.message : String(error);\n await hooks.step(`persist:toolfail:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'failed',\n error: message,\n executionMs,\n }),\n );\n results.push({ id: call.id, name: call.name, output: null, error: message });\n publishAgentToolCall({\n runId: hooks.runId,\n toolName: call.name,\n toolType,\n status: 'failed',\n durationMs: executionMs,\n });\n }\n }\n\n assistantMessage.toolResults = results;\n\n // Stream each tool's result so the client flips its live tool card from \"running\" to the\n // rendered output (renderResult → DataTable/Chart, executeSql → rows). One durable step keeps\n // replay from re-emitting. `error` covers both a thrown tool and a rejected action.\n await hooks.step(`stream:tool-outputs:${i}`, async () => {\n for (const result of results) {\n await writer.write(\n encodeStreamEvent(\n result.error !== undefined\n ? { kind: 'tool-output-error', id: result.id, error: result.error }\n : { kind: 'tool-output', id: result.id, output: result.output },\n ),\n );\n }\n });\n\n await hooks.step(`stream:step-finish:${i}`, async () => {\n await writer.write(encodeStreamEvent({ kind: 'step-finish', usage: turn.usage, costUsd }));\n });\n }\n\n if (thread !== null && (thread.title === '' || thread.title === 'New chat')) {\n await hooks.step('persist:title', () =>\n deps.store.setTitle(input.threadId, deriveTitle(input.userText)),\n );\n }\n\n // Normal completion only. The loop never records 'failed' — it doesn't catch its own crash;\n // failure recording is the RUNNER's job. A checkpointed step, so a resumed replay settles once.\n await hooks.step('persist:run:end', async () => {\n await deps.store.recordRunEnd?.({\n runId: hooks.runId,\n status: 'completed',\n durationMs: Date.now() - startedAt,\n });\n });\n\n await writer.end();\n publishAgentRunFinished({\n runId: hooks.runId,\n threadId: input.threadId,\n steps,\n inputTokens: totalInput,\n outputTokens: totalOutput,\n });\n return { text: lastText };\n}\n","import { emit } from '@dudousxd/nestjs-diagnostics';\nimport type { ChannelRegistry } from '@dudousxd/nestjs-diagnostics';\n\n/** Payloads carried on each `aviary:agent:*` channel. */\nexport interface AgentRunStarted {\n runId: string;\n threadId: string;\n actorId: string;\n /** Which agent is handling the run. */\n agentName?: string;\n}\nexport interface AgentMessageEvent {\n runId: string;\n threadId: string;\n role: 'user' | 'assistant';\n textLength: number;\n}\nexport interface AgentToolCallEvent {\n runId: string;\n toolName: string;\n toolType: 'read' | 'action';\n status: string;\n durationMs?: number;\n}\nexport interface AgentQuotaExceeded {\n actorId: string;\n usedTokens: number;\n limitTokens: number;\n}\nexport interface AgentRunFinished {\n runId: string;\n threadId: string;\n steps: number;\n inputTokens: number;\n outputTokens: number;\n}\nexport interface AgentRunFailed {\n runId: string;\n /** Stable failure slug, e.g. `quota_exceeded` or `run_failed`. */\n code: string;\n message: string;\n}\nexport interface AgentDelegated {\n runId: string;\n fromAgent?: string;\n toAgent: string;\n}\nexport interface AgentRetrieved {\n runId: string;\n query: string;\n /** How many passages the retriever returned. */\n count: number;\n}\n/**\n * A transient-classified tool error being retried in place (no new checkpoint) — see\n * `invokeWithTransientRetry`. Emitted once per retry (not for the final, non-retried outcome).\n */\nexport interface AgentToolRetry {\n toolName: string;\n toolCallId: string;\n /** 1-based ordinal of the attempt that just failed and is about to be retried. */\n attempt: number;\n /** The failed attempt's error message. */\n message: string;\n}\n\n// --- Span (trace) payloads — the START-phase payload of each traced operation. Metadata only:\n// token counts / lengths / names, never prompt or output text (the point events' redaction\n// posture). The traced result rides the `end`/`asyncEnd` envelope; see agent-loop's span helpers.\n\n/** START payload of an `aviary:agent:llm.turn:*` span — one model call within a run. */\nexport interface AgentLlmTurnSpan {\n runId: string;\n /** Zero-based model-call index within the run (the loop's step counter). */\n step: number;\n}\n/** START payload of an `aviary:agent:tool.execution:*` span — one tool invocation. */\nexport interface AgentToolExecutionSpan {\n runId: string;\n toolCallId: string;\n toolName: string;\n toolType: 'read' | 'action';\n}\n/** START payload of an `aviary:agent:retrieval:*` span — inject-mode RAG retrieval. */\nexport interface AgentRetrievalSpan {\n runId: string;\n /** Length of the retrieval query in characters — never the query text itself. */\n queryLength: number;\n topK: number;\n}\n/** START payload of an `aviary:agent:follow-ups:*` span — the extra follow-up-suggestions call. */\nexport interface AgentFollowUpsSpan {\n runId: string;\n /** Zero-based model-call index of the final turn the follow-ups ride on. */\n step: number;\n /** How many follow-up questions were requested. */\n count: number;\n}\n\n/** Declaration-merge so `emit('agent', ...)`, `trace('agent', ...)` and telescope infer the agent payloads. */\ndeclare module '@dudousxd/nestjs-diagnostics' {\n interface ChannelRegistry {\n agent: {\n 'run.started': AgentRunStarted;\n message: AgentMessageEvent;\n 'tool-call': AgentToolCallEvent;\n 'quota.exceeded': AgentQuotaExceeded;\n 'run.finished': AgentRunFinished;\n 'run.failed': AgentRunFailed;\n delegated: AgentDelegated;\n retrieved: AgentRetrieved;\n 'tool.retry': AgentToolRetry;\n // Span-only events (published via trace() on :start/:end/:asyncStart/:asyncEnd/:error\n // sub-channels, never as point events) — see AgentSpanEvent below.\n 'llm.turn': AgentLlmTurnSpan;\n 'tool.execution': AgentToolExecutionSpan;\n retrieval: AgentRetrievalSpan;\n 'follow-ups': AgentFollowUpsSpan;\n };\n }\n}\n\nexport function publishAgentRunStarted(payload: AgentRunStarted): void {\n emit('agent', 'run.started', payload);\n}\nexport function publishAgentMessage(payload: AgentMessageEvent): void {\n emit('agent', 'message', payload);\n}\nexport function publishAgentToolCall(payload: AgentToolCallEvent): void {\n emit('agent', 'tool-call', payload);\n}\nexport function publishAgentQuotaExceeded(payload: AgentQuotaExceeded): void {\n emit('agent', 'quota.exceeded', payload);\n}\nexport function publishAgentRunFinished(payload: AgentRunFinished): void {\n emit('agent', 'run.finished', payload);\n}\nexport function publishAgentRunFailed(payload: AgentRunFailed): void {\n emit('agent', 'run.failed', payload);\n}\nexport function publishAgentDelegated(payload: AgentDelegated): void {\n emit('agent', 'delegated', payload);\n}\nexport function publishAgentRetrieved(payload: AgentRetrieved): void {\n emit('agent', 'retrieved', payload);\n}\nexport function publishAgentToolRetry(payload: AgentToolRetry): void {\n emit('agent', 'tool.retry', payload);\n}\n\n/**\n * Events published ONLY as spans — via `trace('agent', ...)` on the five `:start`/`:end`/\n * `:asyncStart`/`:asyncEnd`/`:error` sub-channels — never as point events on the base channel.\n * They are deliberately NOT in {@link AGENT_DIAGNOSTIC_EVENTS}: the point-event watcher has\n * nothing to subscribe to on their base channels, and claiming their keys would be meaningless\n * (the generic bridge only records point traffic).\n */\nexport type AgentSpanEvent = 'llm.turn' | 'tool.execution' | 'retrieval' | 'follow-ups';\n\n/** All span-only events, in a stable order — for a future span recorder to derive sub-channels from. */\nexport const AGENT_SPAN_EVENTS: readonly AgentSpanEvent[] = [\n 'llm.turn',\n 'tool.execution',\n 'retrieval',\n 'follow-ups',\n];\n\n/** Compile-time-only check: every span event must be declared on `ChannelRegistry['agent']`. */\ntype AgentSpanEventsAreRegistered = [AgentSpanEvent] extends [keyof ChannelRegistry['agent']]\n ? true\n : [\"AGENT_SPAN_EVENTS names an event not declared on ChannelRegistry['agent']\"];\nconst agentSpanEventsAreRegistered: AgentSpanEventsAreRegistered = true;\nvoid agentSpanEventsAreRegistered;\n\n/** Every POINT event key declared on `ChannelRegistry['agent']` above — derived, not hand-copied. */\nexport type AgentDiagnosticEvent = Exclude<keyof ChannelRegistry['agent'], AgentSpanEvent>;\n\n/**\n * All 9 point events on `ChannelRegistry['agent']`, in a stable order — handy for wiring\n * subscribers (mirrors nestjs-media's `MEDIA_DIAGNOSTIC_EVENTS`). Span-only events (see\n * {@link AgentSpanEvent}) are excluded. A drift between this list and the registry is a compile\n * error in both directions: an extra/misspelled entry fails this array's own\n * `readonly AgentDiagnosticEvent[]` annotation immediately; a missing entry fails the\n * {@link AgentDiagnosticEventsCoverAllKeys} check below.\n */\nexport const AGENT_DIAGNOSTIC_EVENTS: readonly AgentDiagnosticEvent[] = [\n 'run.started',\n 'message',\n 'tool-call',\n 'quota.exceeded',\n 'run.finished',\n 'run.failed',\n 'delegated',\n 'retrieved',\n 'tool.retry',\n];\n\n/** Compile-time-only check: every point event of `ChannelRegistry['agent']` must appear above. */\ntype AgentDiagnosticEventsCoverAllKeys = [AgentDiagnosticEvent] extends [\n (typeof AGENT_DIAGNOSTIC_EVENTS)[number],\n]\n ? true\n : [\"AGENT_DIAGNOSTIC_EVENTS is missing a key declared on ChannelRegistry['agent']\"];\n\n// If this line stops typechecking, an event was added to (or renamed on) ChannelRegistry['agent']\n// without a matching update to AGENT_DIAGNOSTIC_EVENTS (point events) or AgentSpanEvent (spans).\nconst agentDiagnosticEventsCoverAllKeys: AgentDiagnosticEventsCoverAllKeys = true;\nvoid agentDiagnosticEventsCoverAllKeys;\n\n/**\n * The telescope key for an agent diagnostics channel — `agent:<event>`. This is the key the\n * `@dudousxd/nestjs-diagnostics-telescope` generic bridge matches its `exclude` option against,\n * and the label its \"Busiest events\" panel shows. Distinct from the `aviary:agent:<event>` channel\n * name used on the wire. Mirrors `mediaDiagnosticKey`.\n */\nexport type AgentDiagnosticKey = `agent:${AgentDiagnosticEvent}`;\n\n/**\n * Compose the telescope key for an agent event, typed against {@link AgentDiagnosticEvent} so a\n * misspelled event is a compile error. Feed the result to `nestjsDiagnosticsTelescope({ exclude:\n * [...] })` to mute a noisy channel, e.g. `agentDiagnosticKey('message')`.\n */\nexport function agentDiagnosticKey(event: AgentDiagnosticEvent): AgentDiagnosticKey {\n return `agent:${event}`;\n}\n","/**\n * Transient tool-error classification + the retry loop that wraps a tool's own invocation. A\n * classified-transient error (a DB deadlock, a lock-wait timeout, a serialization failure) means\n * the server rolled the tool's work back — retrying THAT class is safe, unlike a tool's general\n * business failure, which stays a one-shot outcome (no durable step retries: a tool may not be\n * idempotent). See `runAgentLoop`'s `tool:<call.id>` step body and `AgentRunSteps.tool` — both wrap\n * `registry.invoke(...)` with {@link invokeWithTransientRetry} so a retry never becomes a new\n * checkpoint; history still shows exactly one step per tool call.\n */\n\n/** Narrow, structural check for a MySQL/Postgres/SQLite transient error shape — no casts. */\nfunction hasTransientShape(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n const code = 'code' in error ? (error as { code: unknown }).code : undefined;\n const errno = 'errno' in error ? (error as { errno: unknown }).errno : undefined;\n const sqlState = 'sqlState' in error ? (error as { sqlState: unknown }).sqlState : undefined;\n if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {\n return true; // MySQL ER_LOCK_DEADLOCK / ER_LOCK_WAIT_TIMEOUT numeric codes\n }\n if (code === 'ER_LOCK_DEADLOCK' || code === 'ER_LOCK_WAIT_TIMEOUT') {\n return true; // MySQL driver string codes\n }\n if (code === '40001' || code === '40P01' || sqlState === '40001' || sqlState === '40P01') {\n return true; // Postgres serialization_failure / deadlock_detected SQLSTATEs\n }\n if (code === 'SQLITE_BUSY') {\n return true;\n }\n const message = 'message' in error ? (error as { message: unknown }).message : undefined;\n return (\n typeof message === 'string' && /deadlock|lock wait timeout|serialization failure/i.test(message)\n );\n}\n\n/**\n * Default transient-tool-error classifier: true for a recognized MySQL/Postgres/SQLite\n * lock-contention shape (by driver `code`/`errno`/`sqlState`, or a matching message), checked on\n * the error itself and one level of `cause` (drivers commonly wrap the original error). A plain\n * `Error` with none of these markers — any other business failure — is `false`.\n */\nexport function isTransientToolError(error: unknown): boolean {\n if (hasTransientShape(error)) {\n return true;\n }\n if (typeof error === 'object' && error !== null && 'cause' in error) {\n const cause = (error as { cause: unknown }).cause;\n if (cause !== undefined && cause !== error && hasTransientShape(cause)) {\n return true;\n }\n }\n return false;\n}\n\n/** Total attempts (initial try + retries) when `toolTransientRetry` doesn't set `attempts`. */\nexport const DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;\n/** Backoff base in ms — the wait between attempt N and N+1 is `backoffMs * N`. */\nexport const DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;\n\n/** The host-configurable half of the policy — everything except the (non-wire-safe) `classify` fn. */\nexport interface ToolTransientRetryOptions {\n /** Total attempts (initial try + retries). Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS}. */\n attempts?: number;\n /** Backoff base in ms. Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS}. */\n backoffMs?: number;\n /** Overrides the default classifier — widen or narrow which errors are treated as transient. */\n classify?: (error: unknown) => boolean;\n}\n\n/** `false` disables transient retry entirely — a tool's own thrown error surfaces immediately. */\nexport type ToolTransientRetrySetting = ToolTransientRetryOptions | false;\n\n/** Just the wire-safe (numeric) half of a resolved policy — what a dispatched envelope carries. */\nexport interface ToolTransientRetryNumbers {\n attempts: number;\n backoffMs: number;\n}\n\n/**\n * Resolves the numeric half of `toolTransientRetry` for the dispatched wire envelope: `false` when\n * explicitly disabled, else concrete `{ attempts, backoffMs }` (defaults filled in) — never\n * `undefined`, so the dispatched handler always gets a definite answer instead of re-deriving its\n * own default. The `classify` function never rides this — it isn't wire-safe; the dispatched\n * handler resolves its own `classify` from its local module options (see `AgentRunSteps.tool`).\n */\nexport function resolveToolTransientRetryNumbers(\n setting: ToolTransientRetrySetting | undefined,\n): ToolTransientRetryNumbers | false {\n if (setting === false) {\n return false;\n }\n return {\n attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,\n backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,\n };\n}\n\nexport interface InvokeWithTransientRetryOptions {\n /**\n * Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so a retry\n * never swallows one — same rule the loop's tool catch already applies. Undefined for a call site\n * with no such notion (e.g. the dispatched step handler, which has no workflow ctx of its own).\n */\n isControlFlowError?: (error: unknown) => boolean;\n /**\n * Called before each wait-and-retry, with the 1-based ordinal of the attempt that just failed and\n * the error it threw. The call site uses this to emit the `tool.retry` diagnostics point event —\n * `invokeWithTransientRetry` itself carries no tool identity (name/callId), only the thunk.\n */\n onRetry?: (attempt: number, error: unknown) => void;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Retries `fn` in place — never a new durable step/checkpoint, just repeated attempts inside\n * whichever step body already wraps this call. `setting: false` runs `fn` once, unwrapped (no\n * classify/backoff bookkeeping at all). Otherwise: try; on a thrown error, rethrow immediately if\n * it's a recognized control-flow signal, else if the (possibly custom) classifier calls it\n * transient AND attempts remain, wait `backoffMs * attemptNumber` and retry; otherwise rethrow the\n * error as-is.\n */\nexport async function invokeWithTransientRetry<T>(\n fn: () => Promise<T>,\n setting: ToolTransientRetrySetting,\n options?: InvokeWithTransientRetryOptions,\n): Promise<T> {\n if (setting === false) {\n return fn();\n }\n const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;\n const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;\n const classify = setting.classify ?? isTransientToolError;\n\n let attempt = 1;\n for (;;) {\n try {\n return await fn();\n } catch (error) {\n if (options?.isControlFlowError?.(error) === true) {\n throw error;\n }\n const attemptsRemain = attempt < attempts;\n if (!attemptsRemain || !classify(error)) {\n throw error;\n }\n options?.onRetry?.(attempt, error);\n await delay(backoffMs * attempt);\n attempt += 1;\n }\n }\n}\n"],"mappings":"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","names":["AGENT_OPTIONS","Symbol","for","AGENT_STORE","AGENT_RUNNER","AGENT_DURABLE_RUNNER","AGENT_SINK","AGENT_MODEL","AGENT_ROLES_POLICY","AGENT_QUOTA_STORE","AGENT_TOOL_REGISTRY","AGENT_REGISTRY","AGENT_ACTOR_RESOLVER","AGENT_GOVERNANCE_QUERIES","AGENT_PRICING_STORE","AGENT_RETRIEVER","AGENT_EMBEDDING_PROVIDER","AGENT_DEPS_FACTORY","AGENT_PROMPT_CONTRIBUTORS","AGENT_ACTOR_DIRECTORY","AGENT_ATTACHMENT_STAGING","AGENT_APPROVAL_PORT","AgentStreamError","Error","code","error","message","name","encoder","TextEncoder","encodeStreamEvent","event","encode","JSON","stringify","seedModelPrices","store","prices","price","upsertModelPrice","THREAD_DETAIL_CONTENT_CHARS","truncateDetailContent","content","length","truncated","slice","estimateCost","usage","price","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","row","prices","costUsd","get","modelId","bucketByModel","rows","byModel","Map","bucket","requests","set","result","push","sort","left","right","localeCompare","bucketByActor","byActor","actorRef","totalTokens","threadIds","Set","add","threadId","threadCount","size","bucketByThread","threads","options","byThread","thread","includeUnknownThreads","title","slice","limit","rollupThreadUsage","rollup","bucketUsageTrend","byDay","day","dayBoundsUtc","range","start","Date","fromDay","end","toDay","isToolEnabled","spec","handler","declared","enabled","isEnabled","undefined","filterToolsByEnabled","entries","checked","Promise","all","map","entry","filter","row","canActorUseTool","actor","canUse","filterToolsByCanUse","allowed","filterToolsByRole","tools","policy","tool","can","filterToolsByAllowList","allowedTools","Set","has","name","AgentRegistry","definitions","Map","register","definition","set","name","get","has","list","values","ToolForbiddenError","Error","toolName","name","ToolDisabledError","ToolNotFoundError","ToolInputInvalidError","issues","map","issue","message","join","ToolRegistry","entries","Map","register","spec","handler","set","has","get","allSpecs","values","entry","definitionsFor","actor","policy","allowedTools","live","filterToolsByEnabled","allowedByRole","Set","filterToolsByRole","roleScoped","filter","actorScoped","filterToolsByCanUse","allowScoped","filterToolsByAllowList","kind","description","inputSchema","invoke","input","ctx","undefined","isToolEnabled","can","canActorUseTool","validation","validate","execute","value","DefaultRolesPolicy","defaultRoles","tool","allowed","roles","some","role","includes","createHash","trace","emit","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","publishAgentToolRetry","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","hasTransientShape","error","code","undefined","errno","sqlState","message","test","isTransientToolError","cause","DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS","DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS","resolveToolTransientRetryNumbers","setting","attempts","backoffMs","delay","ms","Promise","resolve","setTimeout","invokeWithTransientRetry","fn","options","classify","attempt","isControlFlowError","attemptsRemain","onRetry","resolveCostUsd","usage","reportedCostUsd","price","undefined","estimateCost","buildContextBlock","passages","items","map","passage","index","label","source","text","join","QuotaExceededError","Error","name","MAX_DELEGATION_DEPTH","resolvePrompt","prompt","ctx","resolveSystemPrompt","deps","input","actor","agentName","pageContext","sections","systemPrompt","contribute","promptContributors","section","length","push","extractTask","task","JSON","stringify","deriveTitle","userText","trimmed","trim","replace","slice","ToolTimeoutError","toolName","ms","withToolTimeout","work","Promise","resolve","reject","timer","setTimeout","then","value","clearTimeout","error","parseFollowUps","count","match","parsed","parse","Array","isArray","filter","item","generateFollowUps","model","messages","discard","write","end","fail","turn","runTurn","system","tools","sink","followUps","modelId","spanned","event","runId","payload","run","summarize","trace","traceId","traceLlmTurn","step","inputTokens","outputTokens","textLength","toolCalls","traceToolExecution","call","runAgentLoop","hooks","maxSteps","quota","state","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","attachments","thread","modelMessages","message","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","startedAt","Date","now","promptHash","createHash","update","digest","recordRunStart","actorRef","injectedPassages","retriever","topK","retrievalTopK","queryLength","retrieve","retrieved","publishAgentRetrieved","query","prices","pricingStore","listCurrentPrices","priceByModel","Map","i","encodeStreamEvent","kind","dispatchLlm","registry","definitionsFor","rolesPolicy","toolAllowList","resolvedModelId","costUsd","get","toolCallsWithKind","spec","recordUsage","purpose","bump","publishAgentMessage","isFinalTurn","followUpsCount","generated","result","assistant","assistantMessage","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","deciderRef","decision","awaitApproval","executedByRef","approved","reason","rejected","publishAgentToolCall","dispatchTool","stepCtx","envelope","toolTimeoutMs","timeoutMs","transientRetry","resolveToolTransientRetryNumbers","toolTransientRetry","invocation","invokeWithTransientRetry","invoke","isControlFlowError","onRetry","attempt","retryError","publishAgentToolRetry","String","executionMs","durationMs","title","setTitle","recordRunEnd","publishAgentRunFinished"]}
|