@dudousxd/nestjs-agent-core 0.8.0 → 0.9.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 +8 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -861,7 +861,8 @@ ${buildContextBlock(passages)}`;
|
|
|
861
861
|
input: {
|
|
862
862
|
query: input.userText
|
|
863
863
|
},
|
|
864
|
-
status: "auto_executed"
|
|
864
|
+
status: "auto_executed",
|
|
865
|
+
runId: hooks.runId
|
|
865
866
|
});
|
|
866
867
|
await deps.store.updateToolCall({
|
|
867
868
|
toolCallId,
|
|
@@ -910,7 +911,8 @@ ${buildContextBlock(passages)}`;
|
|
|
910
911
|
toolName: call.name,
|
|
911
912
|
toolType: "read",
|
|
912
913
|
input: call.input,
|
|
913
|
-
status: "auto_executed"
|
|
914
|
+
status: "auto_executed",
|
|
915
|
+
runId: hooks.runId
|
|
914
916
|
}));
|
|
915
917
|
const overDepth = (input.delegationDepth ?? 0) >= MAX_DELEGATION_DEPTH;
|
|
916
918
|
publishAgentDelegated({
|
|
@@ -952,7 +954,8 @@ ${buildContextBlock(passages)}`;
|
|
|
952
954
|
toolName: call.name,
|
|
953
955
|
toolType: "action",
|
|
954
956
|
input: call.input,
|
|
955
|
-
status: "pending_approval"
|
|
957
|
+
status: "pending_approval",
|
|
958
|
+
runId: hooks.runId
|
|
956
959
|
}));
|
|
957
960
|
const decision = await hooks.awaitApproval(call, ctx);
|
|
958
961
|
deciderRef = decision.executedByRef ?? input.actor.id;
|
|
@@ -989,7 +992,8 @@ ${buildContextBlock(passages)}`;
|
|
|
989
992
|
toolName: call.name,
|
|
990
993
|
toolType: "read",
|
|
991
994
|
input: call.input,
|
|
992
|
-
status: "auto_executed"
|
|
995
|
+
status: "auto_executed",
|
|
996
|
+
runId: hooks.runId
|
|
993
997
|
}));
|
|
994
998
|
}
|
|
995
999
|
const startedAt2 = Date.now();
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/tokens.ts","../src/spi/token-stream-sink.ts","../src/stream-events.ts","../src/spi/pricing-store.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.ts"],"sourcesContent":["export * from './types.js';\nexport * from './tokens.js';\nexport * from './spi/tool.js';\nexport * from './spi/model-provider.js';\nexport * from './spi/token-stream-sink.js';\nexport * from './stream-events.js';\nexport * from './spi/agent-store.js';\nexport * from './spi/roles-policy.js';\nexport * from './spi/quota-store.js';\nexport * from './spi/pricing-store.js';\nexport * from './spi/retriever.js';\nexport * from './spi/embedding-provider.js';\nexport * from './spi/reranker.js';\nexport * from './spi/agent-runner.js';\nexport * from './spi/actor-resolver.js';\nexport * from './spi/governance-queries.js';\nexport * from './spi/actor-directory.js';\nexport * from './spi/attachment-staging.js';\nexport * from './spi/approval-port.js';\nexport * from './governance/compute.js';\nexport * from './tool-filters.js';\nexport { AgentRegistry } from './agent-registry.js';\nexport {\n ToolRegistry,\n DefaultRolesPolicy,\n ToolForbiddenError,\n ToolNotFoundError,\n ToolInputInvalidError,\n} from './tool-registry.js';\nexport {\n runAgentLoop,\n QuotaExceededError,\n withToolTimeout,\n traceLlmTurn,\n traceToolExecution,\n type AgentLoopDeps,\n type AgentLoopHooks,\n} from './agent-loop.js';\nexport * from './diagnostics.js';\n","/**\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","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\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/** 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} 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 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 * 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 });\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 }),\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 }),\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 }),\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 };\n // The handler applies withToolTimeout itself — no loop-side wrap for 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 () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\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// --- 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 // 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}\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 8 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];\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"],"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","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","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","import_nestjs_diagnostics","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","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","invocation","invoke","executionMs","durationMs","isControlFlowError","String","title","setTitle","recordRunEnd","publishAgentRunFinished"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/tokens.ts","../src/spi/token-stream-sink.ts","../src/stream-events.ts","../src/spi/pricing-store.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.ts"],"sourcesContent":["export * from './types.js';\nexport * from './tokens.js';\nexport * from './spi/tool.js';\nexport * from './spi/model-provider.js';\nexport * from './spi/token-stream-sink.js';\nexport * from './stream-events.js';\nexport * from './spi/agent-store.js';\nexport * from './spi/roles-policy.js';\nexport * from './spi/quota-store.js';\nexport * from './spi/pricing-store.js';\nexport * from './spi/retriever.js';\nexport * from './spi/embedding-provider.js';\nexport * from './spi/reranker.js';\nexport * from './spi/agent-runner.js';\nexport * from './spi/actor-resolver.js';\nexport * from './spi/governance-queries.js';\nexport * from './spi/actor-directory.js';\nexport * from './spi/attachment-staging.js';\nexport * from './spi/approval-port.js';\nexport * from './governance/compute.js';\nexport * from './tool-filters.js';\nexport { AgentRegistry } from './agent-registry.js';\nexport {\n ToolRegistry,\n DefaultRolesPolicy,\n ToolForbiddenError,\n ToolNotFoundError,\n ToolInputInvalidError,\n} from './tool-registry.js';\nexport {\n runAgentLoop,\n QuotaExceededError,\n withToolTimeout,\n traceLlmTurn,\n traceToolExecution,\n type AgentLoopDeps,\n type AgentLoopHooks,\n} from './agent-loop.js';\nexport * from './diagnostics.js';\n","/**\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","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\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/** 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} 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 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 * 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 };\n // The handler applies withToolTimeout itself — no loop-side wrap for 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 () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\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// --- 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 // 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}\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 8 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];\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"],"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","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","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","import_nestjs_diagnostics","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","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","invocation","invoke","executionMs","durationMs","isControlFlowError","String","title","setTitle","recordRunEnd","publishAgentRunFinished"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -559,6 +559,12 @@ interface RecordToolCallInput {
|
|
|
559
559
|
toolType: 'read' | 'action';
|
|
560
560
|
input: unknown;
|
|
561
561
|
status: ToolCallStatus;
|
|
562
|
+
/**
|
|
563
|
+
* The run (turn) this tool call belongs to — enables a governance surface to deep-link a tool
|
|
564
|
+
* call out to its trace waterfall. Optional so a caller predating this (or a store's own
|
|
565
|
+
* synthetic tool calls) can omit it; the store persists it as `null` when absent.
|
|
566
|
+
*/
|
|
567
|
+
runId?: string;
|
|
562
568
|
}
|
|
563
569
|
interface UpdateToolCallInput {
|
|
564
570
|
toolCallId: string;
|
|
@@ -879,6 +885,8 @@ interface ToolCallActivityRow {
|
|
|
879
885
|
status: string;
|
|
880
886
|
threadId: string;
|
|
881
887
|
createdAt: string;
|
|
888
|
+
/** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */
|
|
889
|
+
runId: string | null;
|
|
882
890
|
}
|
|
883
891
|
/** A recent thread with rolled-up activity. */
|
|
884
892
|
interface ThreadActivityRow {
|
|
@@ -949,6 +957,8 @@ interface PendingApprovalRow {
|
|
|
949
957
|
agentName: string | null;
|
|
950
958
|
/** ISO timestamp. */
|
|
951
959
|
requestedAt: string;
|
|
960
|
+
/** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */
|
|
961
|
+
runId: string | null;
|
|
952
962
|
}
|
|
953
963
|
/** Governance rollup for one tool over a range. */
|
|
954
964
|
interface ToolStatRow {
|
|
@@ -1004,6 +1014,7 @@ interface RunWhere {
|
|
|
1004
1014
|
agentName?: string;
|
|
1005
1015
|
status?: string;
|
|
1006
1016
|
errorCode?: string;
|
|
1017
|
+
threadId?: string;
|
|
1007
1018
|
fromDay?: string;
|
|
1008
1019
|
toDay?: string;
|
|
1009
1020
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -559,6 +559,12 @@ interface RecordToolCallInput {
|
|
|
559
559
|
toolType: 'read' | 'action';
|
|
560
560
|
input: unknown;
|
|
561
561
|
status: ToolCallStatus;
|
|
562
|
+
/**
|
|
563
|
+
* The run (turn) this tool call belongs to — enables a governance surface to deep-link a tool
|
|
564
|
+
* call out to its trace waterfall. Optional so a caller predating this (or a store's own
|
|
565
|
+
* synthetic tool calls) can omit it; the store persists it as `null` when absent.
|
|
566
|
+
*/
|
|
567
|
+
runId?: string;
|
|
562
568
|
}
|
|
563
569
|
interface UpdateToolCallInput {
|
|
564
570
|
toolCallId: string;
|
|
@@ -879,6 +885,8 @@ interface ToolCallActivityRow {
|
|
|
879
885
|
status: string;
|
|
880
886
|
threadId: string;
|
|
881
887
|
createdAt: string;
|
|
888
|
+
/** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */
|
|
889
|
+
runId: string | null;
|
|
882
890
|
}
|
|
883
891
|
/** A recent thread with rolled-up activity. */
|
|
884
892
|
interface ThreadActivityRow {
|
|
@@ -949,6 +957,8 @@ interface PendingApprovalRow {
|
|
|
949
957
|
agentName: string | null;
|
|
950
958
|
/** ISO timestamp. */
|
|
951
959
|
requestedAt: string;
|
|
960
|
+
/** The run this call belongs to, for a trace deep-link; `null` for a call recorded before this shipped. */
|
|
961
|
+
runId: string | null;
|
|
952
962
|
}
|
|
953
963
|
/** Governance rollup for one tool over a range. */
|
|
954
964
|
interface ToolStatRow {
|
|
@@ -1004,6 +1014,7 @@ interface RunWhere {
|
|
|
1004
1014
|
agentName?: string;
|
|
1005
1015
|
status?: string;
|
|
1006
1016
|
errorCode?: string;
|
|
1017
|
+
threadId?: string;
|
|
1007
1018
|
fromDay?: string;
|
|
1008
1019
|
toDay?: string;
|
|
1009
1020
|
}
|
package/dist/index.js
CHANGED
|
@@ -785,7 +785,8 @@ ${buildContextBlock(passages)}`;
|
|
|
785
785
|
input: {
|
|
786
786
|
query: input.userText
|
|
787
787
|
},
|
|
788
|
-
status: "auto_executed"
|
|
788
|
+
status: "auto_executed",
|
|
789
|
+
runId: hooks.runId
|
|
789
790
|
});
|
|
790
791
|
await deps.store.updateToolCall({
|
|
791
792
|
toolCallId,
|
|
@@ -834,7 +835,8 @@ ${buildContextBlock(passages)}`;
|
|
|
834
835
|
toolName: call.name,
|
|
835
836
|
toolType: "read",
|
|
836
837
|
input: call.input,
|
|
837
|
-
status: "auto_executed"
|
|
838
|
+
status: "auto_executed",
|
|
839
|
+
runId: hooks.runId
|
|
838
840
|
}));
|
|
839
841
|
const overDepth = (input.delegationDepth ?? 0) >= MAX_DELEGATION_DEPTH;
|
|
840
842
|
publishAgentDelegated({
|
|
@@ -876,7 +878,8 @@ ${buildContextBlock(passages)}`;
|
|
|
876
878
|
toolName: call.name,
|
|
877
879
|
toolType: "action",
|
|
878
880
|
input: call.input,
|
|
879
|
-
status: "pending_approval"
|
|
881
|
+
status: "pending_approval",
|
|
882
|
+
runId: hooks.runId
|
|
880
883
|
}));
|
|
881
884
|
const decision = await hooks.awaitApproval(call, ctx);
|
|
882
885
|
deciderRef = decision.executedByRef ?? input.actor.id;
|
|
@@ -913,7 +916,8 @@ ${buildContextBlock(passages)}`;
|
|
|
913
916
|
toolName: call.name,
|
|
914
917
|
toolType: "read",
|
|
915
918
|
input: call.input,
|
|
916
|
-
status: "auto_executed"
|
|
919
|
+
status: "auto_executed",
|
|
920
|
+
runId: hooks.runId
|
|
917
921
|
}));
|
|
918
922
|
}
|
|
919
923
|
const startedAt2 = Date.now();
|
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/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.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","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\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/** 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} 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 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 * 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 });\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 }),\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 }),\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 }),\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 };\n // The handler applies withToolTimeout itself — no loop-side wrap for 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 () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\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// --- 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 // 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}\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 8 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];\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"],"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","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","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","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","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","invocation","invoke","executionMs","durationMs","isControlFlowError","String","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/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/agent-loop.ts","../src/diagnostics.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","import type {\n ActorSpendRow,\n GovernanceRange,\n ModelSpendRow,\n ThreadSpendRow,\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/** 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} 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 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 * 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 };\n // The handler applies withToolTimeout itself — no loop-side wrap for 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 () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\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// --- 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 // 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}\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 8 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];\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"],"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","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","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","AGENT_SPAN_EVENTS","AGENT_DIAGNOSTIC_EVENTS","agentDiagnosticKey","event","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","invocation","invoke","executionMs","durationMs","isControlFlowError","String","title","setTitle","recordRunEnd","publishAgentRunFinished"]}
|