@dudousxd/nestjs-agent-core 0.3.2 → 0.3.3
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 +48 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -1
- package/dist/index.d.ts +73 -1
- package/dist/index.js +47 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -51,6 +51,7 @@ __export(index_exports, {
|
|
|
51
51
|
bucketByThread: () => bucketByThread,
|
|
52
52
|
bucketUsageTrend: () => bucketUsageTrend,
|
|
53
53
|
dayBoundsUtc: () => dayBoundsUtc,
|
|
54
|
+
encodeStreamEvent: () => encodeStreamEvent,
|
|
54
55
|
estimateCost: () => estimateCost,
|
|
55
56
|
filterToolsByAllowList: () => filterToolsByAllowList,
|
|
56
57
|
filterToolsByRole: () => filterToolsByRole,
|
|
@@ -99,6 +100,14 @@ var AgentStreamError = class extends Error {
|
|
|
99
100
|
}
|
|
100
101
|
};
|
|
101
102
|
|
|
103
|
+
// src/stream-events.ts
|
|
104
|
+
var encoder = new TextEncoder();
|
|
105
|
+
function encodeStreamEvent(event) {
|
|
106
|
+
return encoder.encode(`${JSON.stringify(event)}
|
|
107
|
+
`);
|
|
108
|
+
}
|
|
109
|
+
__name(encodeStreamEvent, "encodeStreamEvent");
|
|
110
|
+
|
|
102
111
|
// src/spi/pricing-store.ts
|
|
103
112
|
async function seedModelPrices(store, prices) {
|
|
104
113
|
for (const price of prices) {
|
|
@@ -569,7 +578,10 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
569
578
|
await hooks.step("persist:user", () => deps.store.appendMessage({
|
|
570
579
|
threadId: input.threadId,
|
|
571
580
|
role: "user",
|
|
572
|
-
content: input.userText
|
|
581
|
+
content: input.userText,
|
|
582
|
+
...input.attachments !== void 0 ? {
|
|
583
|
+
attachments: input.attachments
|
|
584
|
+
} : {}
|
|
573
585
|
}));
|
|
574
586
|
}
|
|
575
587
|
const thread = await hooks.step("load:thread", () => deps.store.getThread(input.threadId));
|
|
@@ -581,6 +593,9 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
581
593
|
} : {},
|
|
582
594
|
...message.toolResults !== void 0 ? {
|
|
583
595
|
toolResults: message.toolResults
|
|
596
|
+
} : {},
|
|
597
|
+
...message.attachments !== void 0 ? {
|
|
598
|
+
attachments: message.attachments
|
|
584
599
|
} : {}
|
|
585
600
|
}));
|
|
586
601
|
const writer = await hooks.openSink();
|
|
@@ -615,6 +630,11 @@ ${buildContextBlock(passages)}`;
|
|
|
615
630
|
});
|
|
616
631
|
}
|
|
617
632
|
for (let i = 0; i < maxSteps; i += 1) {
|
|
633
|
+
await hooks.step(`stream:step-start:${i}`, async () => {
|
|
634
|
+
await writer.write(encodeStreamEvent({
|
|
635
|
+
kind: "step-start"
|
|
636
|
+
}));
|
|
637
|
+
});
|
|
618
638
|
const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
|
|
619
639
|
const turn = await hooks.step(`llm:${i}`, () => deps.model.runTurn({
|
|
620
640
|
system,
|
|
@@ -685,13 +705,14 @@ ${buildContextBlock(passages)}`;
|
|
|
685
705
|
followUps
|
|
686
706
|
} : {}
|
|
687
707
|
}));
|
|
688
|
-
|
|
708
|
+
const assistantMessage = {
|
|
689
709
|
role: "assistant",
|
|
690
710
|
content: turn.text,
|
|
691
711
|
...turn.toolCalls.length > 0 ? {
|
|
692
712
|
toolCalls: turn.toolCalls
|
|
693
713
|
} : {}
|
|
694
|
-
}
|
|
714
|
+
};
|
|
715
|
+
modelMessages.push(assistantMessage);
|
|
695
716
|
if (i === 0 && injectedPassages !== void 0) {
|
|
696
717
|
const passages = injectedPassages;
|
|
697
718
|
const toolCallId = `retrieve-${assistant.id}`;
|
|
@@ -716,6 +737,11 @@ ${buildContextBlock(passages)}`;
|
|
|
716
737
|
});
|
|
717
738
|
}
|
|
718
739
|
if (isFinalTurn) {
|
|
740
|
+
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
741
|
+
await writer.write(encodeStreamEvent({
|
|
742
|
+
kind: "step-finish"
|
|
743
|
+
}));
|
|
744
|
+
});
|
|
719
745
|
break;
|
|
720
746
|
}
|
|
721
747
|
const results = [];
|
|
@@ -875,10 +901,24 @@ ${buildContextBlock(passages)}`;
|
|
|
875
901
|
});
|
|
876
902
|
}
|
|
877
903
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
904
|
+
assistantMessage.toolResults = results;
|
|
905
|
+
await hooks.step(`stream:tool-outputs:${i}`, async () => {
|
|
906
|
+
for (const result of results) {
|
|
907
|
+
await writer.write(encodeStreamEvent(result.error !== void 0 ? {
|
|
908
|
+
kind: "tool-output-error",
|
|
909
|
+
id: result.id,
|
|
910
|
+
error: result.error
|
|
911
|
+
} : {
|
|
912
|
+
kind: "tool-output",
|
|
913
|
+
id: result.id,
|
|
914
|
+
output: result.output
|
|
915
|
+
}));
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
919
|
+
await writer.write(encodeStreamEvent({
|
|
920
|
+
kind: "step-finish"
|
|
921
|
+
}));
|
|
882
922
|
});
|
|
883
923
|
}
|
|
884
924
|
if (thread !== null && (thread.title === "" || thread.title === "New chat")) {
|
|
@@ -929,6 +969,7 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
929
969
|
bucketByThread,
|
|
930
970
|
bucketUsageTrend,
|
|
931
971
|
dayBoundsUtc,
|
|
972
|
+
encodeStreamEvent,
|
|
932
973
|
estimateCost,
|
|
933
974
|
filterToolsByAllowList,
|
|
934
975
|
filterToolsByRole,
|
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/spi/pricing-store.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/diagnostics.ts","../src/agent-loop.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 './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 './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 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 * 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 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 { emit } 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/** Declaration-merge so `emit('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 };\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","import {\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n} from './diagnostics.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider } from './spi/model-provider.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 type { ToolRegistry } from './tool-registry.js';\nimport type {\n AgentRunInput,\n Decision,\n MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\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\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.step(name, fn).\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\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. */\nfunction withTimeout<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 * 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 }),\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 }));\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 // 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 passages = await hooks.step('retrieve', () =>\n retriever.retrieve(input.userText, { topK: deps.retrievalTopK ?? 5 }),\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 // 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 const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n\n const turn = await hooks.step(`llm:${i}`, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n );\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n modelId: turn.modelId ?? deps.modelId ?? 'unknown',\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 const generated = await hooks.step(`followups:${i}`, () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\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,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n }),\n );\n modelMessages.push({\n role: 'assistant',\n content: turn.text,\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\n });\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 break;\n }\n\n const results: ToolResult[] = [];\n for (const call of turn.toolCalls) {\n const spec = deps.registry.spec(call.name);\n const toolType = spec?.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 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 if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\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 const invocation = hooks.step(`tool:${call.id}`, () =>\n deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n );\n const output =\n deps.toolTimeoutMs !== undefined\n ? await withTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\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: input.actor.id } : {}),\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 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 modelMessages.push({ role: 'user', content: '', toolResults: results });\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 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"],"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","AgentStreamError","Error","code","error","message","name","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","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","buildContextBlock","passages","items","map","passage","index","label","source","undefined","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","withTimeout","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","usage","modelId","runAgentLoop","hooks","maxSteps","quota","state","step","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","thread","modelMessages","message","toolCalls","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","runId","injectedPassages","retriever","retrieve","topK","retrievalTopK","publishAgentRetrieved","query","i","registry","definitionsFor","rolesPolicy","toolAllowList","recordUsage","actorRef","purpose","costUsd","bump","inputTokens","outputTokens","publishAgentMessage","textLength","isFinalTurn","followUpsCount","generated","assistant","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","call","spec","kind","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","decision","awaitApproval","approved","reason","rejected","publishAgentToolCall","startedAt","Date","now","invocation","invoke","toolTimeoutMs","executionMs","executedByRef","durationMs","String","title","setTitle","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/diagnostics.ts","../src/agent-loop.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 './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 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 * 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 */\nexport type AgentStreamEvent =\n | { kind: 'step-start' }\n | { kind: 'step-finish' }\n | { kind: 'text'; text: string }\n | { kind: 'reasoning'; text: string }\n | { kind: 'tool-input-start'; id: string; name: string }\n | { kind: 'tool-input-delta'; id: string; delta: string }\n | { kind: 'tool-input-available'; id: string; name: string; input: unknown }\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 { emit } 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/** Declaration-merge so `emit('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 };\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","import {\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n} from './diagnostics.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider } from './spi/model-provider.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 MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\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\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.step(name, fn).\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\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. */\nfunction withTimeout<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 * 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 // 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 passages = await hooks.step('retrieve', () =>\n retriever.retrieve(input.userText, { topK: deps.retrievalTopK ?? 5 }),\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 // 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 const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n\n const turn = await hooks.step(`llm:${i}`, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n );\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n modelId: turn.modelId ?? deps.modelId ?? 'unknown',\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 const generated = await hooks.step(`followups:${i}`, () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\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,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\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 ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\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' }));\n });\n break;\n }\n\n const results: ToolResult[] = [];\n for (const call of turn.toolCalls) {\n const spec = deps.registry.spec(call.name);\n const toolType = spec?.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 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 if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\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 const invocation = hooks.step(`tool:${call.id}`, () =>\n deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n );\n const output =\n deps.toolTimeoutMs !== undefined\n ? await withTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\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: input.actor.id } : {}),\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 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' }));\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 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"],"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","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","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","buildContextBlock","passages","items","map","passage","index","label","source","undefined","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","withTimeout","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","usage","modelId","runAgentLoop","hooks","maxSteps","quota","state","step","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","attachments","thread","modelMessages","message","toolCalls","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","runId","injectedPassages","retriever","retrieve","topK","retrievalTopK","publishAgentRetrieved","query","i","encodeStreamEvent","kind","registry","definitionsFor","rolesPolicy","toolAllowList","recordUsage","actorRef","purpose","costUsd","bump","inputTokens","outputTokens","publishAgentMessage","textLength","isFinalTurn","followUpsCount","generated","assistant","assistantMessage","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","call","spec","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","decision","awaitApproval","approved","reason","rejected","publishAgentToolCall","startedAt","Date","now","invocation","invoke","toolTimeoutMs","executionMs","executedByRef","durationMs","String","result","title","setTitle","publishAgentRunFinished"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -107,12 +107,30 @@ interface Decision {
|
|
|
107
107
|
reason?: string;
|
|
108
108
|
}
|
|
109
109
|
type MessageRole = 'user' | 'assistant' | 'system';
|
|
110
|
+
/**
|
|
111
|
+
* A file a user attached to a message so a vision-capable model sees it natively (an image, a PDF).
|
|
112
|
+
* The lib stays provider-agnostic: it passes {@link MessageAttachment.url} straight through as the
|
|
113
|
+
* model's image/file part data — making that URL reachable by the provider (presigned S3, a proxy)
|
|
114
|
+
* is the consumer's job. The lib never fetches bytes or talks to a store.
|
|
115
|
+
*/
|
|
116
|
+
interface MessageAttachment {
|
|
117
|
+
/** Stable id of the stored media object in the consumer's media store. Provenance + replay key. */
|
|
118
|
+
mediaId: string;
|
|
119
|
+
/** A URL the model provider can fetch the bytes from at turn time. */
|
|
120
|
+
url: string;
|
|
121
|
+
/** MIME type — routes the part: `image/*` → image part, otherwise → file part. */
|
|
122
|
+
contentType: string;
|
|
123
|
+
/** Original filename, for display and the file part's filename. */
|
|
124
|
+
name: string;
|
|
125
|
+
}
|
|
110
126
|
/** A neutral chat message exchanged with the model. */
|
|
111
127
|
interface ModelMessage {
|
|
112
128
|
role: MessageRole;
|
|
113
129
|
content: string;
|
|
114
130
|
toolCalls?: ToolCallRequest[];
|
|
115
131
|
toolResults?: ToolResult[];
|
|
132
|
+
/** User-message attachments (image/PDF), rendered as native model content parts by the adapter. */
|
|
133
|
+
attachments?: MessageAttachment[];
|
|
116
134
|
}
|
|
117
135
|
interface PageContext {
|
|
118
136
|
kind?: string;
|
|
@@ -148,6 +166,8 @@ interface AgentRunInput {
|
|
|
148
166
|
actor: Actor;
|
|
149
167
|
/** The latest user message text. */
|
|
150
168
|
userText: string;
|
|
169
|
+
/** Files attached to the latest user message (image/PDF). Persisted with it and sent to the model. */
|
|
170
|
+
attachments?: MessageAttachment[];
|
|
151
171
|
pageContext?: PageContext;
|
|
152
172
|
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
153
173
|
day?: string;
|
|
@@ -218,6 +238,8 @@ interface StoredMessage {
|
|
|
218
238
|
agentName?: string;
|
|
219
239
|
toolCalls?: ToolCallRequest[];
|
|
220
240
|
toolResults?: ToolResult[];
|
|
241
|
+
/** Files the user attached to this message (image/PDF). Persisted with the message, replayed as-is. */
|
|
242
|
+
attachments?: MessageAttachment[];
|
|
221
243
|
followUps?: string[];
|
|
222
244
|
usage?: MessageUsage;
|
|
223
245
|
createdAt: string;
|
|
@@ -371,6 +393,54 @@ interface ModelProvider {
|
|
|
371
393
|
runTurn(args: ModelTurnArgs): Promise<ModelTurnResult>;
|
|
372
394
|
}
|
|
373
395
|
|
|
396
|
+
/**
|
|
397
|
+
* The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
|
|
398
|
+
*
|
|
399
|
+
* The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
|
|
400
|
+
* `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
|
|
401
|
+
* SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
|
|
402
|
+
* protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
|
|
403
|
+
* rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
|
|
404
|
+
* client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
|
|
405
|
+
*
|
|
406
|
+
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
407
|
+
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
408
|
+
*/
|
|
409
|
+
type AgentStreamEvent = {
|
|
410
|
+
kind: 'step-start';
|
|
411
|
+
} | {
|
|
412
|
+
kind: 'step-finish';
|
|
413
|
+
} | {
|
|
414
|
+
kind: 'text';
|
|
415
|
+
text: string;
|
|
416
|
+
} | {
|
|
417
|
+
kind: 'reasoning';
|
|
418
|
+
text: string;
|
|
419
|
+
} | {
|
|
420
|
+
kind: 'tool-input-start';
|
|
421
|
+
id: string;
|
|
422
|
+
name: string;
|
|
423
|
+
} | {
|
|
424
|
+
kind: 'tool-input-delta';
|
|
425
|
+
id: string;
|
|
426
|
+
delta: string;
|
|
427
|
+
} | {
|
|
428
|
+
kind: 'tool-input-available';
|
|
429
|
+
id: string;
|
|
430
|
+
name: string;
|
|
431
|
+
input: unknown;
|
|
432
|
+
} | {
|
|
433
|
+
kind: 'tool-output';
|
|
434
|
+
id: string;
|
|
435
|
+
output: unknown;
|
|
436
|
+
} | {
|
|
437
|
+
kind: 'tool-output-error';
|
|
438
|
+
id: string;
|
|
439
|
+
error: string;
|
|
440
|
+
};
|
|
441
|
+
/** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
|
|
442
|
+
declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
|
|
443
|
+
|
|
374
444
|
interface CreateThreadInput {
|
|
375
445
|
actor: Actor;
|
|
376
446
|
transient?: boolean;
|
|
@@ -384,6 +454,8 @@ interface AppendMessageInput {
|
|
|
384
454
|
agentName?: string;
|
|
385
455
|
toolCalls?: ToolCallRequest[];
|
|
386
456
|
toolResults?: ToolResult[];
|
|
457
|
+
/** Files the user attached to this message (image/PDF). Persisted verbatim. */
|
|
458
|
+
attachments?: MessageAttachment[];
|
|
387
459
|
followUps?: string[];
|
|
388
460
|
usage?: MessageUsage;
|
|
389
461
|
}
|
|
@@ -971,4 +1043,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
971
1043
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
972
1044
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
973
1045
|
|
|
974
|
-
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
|
1046
|
+
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageAttachment, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
package/dist/index.d.ts
CHANGED
|
@@ -107,12 +107,30 @@ interface Decision {
|
|
|
107
107
|
reason?: string;
|
|
108
108
|
}
|
|
109
109
|
type MessageRole = 'user' | 'assistant' | 'system';
|
|
110
|
+
/**
|
|
111
|
+
* A file a user attached to a message so a vision-capable model sees it natively (an image, a PDF).
|
|
112
|
+
* The lib stays provider-agnostic: it passes {@link MessageAttachment.url} straight through as the
|
|
113
|
+
* model's image/file part data — making that URL reachable by the provider (presigned S3, a proxy)
|
|
114
|
+
* is the consumer's job. The lib never fetches bytes or talks to a store.
|
|
115
|
+
*/
|
|
116
|
+
interface MessageAttachment {
|
|
117
|
+
/** Stable id of the stored media object in the consumer's media store. Provenance + replay key. */
|
|
118
|
+
mediaId: string;
|
|
119
|
+
/** A URL the model provider can fetch the bytes from at turn time. */
|
|
120
|
+
url: string;
|
|
121
|
+
/** MIME type — routes the part: `image/*` → image part, otherwise → file part. */
|
|
122
|
+
contentType: string;
|
|
123
|
+
/** Original filename, for display and the file part's filename. */
|
|
124
|
+
name: string;
|
|
125
|
+
}
|
|
110
126
|
/** A neutral chat message exchanged with the model. */
|
|
111
127
|
interface ModelMessage {
|
|
112
128
|
role: MessageRole;
|
|
113
129
|
content: string;
|
|
114
130
|
toolCalls?: ToolCallRequest[];
|
|
115
131
|
toolResults?: ToolResult[];
|
|
132
|
+
/** User-message attachments (image/PDF), rendered as native model content parts by the adapter. */
|
|
133
|
+
attachments?: MessageAttachment[];
|
|
116
134
|
}
|
|
117
135
|
interface PageContext {
|
|
118
136
|
kind?: string;
|
|
@@ -148,6 +166,8 @@ interface AgentRunInput {
|
|
|
148
166
|
actor: Actor;
|
|
149
167
|
/** The latest user message text. */
|
|
150
168
|
userText: string;
|
|
169
|
+
/** Files attached to the latest user message (image/PDF). Persisted with it and sent to the model. */
|
|
170
|
+
attachments?: MessageAttachment[];
|
|
151
171
|
pageContext?: PageContext;
|
|
152
172
|
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
153
173
|
day?: string;
|
|
@@ -218,6 +238,8 @@ interface StoredMessage {
|
|
|
218
238
|
agentName?: string;
|
|
219
239
|
toolCalls?: ToolCallRequest[];
|
|
220
240
|
toolResults?: ToolResult[];
|
|
241
|
+
/** Files the user attached to this message (image/PDF). Persisted with the message, replayed as-is. */
|
|
242
|
+
attachments?: MessageAttachment[];
|
|
221
243
|
followUps?: string[];
|
|
222
244
|
usage?: MessageUsage;
|
|
223
245
|
createdAt: string;
|
|
@@ -371,6 +393,54 @@ interface ModelProvider {
|
|
|
371
393
|
runTurn(args: ModelTurnArgs): Promise<ModelTurnResult>;
|
|
372
394
|
}
|
|
373
395
|
|
|
396
|
+
/**
|
|
397
|
+
* The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
|
|
398
|
+
*
|
|
399
|
+
* The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
|
|
400
|
+
* `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
|
|
401
|
+
* SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
|
|
402
|
+
* protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
|
|
403
|
+
* rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
|
|
404
|
+
* client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
|
|
405
|
+
*
|
|
406
|
+
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
407
|
+
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
408
|
+
*/
|
|
409
|
+
type AgentStreamEvent = {
|
|
410
|
+
kind: 'step-start';
|
|
411
|
+
} | {
|
|
412
|
+
kind: 'step-finish';
|
|
413
|
+
} | {
|
|
414
|
+
kind: 'text';
|
|
415
|
+
text: string;
|
|
416
|
+
} | {
|
|
417
|
+
kind: 'reasoning';
|
|
418
|
+
text: string;
|
|
419
|
+
} | {
|
|
420
|
+
kind: 'tool-input-start';
|
|
421
|
+
id: string;
|
|
422
|
+
name: string;
|
|
423
|
+
} | {
|
|
424
|
+
kind: 'tool-input-delta';
|
|
425
|
+
id: string;
|
|
426
|
+
delta: string;
|
|
427
|
+
} | {
|
|
428
|
+
kind: 'tool-input-available';
|
|
429
|
+
id: string;
|
|
430
|
+
name: string;
|
|
431
|
+
input: unknown;
|
|
432
|
+
} | {
|
|
433
|
+
kind: 'tool-output';
|
|
434
|
+
id: string;
|
|
435
|
+
output: unknown;
|
|
436
|
+
} | {
|
|
437
|
+
kind: 'tool-output-error';
|
|
438
|
+
id: string;
|
|
439
|
+
error: string;
|
|
440
|
+
};
|
|
441
|
+
/** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
|
|
442
|
+
declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
|
|
443
|
+
|
|
374
444
|
interface CreateThreadInput {
|
|
375
445
|
actor: Actor;
|
|
376
446
|
transient?: boolean;
|
|
@@ -384,6 +454,8 @@ interface AppendMessageInput {
|
|
|
384
454
|
agentName?: string;
|
|
385
455
|
toolCalls?: ToolCallRequest[];
|
|
386
456
|
toolResults?: ToolResult[];
|
|
457
|
+
/** Files the user attached to this message (image/PDF). Persisted verbatim. */
|
|
458
|
+
attachments?: MessageAttachment[];
|
|
387
459
|
followUps?: string[];
|
|
388
460
|
usage?: MessageUsage;
|
|
389
461
|
}
|
|
@@ -971,4 +1043,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
971
1043
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
972
1044
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
973
1045
|
|
|
974
|
-
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
|
1046
|
+
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageAttachment, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,14 @@ var AgentStreamError = class extends Error {
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
+
// src/stream-events.ts
|
|
37
|
+
var encoder = new TextEncoder();
|
|
38
|
+
function encodeStreamEvent(event) {
|
|
39
|
+
return encoder.encode(`${JSON.stringify(event)}
|
|
40
|
+
`);
|
|
41
|
+
}
|
|
42
|
+
__name(encodeStreamEvent, "encodeStreamEvent");
|
|
43
|
+
|
|
36
44
|
// src/spi/pricing-store.ts
|
|
37
45
|
async function seedModelPrices(store, prices) {
|
|
38
46
|
for (const price of prices) {
|
|
@@ -503,7 +511,10 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
503
511
|
await hooks.step("persist:user", () => deps.store.appendMessage({
|
|
504
512
|
threadId: input.threadId,
|
|
505
513
|
role: "user",
|
|
506
|
-
content: input.userText
|
|
514
|
+
content: input.userText,
|
|
515
|
+
...input.attachments !== void 0 ? {
|
|
516
|
+
attachments: input.attachments
|
|
517
|
+
} : {}
|
|
507
518
|
}));
|
|
508
519
|
}
|
|
509
520
|
const thread = await hooks.step("load:thread", () => deps.store.getThread(input.threadId));
|
|
@@ -515,6 +526,9 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
515
526
|
} : {},
|
|
516
527
|
...message.toolResults !== void 0 ? {
|
|
517
528
|
toolResults: message.toolResults
|
|
529
|
+
} : {},
|
|
530
|
+
...message.attachments !== void 0 ? {
|
|
531
|
+
attachments: message.attachments
|
|
518
532
|
} : {}
|
|
519
533
|
}));
|
|
520
534
|
const writer = await hooks.openSink();
|
|
@@ -549,6 +563,11 @@ ${buildContextBlock(passages)}`;
|
|
|
549
563
|
});
|
|
550
564
|
}
|
|
551
565
|
for (let i = 0; i < maxSteps; i += 1) {
|
|
566
|
+
await hooks.step(`stream:step-start:${i}`, async () => {
|
|
567
|
+
await writer.write(encodeStreamEvent({
|
|
568
|
+
kind: "step-start"
|
|
569
|
+
}));
|
|
570
|
+
});
|
|
552
571
|
const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
|
|
553
572
|
const turn = await hooks.step(`llm:${i}`, () => deps.model.runTurn({
|
|
554
573
|
system,
|
|
@@ -619,13 +638,14 @@ ${buildContextBlock(passages)}`;
|
|
|
619
638
|
followUps
|
|
620
639
|
} : {}
|
|
621
640
|
}));
|
|
622
|
-
|
|
641
|
+
const assistantMessage = {
|
|
623
642
|
role: "assistant",
|
|
624
643
|
content: turn.text,
|
|
625
644
|
...turn.toolCalls.length > 0 ? {
|
|
626
645
|
toolCalls: turn.toolCalls
|
|
627
646
|
} : {}
|
|
628
|
-
}
|
|
647
|
+
};
|
|
648
|
+
modelMessages.push(assistantMessage);
|
|
629
649
|
if (i === 0 && injectedPassages !== void 0) {
|
|
630
650
|
const passages = injectedPassages;
|
|
631
651
|
const toolCallId = `retrieve-${assistant.id}`;
|
|
@@ -650,6 +670,11 @@ ${buildContextBlock(passages)}`;
|
|
|
650
670
|
});
|
|
651
671
|
}
|
|
652
672
|
if (isFinalTurn) {
|
|
673
|
+
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
674
|
+
await writer.write(encodeStreamEvent({
|
|
675
|
+
kind: "step-finish"
|
|
676
|
+
}));
|
|
677
|
+
});
|
|
653
678
|
break;
|
|
654
679
|
}
|
|
655
680
|
const results = [];
|
|
@@ -809,10 +834,24 @@ ${buildContextBlock(passages)}`;
|
|
|
809
834
|
});
|
|
810
835
|
}
|
|
811
836
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
837
|
+
assistantMessage.toolResults = results;
|
|
838
|
+
await hooks.step(`stream:tool-outputs:${i}`, async () => {
|
|
839
|
+
for (const result of results) {
|
|
840
|
+
await writer.write(encodeStreamEvent(result.error !== void 0 ? {
|
|
841
|
+
kind: "tool-output-error",
|
|
842
|
+
id: result.id,
|
|
843
|
+
error: result.error
|
|
844
|
+
} : {
|
|
845
|
+
kind: "tool-output",
|
|
846
|
+
id: result.id,
|
|
847
|
+
output: result.output
|
|
848
|
+
}));
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
852
|
+
await writer.write(encodeStreamEvent({
|
|
853
|
+
kind: "step-finish"
|
|
854
|
+
}));
|
|
816
855
|
});
|
|
817
856
|
}
|
|
818
857
|
if (thread !== null && (thread.title === "" || thread.title === "New chat")) {
|
|
@@ -862,6 +901,7 @@ export {
|
|
|
862
901
|
bucketByThread,
|
|
863
902
|
bucketUsageTrend,
|
|
864
903
|
dayBoundsUtc,
|
|
904
|
+
encodeStreamEvent,
|
|
865
905
|
estimateCost,
|
|
866
906
|
filterToolsByAllowList,
|
|
867
907
|
filterToolsByRole,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tokens.ts","../src/spi/token-stream-sink.ts","../src/spi/pricing-store.ts","../src/governance/compute.ts","../src/tool-filters.ts","../src/agent-registry.ts","../src/tool-registry.ts","../src/diagnostics.ts","../src/agent-loop.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 * 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 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 { emit } 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/** Declaration-merge so `emit('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 };\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","import {\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n} from './diagnostics.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider } from './spi/model-provider.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 type { ToolRegistry } from './tool-registry.js';\nimport type {\n AgentRunInput,\n Decision,\n MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\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\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.step(name, fn).\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\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. */\nfunction withTimeout<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 * 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 }),\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 }));\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 // 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 passages = await hooks.step('retrieve', () =>\n retriever.retrieve(input.userText, { topK: deps.retrievalTopK ?? 5 }),\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 // 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 const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n\n const turn = await hooks.step(`llm:${i}`, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n );\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n modelId: turn.modelId ?? deps.modelId ?? 'unknown',\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 const generated = await hooks.step(`followups:${i}`, () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\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,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\n ...(followUps !== undefined ? { followUps } : {}),\n }),\n );\n modelMessages.push({\n role: 'assistant',\n content: turn.text,\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\n });\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 break;\n }\n\n const results: ToolResult[] = [];\n for (const call of turn.toolCalls) {\n const spec = deps.registry.spec(call.name);\n const toolType = spec?.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 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 if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\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 const invocation = hooks.step(`tool:${call.id}`, () =>\n deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n );\n const output =\n deps.toolTimeoutMs !== undefined\n ? await withTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\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: input.actor.id } : {}),\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 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 modelMessages.push({ role: 'user', content: '', toolResults: results });\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 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"],"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","AgentStreamError","Error","code","error","message","name","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","emit","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","buildContextBlock","passages","items","map","passage","index","label","source","undefined","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","withTimeout","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","usage","modelId","runAgentLoop","hooks","maxSteps","quota","state","step","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","thread","modelMessages","message","toolCalls","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","runId","injectedPassages","retriever","retrieve","topK","retrievalTopK","publishAgentRetrieved","query","i","registry","definitionsFor","rolesPolicy","toolAllowList","recordUsage","actorRef","purpose","costUsd","bump","inputTokens","outputTokens","publishAgentMessage","textLength","isFinalTurn","followUpsCount","generated","assistant","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","call","spec","kind","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","decision","awaitApproval","approved","reason","rejected","publishAgentToolCall","startedAt","Date","now","invocation","invoke","toolTimeoutMs","executionMs","executedByRef","durationMs","String","title","setTitle","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/diagnostics.ts","../src/agent-loop.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 * 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 */\nexport type AgentStreamEvent =\n | { kind: 'step-start' }\n | { kind: 'step-finish' }\n | { kind: 'text'; text: string }\n | { kind: 'reasoning'; text: string }\n | { kind: 'tool-input-start'; id: string; name: string }\n | { kind: 'tool-input-delta'; id: string; delta: string }\n | { kind: 'tool-input-available'; id: string; name: string; input: unknown }\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 { emit } 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/** Declaration-merge so `emit('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 };\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","import {\n publishAgentDelegated,\n publishAgentMessage,\n publishAgentQuotaExceeded,\n publishAgentRetrieved,\n publishAgentRunFinished,\n publishAgentRunStarted,\n publishAgentToolCall,\n} from './diagnostics.js';\nimport type { AgentStore } from './spi/agent-store.js';\nimport type { ModelProvider } from './spi/model-provider.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 MessageUsage,\n ModelMessage,\n PromptBuilder,\n PromptContext,\n PromptContributor,\n ToolCallRequest,\n ToolResult,\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\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.step(name, fn).\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\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. */\nfunction withTimeout<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 * 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 // 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 passages = await hooks.step('retrieve', () =>\n retriever.retrieve(input.userText, { topK: deps.retrievalTopK ?? 5 }),\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 // 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 const tools = await deps.registry.definitionsFor(\n input.actor,\n deps.rolesPolicy,\n deps.toolAllowList,\n );\n\n const turn = await hooks.step(`llm:${i}`, () =>\n deps.model.runTurn({ system, messages: modelMessages, tools, sink: writer }),\n );\n\n await hooks.step(`persist:usage:${i}`, () =>\n deps.store.recordUsage({\n threadId: input.threadId,\n actorRef: input.actor.id,\n // provider-reported model wins over the configured fallback, so cost can't misattribute\n modelId: turn.modelId ?? deps.modelId ?? 'unknown',\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 const generated = await hooks.step(`followups:${i}`, () =>\n generateFollowUps(\n deps.model,\n [...modelMessages, { role: 'assistant', content: turn.text }],\n count,\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,\n ...(input.agentName !== undefined ? { agentName: input.agentName } : {}),\n ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\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 ...(turn.toolCalls.length > 0 ? { toolCalls: turn.toolCalls } : {}),\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' }));\n });\n break;\n }\n\n const results: ToolResult[] = [];\n for (const call of turn.toolCalls) {\n const spec = deps.registry.spec(call.name);\n const toolType = spec?.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 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 if (!decision.approved) {\n await hooks.step(`persist:toolreject:${call.id}`, () =>\n deps.store.updateToolCall({\n toolCallId: call.id,\n status: 'rejected',\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 const invocation = hooks.step(`tool:${call.id}`, () =>\n deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy),\n );\n const output =\n deps.toolTimeoutMs !== undefined\n ? await withTimeout(invocation, deps.toolTimeoutMs, call.name)\n : await invocation;\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: input.actor.id } : {}),\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 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' }));\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 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"],"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","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","emit","publishAgentRunStarted","payload","emit","publishAgentMessage","publishAgentToolCall","publishAgentQuotaExceeded","publishAgentRunFinished","publishAgentRunFailed","publishAgentDelegated","publishAgentRetrieved","buildContextBlock","passages","items","map","passage","index","label","source","undefined","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","withTimeout","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","usage","modelId","runAgentLoop","hooks","maxSteps","quota","state","step","check","id","day","withinLimit","publishAgentQuotaExceeded","actorId","usedTokens","limitTokens","regenerate","existing","store","getThread","threadId","lastUserIndex","role","firstDropped","truncateFrom","appendMessage","content","attachments","thread","modelMessages","message","toolCalls","toolResults","writer","openSink","lastText","steps","totalInput","totalOutput","publishAgentRunStarted","runId","injectedPassages","retriever","retrieve","topK","retrievalTopK","publishAgentRetrieved","query","i","encodeStreamEvent","kind","registry","definitionsFor","rolesPolicy","toolAllowList","recordUsage","actorRef","purpose","costUsd","bump","inputTokens","outputTokens","publishAgentMessage","textLength","isFinalTurn","followUpsCount","generated","assistant","assistantMessage","toolCallId","recordToolCall","messageId","toolType","status","updateToolCall","output","results","call","spec","requestId","host","targetAgent","overDepth","delegationDepth","publishAgentDelegated","toAgent","fromAgent","sub","runAgent","decision","awaitApproval","approved","reason","rejected","publishAgentToolCall","startedAt","Date","now","invocation","invoke","toolTimeoutMs","executionMs","executedByRef","durationMs","String","result","title","setTitle","publishAgentRunFinished"]}
|