@dudousxd/nestjs-agent-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +28 -0
- package/dist/index.cjs +813 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +848 -0
- package/dist/index.d.ts +848 -0
- package/dist/index.js +753 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,848 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
|
|
3
|
+
/** Who is driving the turn. Roles + tenant come from the host app (nestjs-context/authz). */
|
|
4
|
+
interface Actor {
|
|
5
|
+
id: string;
|
|
6
|
+
/** The caller's roles. Tool authorization is a set intersection against a tool's `roles`. */
|
|
7
|
+
roles?: string[];
|
|
8
|
+
tenantRef?: string;
|
|
9
|
+
}
|
|
10
|
+
type ToolKind = 'read' | 'action' | 'agent';
|
|
11
|
+
/**
|
|
12
|
+
* Declared shape of a tool.
|
|
13
|
+
* - `read` auto-executes.
|
|
14
|
+
* - `action` never auto-executes — requires HITL approval.
|
|
15
|
+
* - `agent` delegates to another named agent (durable: a child workflow; inline: a nested loop),
|
|
16
|
+
* handled at the loop level — NOT via a handler. Carries `targetAgent`.
|
|
17
|
+
*/
|
|
18
|
+
interface ToolSpec {
|
|
19
|
+
name: string;
|
|
20
|
+
kind: ToolKind;
|
|
21
|
+
description: string;
|
|
22
|
+
/**
|
|
23
|
+
* Input schema as a [Standard Schema](https://standardschema.dev) — validation-agnostic, so
|
|
24
|
+
* Zod, Valibot, or ArkType all work. The loop validates input via `~standard.validate` before
|
|
25
|
+
* running the handler, and providers convert it to the model's tool-parameter JSON schema.
|
|
26
|
+
*/
|
|
27
|
+
inputSchema: StandardSchemaV1;
|
|
28
|
+
/** For `kind: 'agent'` — the name of the agent to delegate to. */
|
|
29
|
+
targetAgent?: string;
|
|
30
|
+
/** Roles allowed to invoke. Undefined → defaults applied by RolesPolicy (e.g. ADMIN-only). */
|
|
31
|
+
roles?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* An authorization ability name (e.g. 'cache.purge'). Consumed by an ability-aware RolesPolicy
|
|
34
|
+
* such as the `@dudousxd/nestjs-agent-authz` Gate adapter. Apps that don't use authz ignore it
|
|
35
|
+
* and rely on `roles` instead — both live on the same SPI, so neither is required.
|
|
36
|
+
*/
|
|
37
|
+
ability?: string;
|
|
38
|
+
}
|
|
39
|
+
/** What the model is told a tool looks like (no handler, no host types). */
|
|
40
|
+
interface ToolDefinition {
|
|
41
|
+
name: string;
|
|
42
|
+
kind: ToolKind;
|
|
43
|
+
description: string;
|
|
44
|
+
inputSchema: StandardSchemaV1;
|
|
45
|
+
}
|
|
46
|
+
/** A tool call the model asked for during a turn. */
|
|
47
|
+
interface ToolCallRequest {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
input: unknown;
|
|
51
|
+
}
|
|
52
|
+
/** Result of running a tool. */
|
|
53
|
+
interface ToolResult {
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
output: unknown;
|
|
57
|
+
error?: string;
|
|
58
|
+
}
|
|
59
|
+
interface MessageUsage {
|
|
60
|
+
/**
|
|
61
|
+
* Total input (prompt) tokens for the turn — the whole input side, cached and uncached alike.
|
|
62
|
+
* `cacheWriteTokens` + `cacheReadTokens` are subsets of this count, not additions to it, so
|
|
63
|
+
* token totals and quota never change when a breakdown is present.
|
|
64
|
+
*/
|
|
65
|
+
inputTokens: number;
|
|
66
|
+
/** Total output (completion) tokens for the turn; `reasoningTokens` is a subset of this. */
|
|
67
|
+
outputTokens: number;
|
|
68
|
+
/**
|
|
69
|
+
* How many of `inputTokens` were written to the prompt cache this turn (billed at a premium,
|
|
70
|
+
* ~1.25× base input). Undefined when the provider doesn't report caching. Refines the cost
|
|
71
|
+
* estimate only — priced by the pricing row's cache-write rate (falling back to the input rate).
|
|
72
|
+
*/
|
|
73
|
+
cacheWriteTokens?: number;
|
|
74
|
+
/**
|
|
75
|
+
* How many of `inputTokens` were served from the prompt cache this turn (billed at a discount,
|
|
76
|
+
* ~0.1× base input). Undefined when the provider doesn't report caching.
|
|
77
|
+
*/
|
|
78
|
+
cacheReadTokens?: number;
|
|
79
|
+
/**
|
|
80
|
+
* How many of `outputTokens` the model spent on reasoning/thinking. Observability only — reasoning
|
|
81
|
+
* tokens are billed at the output rate, so they don't change the cost estimate. Undefined for
|
|
82
|
+
* non-reasoning models or providers that don't report it.
|
|
83
|
+
*/
|
|
84
|
+
reasoningTokens?: number;
|
|
85
|
+
}
|
|
86
|
+
type UsagePurpose = 'chat' | 'follow_ups';
|
|
87
|
+
interface QuotaState {
|
|
88
|
+
usedTokens: number;
|
|
89
|
+
limitTokens: number;
|
|
90
|
+
withinLimit: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** A human decision on a pending action tool call. */
|
|
93
|
+
interface Decision {
|
|
94
|
+
approved: boolean;
|
|
95
|
+
reason?: string;
|
|
96
|
+
}
|
|
97
|
+
type MessageRole = 'user' | 'assistant' | 'system';
|
|
98
|
+
/** A neutral chat message exchanged with the model. */
|
|
99
|
+
interface ModelMessage {
|
|
100
|
+
role: MessageRole;
|
|
101
|
+
content: string;
|
|
102
|
+
toolCalls?: ToolCallRequest[];
|
|
103
|
+
toolResults?: ToolResult[];
|
|
104
|
+
}
|
|
105
|
+
interface PageContext {
|
|
106
|
+
kind?: string;
|
|
107
|
+
[key: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Inputs a {@link PromptBuilder} may use to compose the effective system prompt for a turn.
|
|
111
|
+
* `basePrompt` is the agent's own (already-resolved) base prompt, so a persona builder can wrap
|
|
112
|
+
* or extend it rather than replace it.
|
|
113
|
+
*/
|
|
114
|
+
interface PromptContext {
|
|
115
|
+
actor: Actor;
|
|
116
|
+
persona?: Persona;
|
|
117
|
+
pageContext?: PageContext;
|
|
118
|
+
basePrompt: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* A dynamic system prompt. Return a string (optionally async) built from the turn's context —
|
|
122
|
+
* e.g. injecting the actor, the current page, or a data-shape description. The loop resolves it
|
|
123
|
+
* once per turn from stable inputs (actor/persona/pageContext), so it stays replay-safe.
|
|
124
|
+
*/
|
|
125
|
+
type PromptBuilder = (ctx: PromptContext) => string | Promise<string>;
|
|
126
|
+
interface Persona {
|
|
127
|
+
id: string;
|
|
128
|
+
label: string;
|
|
129
|
+
/** A flat prompt, or a {@link PromptBuilder} composed per request from {@link PromptContext}. */
|
|
130
|
+
systemPrompt: string | PromptBuilder;
|
|
131
|
+
/** If set, only these tool names are offered (after role filtering). */
|
|
132
|
+
allowedTools?: string[];
|
|
133
|
+
}
|
|
134
|
+
/** Everything needed to run one agent turn. */
|
|
135
|
+
interface AgentRunInput {
|
|
136
|
+
threadId: string;
|
|
137
|
+
actor: Actor;
|
|
138
|
+
/** The latest user message text. */
|
|
139
|
+
userText: string;
|
|
140
|
+
persona?: Persona;
|
|
141
|
+
pageContext?: PageContext;
|
|
142
|
+
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
143
|
+
day?: string;
|
|
144
|
+
/** Which named agent runs this turn. Omitted → the default/single agent. */
|
|
145
|
+
agentName?: string;
|
|
146
|
+
/**
|
|
147
|
+
* How many agent→agent delegations deep this run already is (0 for a top-level turn). The runner
|
|
148
|
+
* increments it for each child run; the loop refuses to delegate past {@link MAX_DELEGATION_DEPTH}.
|
|
149
|
+
*/
|
|
150
|
+
delegationDepth?: number;
|
|
151
|
+
/**
|
|
152
|
+
* When set, this run streams into ANOTHER run's sink instead of its own. A sub-agent run carries
|
|
153
|
+
* its top-level ancestor's runId here so its tokens (and its pending action-tool frames) land in
|
|
154
|
+
* the live stream the human is already watching — the only way a human can see, and therefore
|
|
155
|
+
* approve, a sub-agent's HITL action. Propagated unchanged down the delegation chain.
|
|
156
|
+
*/
|
|
157
|
+
sinkRunId?: string;
|
|
158
|
+
/**
|
|
159
|
+
* Re-run the last exchange instead of adding a new message: the loop truncates everything after
|
|
160
|
+
* the thread's last user message and re-answers it (no `userText` is appended). Used by a
|
|
161
|
+
* "regenerate" button. `userText` is ignored when set.
|
|
162
|
+
*/
|
|
163
|
+
regenerate?: boolean;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* A named agent: its prompt, the tools it may use, and its personas. Multiple definitions are
|
|
167
|
+
* registered via `AgentModule.forFeature([...])`; an orchestrator delegates to others through
|
|
168
|
+
* `ctx.runAgent(name, task)`. Model/store/sink/governance are shared from the module unless
|
|
169
|
+
* overridden here.
|
|
170
|
+
*/
|
|
171
|
+
interface AgentDefinition {
|
|
172
|
+
name: string;
|
|
173
|
+
/** Base prompt for this agent. A flat string, or a {@link PromptBuilder} resolved per turn. */
|
|
174
|
+
systemPrompt?: string | PromptBuilder;
|
|
175
|
+
/** Allow-list of tool names this agent may use (subset of all registered tools). */
|
|
176
|
+
tools?: string[];
|
|
177
|
+
/** Names of other agents this agent may delegate to (auto-registered as `agent`-kind tools). */
|
|
178
|
+
delegatesTo?: string[];
|
|
179
|
+
personas?: Persona[];
|
|
180
|
+
defaultPersona?: string;
|
|
181
|
+
modelId?: string;
|
|
182
|
+
maxSteps?: number;
|
|
183
|
+
}
|
|
184
|
+
interface ThreadSummary {
|
|
185
|
+
id: string;
|
|
186
|
+
title: string;
|
|
187
|
+
persona: string;
|
|
188
|
+
transient: boolean;
|
|
189
|
+
createdAt: string;
|
|
190
|
+
updatedAt: string;
|
|
191
|
+
lastMessagePreview?: string;
|
|
192
|
+
}
|
|
193
|
+
interface StoredMessage {
|
|
194
|
+
id: string;
|
|
195
|
+
role: MessageRole;
|
|
196
|
+
content: string;
|
|
197
|
+
toolCalls?: ToolCallRequest[];
|
|
198
|
+
toolResults?: ToolResult[];
|
|
199
|
+
followUps?: string[];
|
|
200
|
+
usage?: MessageUsage;
|
|
201
|
+
createdAt: string;
|
|
202
|
+
}
|
|
203
|
+
interface ThreadDetail extends ThreadSummary {
|
|
204
|
+
messages: StoredMessage[];
|
|
205
|
+
activeStreamId?: string;
|
|
206
|
+
}
|
|
207
|
+
type ToolCallStatus = 'auto_executed' | 'pending_approval' | 'executed' | 'rejected' | 'failed';
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Public, cross-lib-discoverable DI tokens.
|
|
211
|
+
*
|
|
212
|
+
* These use `Symbol.for(...)` (the global symbol registry) on purpose: pnpm peer
|
|
213
|
+
* multiplexing + dual ESM/CJS can load `core` more than once, and a plain `Symbol()`
|
|
214
|
+
* would mint a distinct token per copy and break DI across package boundaries. A
|
|
215
|
+
* registered symbol collapses every copy onto the same token, and lets a sibling lib
|
|
216
|
+
* resolve our injectables by name without importing our internals.
|
|
217
|
+
*
|
|
218
|
+
* Naming convention (ecosystem-wide): `@dudousxd/nestjs-<lib>:<name>`.
|
|
219
|
+
*/
|
|
220
|
+
declare const AGENT_OPTIONS: unique symbol;
|
|
221
|
+
declare const AGENT_STORE: unique symbol;
|
|
222
|
+
declare const AGENT_RUNNER: unique symbol;
|
|
223
|
+
/**
|
|
224
|
+
* The durable runner, provided ONLY by `AgentDurableModule`. When `durable: true`, the module
|
|
225
|
+
* binds `AGENT_RUNNER` to this via an optional injection, so a missing `AgentDurableModule`
|
|
226
|
+
* fails with a clear error instead of a cryptic unresolved-dependency one.
|
|
227
|
+
*/
|
|
228
|
+
declare const AGENT_DURABLE_RUNNER: unique symbol;
|
|
229
|
+
declare const AGENT_SINK: unique symbol;
|
|
230
|
+
declare const AGENT_MODEL: unique symbol;
|
|
231
|
+
declare const AGENT_ROLES_POLICY: unique symbol;
|
|
232
|
+
declare const AGENT_QUOTA_STORE: unique symbol;
|
|
233
|
+
declare const AGENT_TOOL_REGISTRY: unique symbol;
|
|
234
|
+
declare const AGENT_REGISTRY: unique symbol;
|
|
235
|
+
declare const AGENT_ACTOR_RESOLVER: unique symbol;
|
|
236
|
+
/** The governance read-model (usage/spend/threads), consumed by the dashboard + telescope surfaces. */
|
|
237
|
+
declare const AGENT_GOVERNANCE_QUERIES: unique symbol;
|
|
238
|
+
/** The pricing WRITE side (`AgentPricingStore`) — seeds/updates the per-model rates cost is priced against. */
|
|
239
|
+
declare const AGENT_PRICING_STORE: unique symbol;
|
|
240
|
+
/** The RAG retrieval seam (`Retriever`) — vector/keyword search behind the agentic tool or inject mode. */
|
|
241
|
+
declare const AGENT_RETRIEVER: unique symbol;
|
|
242
|
+
/** The embedding provider (`EmbeddingProvider`) — text→vector for retrieval + ingestion. */
|
|
243
|
+
declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
244
|
+
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
248
|
+
* on {@link AiToolCtx.actor} — read `ctx.actor.id` / `ctx.actor.tenantRef` (single source of truth;
|
|
249
|
+
* no denormalized copies).
|
|
250
|
+
*/
|
|
251
|
+
interface AiToolCtx {
|
|
252
|
+
actor: Actor;
|
|
253
|
+
threadId: string;
|
|
254
|
+
runId: string;
|
|
255
|
+
requestId: string;
|
|
256
|
+
persona?: Persona;
|
|
257
|
+
pageContext?: PageContext;
|
|
258
|
+
/** Optional host handle (e.g. an ORM EntityManager) the app threads through options. */
|
|
259
|
+
host?: unknown;
|
|
260
|
+
}
|
|
261
|
+
/** A tool implementation. `I` is the parsed (Zod-validated) input. */
|
|
262
|
+
interface ToolHandler<I = unknown> {
|
|
263
|
+
execute(input: I, ctx: AiToolCtx): Promise<unknown>;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* The "data plane": live token transport, decoupled from the durable control plane.
|
|
268
|
+
*
|
|
269
|
+
* The model turn writes deltas to a `SinkWriter` keyed by runId; the HTTP layer
|
|
270
|
+
* `subscribe`s by runId and pipes the chunks to the browser as SSE. A late subscriber
|
|
271
|
+
* (reconnect/resume) replays buffered chunks first, then follows live — which is what
|
|
272
|
+
* makes streaming survive a dropped connection or a pod restart.
|
|
273
|
+
*/
|
|
274
|
+
interface SinkWriter {
|
|
275
|
+
write(chunk: Uint8Array): void | Promise<void>;
|
|
276
|
+
/** Mark the run's stream finished (no more chunks). */
|
|
277
|
+
end(): void | Promise<void>;
|
|
278
|
+
/**
|
|
279
|
+
* Terminate the run's stream with an error instead of a normal end. Subscribers replay any
|
|
280
|
+
* buffered chunks first, then throw an {@link AgentStreamError} carrying this `code`/`message`
|
|
281
|
+
* — so the transport can surface a typed failure frame instead of leaking it as assistant text.
|
|
282
|
+
*/
|
|
283
|
+
fail(error: StreamError): void | Promise<void>;
|
|
284
|
+
}
|
|
285
|
+
/** A machine-readable stream failure. `code` is a stable slug; `message` is human-facing. */
|
|
286
|
+
interface StreamError {
|
|
287
|
+
code: string;
|
|
288
|
+
message: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Thrown out of {@link TokenStreamSink.subscribe} when a run ended via {@link SinkWriter.fail}.
|
|
292
|
+
* Carries the structured {@link StreamError} so the HTTP layer can emit an `event: error` frame.
|
|
293
|
+
*/
|
|
294
|
+
declare class AgentStreamError extends Error {
|
|
295
|
+
readonly code: string;
|
|
296
|
+
constructor(error: StreamError);
|
|
297
|
+
}
|
|
298
|
+
interface TokenStreamSink {
|
|
299
|
+
/** Open (or reopen) the writer for a run. */
|
|
300
|
+
open(runId: string): SinkWriter | Promise<SinkWriter>;
|
|
301
|
+
/**
|
|
302
|
+
* Replay buffered chunks for the run, then yield live ones until `end()`. Throws
|
|
303
|
+
* {@link AgentStreamError} if the run was terminated with {@link SinkWriter.fail}.
|
|
304
|
+
*/
|
|
305
|
+
subscribe(runId: string): AsyncIterable<Uint8Array>;
|
|
306
|
+
/** Drop any buffer/resources for the run. */
|
|
307
|
+
close(runId: string): void | Promise<void>;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
interface ModelTurnArgs {
|
|
311
|
+
system: string;
|
|
312
|
+
messages: ModelMessage[];
|
|
313
|
+
tools: ToolDefinition[];
|
|
314
|
+
/** The model writes streamed text deltas here as it generates them. */
|
|
315
|
+
sink: SinkWriter;
|
|
316
|
+
abortSignal?: AbortSignal;
|
|
317
|
+
}
|
|
318
|
+
/** The outcome of ONE assistant turn. The loop — not the model — drives tool execution. */
|
|
319
|
+
interface ModelTurnResult {
|
|
320
|
+
text: string;
|
|
321
|
+
toolCalls: ToolCallRequest[];
|
|
322
|
+
usage: MessageUsage;
|
|
323
|
+
/**
|
|
324
|
+
* The model actually used this turn (e.g. `anthropic.claude-...`), recorded with usage for
|
|
325
|
+
* cost accounting. When set it wins over the module's configured `modelId`, so the accounting
|
|
326
|
+
* label can't silently drift from the runtime. Omit if the provider can't report one.
|
|
327
|
+
*/
|
|
328
|
+
modelId?: string;
|
|
329
|
+
/**
|
|
330
|
+
* The ACTUAL USD cost of this turn, when the provider knows it — a gateway (Vercel AI Gateway
|
|
331
|
+
* `providerMetadata.gateway.cost`, OpenRouter `total_cost`) reports real spend; a direct provider
|
|
332
|
+
* (Anthropic/OpenAI/Bedrock) reports only tokens and leaves this undefined. When set, the
|
|
333
|
+
* governance read-model uses it verbatim; otherwise it estimates from tokens × the pricing table.
|
|
334
|
+
*/
|
|
335
|
+
costUsd?: number;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Thin wrapper over the actual LLM. The concrete impl (e.g. Vercel AI SDK `streamText`
|
|
339
|
+
* over Bedrock/Anthropic) lives in the host app or an adapter; core stays provider-free.
|
|
340
|
+
*
|
|
341
|
+
* Contract: `runTurn` performs exactly one model turn, streaming deltas to `args.sink`,
|
|
342
|
+
* and returns the assembled text + requested tool calls + usage. It MUST NOT execute
|
|
343
|
+
* tools — the agent loop runs each as a (durable) step for replay-safety.
|
|
344
|
+
*/
|
|
345
|
+
interface ModelProvider {
|
|
346
|
+
runTurn(args: ModelTurnArgs): Promise<ModelTurnResult>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
interface CreateThreadInput {
|
|
350
|
+
actor: Actor;
|
|
351
|
+
persona: string;
|
|
352
|
+
transient?: boolean;
|
|
353
|
+
title?: string;
|
|
354
|
+
}
|
|
355
|
+
interface AppendMessageInput {
|
|
356
|
+
threadId: string;
|
|
357
|
+
role: StoredMessage['role'];
|
|
358
|
+
content: string;
|
|
359
|
+
persona?: string;
|
|
360
|
+
toolCalls?: ToolCallRequest[];
|
|
361
|
+
toolResults?: ToolResult[];
|
|
362
|
+
followUps?: string[];
|
|
363
|
+
usage?: MessageUsage;
|
|
364
|
+
}
|
|
365
|
+
interface RecordToolCallInput {
|
|
366
|
+
toolCallId: string;
|
|
367
|
+
messageId: string;
|
|
368
|
+
toolName: string;
|
|
369
|
+
toolType: 'read' | 'action';
|
|
370
|
+
input: unknown;
|
|
371
|
+
status: ToolCallStatus;
|
|
372
|
+
}
|
|
373
|
+
interface UpdateToolCallInput {
|
|
374
|
+
toolCallId: string;
|
|
375
|
+
status: ToolCallStatus;
|
|
376
|
+
output?: unknown;
|
|
377
|
+
error?: string;
|
|
378
|
+
executionMs?: number;
|
|
379
|
+
executedByRef?: string;
|
|
380
|
+
}
|
|
381
|
+
interface RecordUsageInput {
|
|
382
|
+
threadId: string;
|
|
383
|
+
actorRef: string;
|
|
384
|
+
messageId?: string;
|
|
385
|
+
modelId: string;
|
|
386
|
+
purpose: UsagePurpose;
|
|
387
|
+
usage: MessageUsage;
|
|
388
|
+
/** Provider-reported actual USD cost for this turn, when known (gateways report it). */
|
|
389
|
+
costUsd?: number;
|
|
390
|
+
}
|
|
391
|
+
/** ORM-agnostic persistence. Refs are string ids; adapters may add real relations. */
|
|
392
|
+
interface AgentStore {
|
|
393
|
+
createThread(input: CreateThreadInput): Promise<ThreadSummary>;
|
|
394
|
+
getThread(threadId: string): Promise<ThreadDetail | null>;
|
|
395
|
+
listThreads(actorRef: string, limit?: number): Promise<ThreadSummary[]>;
|
|
396
|
+
softDeleteThread(threadId: string): Promise<void>;
|
|
397
|
+
forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary>;
|
|
398
|
+
setTitle(threadId: string, title: string): Promise<void>;
|
|
399
|
+
setActiveStream(threadId: string, runId: string | null): Promise<void>;
|
|
400
|
+
/**
|
|
401
|
+
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
402
|
+
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
403
|
+
* resolved caller before acting, so one actor can never read or mutate another's thread.
|
|
404
|
+
*/
|
|
405
|
+
ownerOfThread(threadId: string): Promise<string | null>;
|
|
406
|
+
/**
|
|
407
|
+
* The `actorRef` that owns the thread a tool call belongs to, or `null` if the call is unknown.
|
|
408
|
+
* The authorization seam for HITL approve / reject: the caller must own the run they approve.
|
|
409
|
+
*/
|
|
410
|
+
ownerOfToolCall(toolCallId: string): Promise<string | null>;
|
|
411
|
+
/**
|
|
412
|
+
* The runId currently streaming the thread a tool call belongs to (its thread's `activeStreamId`),
|
|
413
|
+
* or `null` if the call or its active run is unknown. HITL approve / reject route the decision to
|
|
414
|
+
* THIS run, derived server-side from the tool call alone — so a decision reaches the exact run
|
|
415
|
+
* awaiting it, including a sub-agent's own child run, which the client never sees and could not
|
|
416
|
+
* name. No client-supplied runId is trusted (or needed).
|
|
417
|
+
*/
|
|
418
|
+
runForToolCall(toolCallId: string): Promise<string | null>;
|
|
419
|
+
/**
|
|
420
|
+
* The `actorRef` that owns the thread currently streaming `runId` (its `activeStreamId`), or
|
|
421
|
+
* `null` if no thread is streaming it. The authorization seam for `cancel`: the caller must own
|
|
422
|
+
* the run they abort. Resolvable during the live window (a run cancel only matters while active).
|
|
423
|
+
*/
|
|
424
|
+
ownerOfActiveStream(runId: string): Promise<string | null>;
|
|
425
|
+
appendMessage(input: AppendMessageInput): Promise<StoredMessage>;
|
|
426
|
+
truncateFrom(threadId: string, messageId: string): Promise<void>;
|
|
427
|
+
recordToolCall(input: RecordToolCallInput): Promise<void>;
|
|
428
|
+
updateToolCall(input: UpdateToolCallInput): Promise<void>;
|
|
429
|
+
recordUsage(input: RecordUsageInput): Promise<void>;
|
|
430
|
+
quotaToday(actorRef: string, day: string): Promise<{
|
|
431
|
+
usedTokens: number;
|
|
432
|
+
}>;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Decides whether an actor may invoke a tool. The default impl checks the actor's role
|
|
437
|
+
* against `spec.roles` (defaulting to an ADMIN-only set). Apps can plug `nestjs-authz`
|
|
438
|
+
* or any custom gate here.
|
|
439
|
+
*/
|
|
440
|
+
interface RolesPolicy {
|
|
441
|
+
/** May return a promise — an authz Gate (`gate.forUser(actor).allows(...)`) is async. */
|
|
442
|
+
can(actor: Actor, tool: ToolSpec): boolean | Promise<boolean>;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Per-actor/day token budget. `check` reports the day's usage against the limit before a turn;
|
|
447
|
+
* `bump` accounts a turn's tokens after it. Two impls ship: `InMemoryQuotaStore` (testing/offline)
|
|
448
|
+
* and the production `LedgerQuotaStore` (nestjs) which reads the persisted usage ledger — set
|
|
449
|
+
* `AgentModule.forRoot({ quotaLimitTokens })` to bind it, or supply your own for a bespoke budget.
|
|
450
|
+
*/
|
|
451
|
+
interface QuotaStore {
|
|
452
|
+
check(actorRef: string, day: string): Promise<QuotaState>;
|
|
453
|
+
/** Account a turn's tokens. A no-op for ledger-backed stores, which read `recordUsage` directly. */
|
|
454
|
+
bump(actorRef: string, day: string, tokens: number): Promise<void>;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* The WRITE side of the pricing table the {@link import('./governance-queries.js').AgentGovernanceQueries}
|
|
459
|
+
* read-model prices usage against. Cost is $0 for an unpriced model, so an app seeds its models'
|
|
460
|
+
* per-1M rates once (and re-`upsert`s when a provider changes prices). A store adapter implements
|
|
461
|
+
* this; consumers inject via `AGENT_PRICING_STORE`. Use `seedModelPrices` for a one-shot batch.
|
|
462
|
+
*/
|
|
463
|
+
/** A per-1M-token price for one model. Cache rates fall back to the input rate when omitted. */
|
|
464
|
+
interface ModelPriceInput {
|
|
465
|
+
modelId: string;
|
|
466
|
+
inputPricePer1m: number;
|
|
467
|
+
outputPricePer1m: number;
|
|
468
|
+
/** Per-1M price for cache-write (prompt-cache) input tokens. Omit → priced at the input rate. */
|
|
469
|
+
cacheWritePricePer1m?: number;
|
|
470
|
+
/** Per-1M price for cache-read (prompt-cache) input tokens. Omit → priced at the input rate. */
|
|
471
|
+
cacheReadPricePer1m?: number;
|
|
472
|
+
}
|
|
473
|
+
/** A current price row as read back, with the timestamp it took effect. */
|
|
474
|
+
interface CurrentModelPrice extends ModelPriceInput {
|
|
475
|
+
effectiveFrom: string;
|
|
476
|
+
}
|
|
477
|
+
interface AgentPricingStore {
|
|
478
|
+
/**
|
|
479
|
+
* Set the current price for a model. Atomic supersede: the model's prior `isCurrent` row (if any)
|
|
480
|
+
* is retired and this one is inserted as current, effective now — so the read-model always joins
|
|
481
|
+
* to exactly one live price per model, with no window where two rows race for `isCurrent`.
|
|
482
|
+
*/
|
|
483
|
+
upsertModelPrice(input: ModelPriceInput): Promise<void>;
|
|
484
|
+
/** The current price row per model (`isCurrent`), for a pricing admin view. */
|
|
485
|
+
listCurrentPrices(): Promise<CurrentModelPrice[]>;
|
|
486
|
+
}
|
|
487
|
+
/** Seed (or refresh) a batch of model prices — one `upsertModelPrice` per row, in order. */
|
|
488
|
+
declare function seedModelPrices(store: AgentPricingStore, prices: ModelPriceInput[]): Promise<void>;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Retrieval seam for RAG. A `Retriever` is a black box — the agent runtime asks it for the passages
|
|
492
|
+
* most relevant to a query and never sees how (vector search, keyword, hybrid, a remote service).
|
|
493
|
+
* The `@dudousxd/nestjs-agent-rag` package ships an `EmbeddingRetriever` (embed + vector store) and
|
|
494
|
+
* store adapters, but any impl satisfying this SPI works. Wire it as a tool for agentic retrieval
|
|
495
|
+
* (`createRetrievalTool`), or for always-on injection via `AgentModule.forRoot({ retrieval })`.
|
|
496
|
+
*/
|
|
497
|
+
/** One retrieved passage. `source` is a human/citation-facing origin; `score` is impl-defined relevance. */
|
|
498
|
+
interface Passage {
|
|
499
|
+
id: string;
|
|
500
|
+
text: string;
|
|
501
|
+
score: number;
|
|
502
|
+
/** Where the passage came from (document title, URL, row id) — surfaced as a citation. */
|
|
503
|
+
source?: string;
|
|
504
|
+
metadata?: Record<string, unknown>;
|
|
505
|
+
}
|
|
506
|
+
interface RetrieveOptions {
|
|
507
|
+
/** Max passages to return. The impl may cap it; the loop defaults to 5 when unset. */
|
|
508
|
+
topK?: number;
|
|
509
|
+
/** Impl-specific metadata filter (e.g. `{ tenantRef }`). Opaque to the runtime. */
|
|
510
|
+
filter?: Record<string, unknown>;
|
|
511
|
+
}
|
|
512
|
+
interface Retriever {
|
|
513
|
+
retrieve(query: string, options?: RetrieveOptions): Promise<Passage[]>;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Turns text into embedding vectors — the sibling of {@link import('./model-provider.js').ModelProvider}
|
|
518
|
+
* for the retrieval side. Batched (`texts` → one vector each, same order) so ingestion can embed many
|
|
519
|
+
* chunks per call. `@dudousxd/nestjs-agent-ai-sdk` implements it over the Vercel AI SDK `embedMany`;
|
|
520
|
+
* `@dudousxd/nestjs-agent-testing` ships a deterministic fake for offline tests.
|
|
521
|
+
*/
|
|
522
|
+
interface EmbeddingProvider {
|
|
523
|
+
/** Embed each input string; returns one vector per input, in the same order. */
|
|
524
|
+
embed(texts: string[]): Promise<number[][]>;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
interface RerankOptions {
|
|
528
|
+
/** Keep only the top N after reranking. Undefined → keep all, reordered. */
|
|
529
|
+
topK?: number;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Re-scores retrieved passages against the query with a stronger (usually cross-encoder) model than
|
|
533
|
+
* the first-stage retriever — the standard precision boost for RAG. It's a black box like
|
|
534
|
+
* {@link import('./retriever.js').Retriever}: bring a Cohere/Voyage rerank endpoint or a local
|
|
535
|
+
* cross-encoder. Compose it over any retriever with `RerankingRetriever` (over-fetch → rerank → topK).
|
|
536
|
+
*/
|
|
537
|
+
interface Reranker {
|
|
538
|
+
/** Re-order `passages` by relevance to `query`, rewriting their `score`; may drop to `topK`. */
|
|
539
|
+
rerank(query: string, passages: Passage[], options?: RerankOptions): Promise<Passage[]>;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Runs an agent turn. Two impls exist:
|
|
544
|
+
* - InlineAgentRunner (default): the loop runs in-process — no extra dependencies. This is what
|
|
545
|
+
* `AGENT_RUNNER` binds to unless `durable: true` is set.
|
|
546
|
+
* - DurableAgentRunner (opt-in via `durable: true`): the turn is a `@dudousxd/nestjs-durable`
|
|
547
|
+
* `@Workflow`, so each model/tool call is a checkpointed step and HITL is `ctx.waitForSignal`.
|
|
548
|
+
*
|
|
549
|
+
* `start` ENQUEUES and returns immediately with the runId — the live tokens flow on the
|
|
550
|
+
* TokenStreamSink, not through this call.
|
|
551
|
+
*/
|
|
552
|
+
interface AgentRunner {
|
|
553
|
+
start(input: AgentRunInput): Promise<{
|
|
554
|
+
runId: string;
|
|
555
|
+
}>;
|
|
556
|
+
/** Deliver a HITL decision for a pending action tool call. */
|
|
557
|
+
signal(runId: string, toolCallId: string, decision: Decision): Promise<void>;
|
|
558
|
+
cancel(runId: string): Promise<void>;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Resolves the acting {@link Actor} for an inbound request. This is the identity seam:
|
|
563
|
+
* the agent NEVER fabricates a caller. Configure one via `AgentModule.forRoot({ actorResolver })`
|
|
564
|
+
* that reads your authenticated principal (session, JWT, `@dudousxd/nestjs-context`, ...).
|
|
565
|
+
*
|
|
566
|
+
* When no resolver is configured, the module installs one that throws on every request —
|
|
567
|
+
* an identity is never invented from a default. See `HeaderActorResolver` for a header-based
|
|
568
|
+
* resolver suitable for demos and gateways that strip/re-set the headers.
|
|
569
|
+
*
|
|
570
|
+
* `req` is the transport request object, typed `unknown` to keep core framework-agnostic;
|
|
571
|
+
* a NestJS/Express app receives the express `Request`.
|
|
572
|
+
*/
|
|
573
|
+
interface ActorResolver {
|
|
574
|
+
resolve(req: unknown): Actor | Promise<Actor>;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* A read-model over the persisted agent data (usage ⋈ pricing, tool calls, threads) for the
|
|
579
|
+
* governance surfaces — the standalone `-dashboard` SPA and the `-telescope` "Agent" tab both
|
|
580
|
+
* consume this ONE interface, so cost/usage aggregation lives in a single place.
|
|
581
|
+
*
|
|
582
|
+
* Separate from {@link AgentStore} on purpose: that SPI owns the write/thread path, this owns the
|
|
583
|
+
* read/analytics path. A store adapter implements both. Consumers inject via
|
|
584
|
+
* `AGENT_GOVERNANCE_QUERIES`.
|
|
585
|
+
*
|
|
586
|
+
* Live activity (in-flight runs, streaming tool calls, delegations, forbidden attempts) is NOT here
|
|
587
|
+
* — that comes off the `aviary:agent:*` diagnostics channel. This interface is the durable, restart-
|
|
588
|
+
* surviving history.
|
|
589
|
+
*/
|
|
590
|
+
/** Inclusive UTC day range, each `YYYY-MM-DD`. */
|
|
591
|
+
interface GovernanceRange {
|
|
592
|
+
fromDay: string;
|
|
593
|
+
toDay: string;
|
|
594
|
+
}
|
|
595
|
+
/** Spend + token totals for one model over a range. */
|
|
596
|
+
interface ModelSpendRow {
|
|
597
|
+
modelId: string;
|
|
598
|
+
requests: number;
|
|
599
|
+
inputTokens: number;
|
|
600
|
+
outputTokens: number;
|
|
601
|
+
costUsd: number;
|
|
602
|
+
}
|
|
603
|
+
/** Spend + token totals for one acting ref (user/tenant) over a range. */
|
|
604
|
+
interface ActorSpendRow {
|
|
605
|
+
actorRef: string;
|
|
606
|
+
requests: number;
|
|
607
|
+
totalTokens: number;
|
|
608
|
+
costUsd: number;
|
|
609
|
+
}
|
|
610
|
+
/** One point on the daily usage/cost trend. */
|
|
611
|
+
interface UsageTrendPoint {
|
|
612
|
+
day: string;
|
|
613
|
+
totalTokens: number;
|
|
614
|
+
costUsd: number;
|
|
615
|
+
}
|
|
616
|
+
/** A recent tool-call for the activity feed. */
|
|
617
|
+
interface ToolCallActivityRow {
|
|
618
|
+
toolCallId: string;
|
|
619
|
+
toolName: string;
|
|
620
|
+
toolType: string;
|
|
621
|
+
status: string;
|
|
622
|
+
threadId: string;
|
|
623
|
+
createdAt: string;
|
|
624
|
+
}
|
|
625
|
+
/** A recent thread with rolled-up activity. */
|
|
626
|
+
interface ThreadActivityRow {
|
|
627
|
+
threadId: string;
|
|
628
|
+
title: string;
|
|
629
|
+
actorRef: string;
|
|
630
|
+
messageCount: number;
|
|
631
|
+
totalTokens: number;
|
|
632
|
+
lastActivityAt: string;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* The governance read-model. Cost is `inputTokens/1e6 * inputPricePer1m + outputTokens/1e6 *
|
|
636
|
+
* outputPricePer1m` against the current pricing row per model; an unpriced model contributes 0 cost
|
|
637
|
+
* (its tokens still count).
|
|
638
|
+
*/
|
|
639
|
+
interface AgentGovernanceQueries {
|
|
640
|
+
spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]>;
|
|
641
|
+
spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]>;
|
|
642
|
+
usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;
|
|
643
|
+
recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;
|
|
644
|
+
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/** First filter layer: drop tools the actor's role may not invoke. `can` may be async (authz). */
|
|
648
|
+
declare function filterToolsByRole(tools: ToolSpec[], actor: Actor, policy: RolesPolicy): Promise<ToolSpec[]>;
|
|
649
|
+
/** Second filter layer: if the persona pins an allow-list, keep only those tool names. */
|
|
650
|
+
declare function personaFilterTools(tools: ToolSpec[], allowedTools: string[] | undefined): ToolSpec[];
|
|
651
|
+
|
|
652
|
+
/** Holds the named agent definitions registered via `AgentModule.forFeature([...])`. */
|
|
653
|
+
declare class AgentRegistry {
|
|
654
|
+
private readonly definitions;
|
|
655
|
+
register(definition: AgentDefinition): void;
|
|
656
|
+
get(name: string): AgentDefinition | undefined;
|
|
657
|
+
has(name: string): boolean;
|
|
658
|
+
list(): AgentDefinition[];
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/** Thrown when an actor invokes a tool their role is not allowed. */
|
|
662
|
+
declare class ToolForbiddenError extends Error {
|
|
663
|
+
readonly toolName: string;
|
|
664
|
+
constructor(toolName: string);
|
|
665
|
+
}
|
|
666
|
+
/** Thrown when a tool is invoked that was never registered. */
|
|
667
|
+
declare class ToolNotFoundError extends Error {
|
|
668
|
+
readonly toolName: string;
|
|
669
|
+
constructor(toolName: string);
|
|
670
|
+
}
|
|
671
|
+
/** Thrown when a tool's input fails its Standard Schema validation. */
|
|
672
|
+
declare class ToolInputInvalidError extends Error {
|
|
673
|
+
readonly toolName: string;
|
|
674
|
+
readonly issues: readonly StandardSchemaV1.Issue[];
|
|
675
|
+
constructor(toolName: string, issues: readonly StandardSchemaV1.Issue[]);
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Holds every registered tool and gates invocation.
|
|
679
|
+
*
|
|
680
|
+
* Note: `definitionsFor` returns NEUTRAL definitions (no `execute`). The agent loop runs
|
|
681
|
+
* each tool itself as a (durable) step — so even read tools are not auto-executed by the
|
|
682
|
+
* model. `action` tools additionally require HITL approval before the loop runs them.
|
|
683
|
+
*/
|
|
684
|
+
declare class ToolRegistry {
|
|
685
|
+
private readonly entries;
|
|
686
|
+
register(spec: ToolSpec, handler: ToolHandler): void;
|
|
687
|
+
has(name: string): boolean;
|
|
688
|
+
spec(name: string): ToolSpec | undefined;
|
|
689
|
+
allSpecs(): ToolSpec[];
|
|
690
|
+
/** The tools to offer the model for this actor+persona, after the two filter layers. */
|
|
691
|
+
definitionsFor(actor: Actor, policy: RolesPolicy, allowedTools?: string[]): Promise<ToolDefinition[]>;
|
|
692
|
+
/** Run a tool. Re-checks the role (defense-in-depth) and re-parses the input via Zod. */
|
|
693
|
+
invoke(name: string, input: unknown, ctx: AiToolCtx, policy: RolesPolicy): Promise<unknown>;
|
|
694
|
+
}
|
|
695
|
+
/** Default gate: one of the actor's roles must be in spec.roles (defaulting to ADMIN-only). */
|
|
696
|
+
declare class DefaultRolesPolicy implements RolesPolicy {
|
|
697
|
+
private readonly defaultRoles;
|
|
698
|
+
constructor(defaultRoles?: string[]);
|
|
699
|
+
can(actor: Actor, tool: ToolSpec): boolean;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
interface AgentLoopDeps {
|
|
703
|
+
model: ModelProvider;
|
|
704
|
+
store: AgentStore;
|
|
705
|
+
registry: ToolRegistry;
|
|
706
|
+
rolesPolicy: RolesPolicy;
|
|
707
|
+
quota?: QuotaStore;
|
|
708
|
+
/**
|
|
709
|
+
* Fallback accounting label when the provider's turn result doesn't report a `modelId`.
|
|
710
|
+
* Optional — a provider that reports its own model makes this unnecessary.
|
|
711
|
+
*/
|
|
712
|
+
modelId?: string;
|
|
713
|
+
/** Pre-computed (YYYY-MM-DD) so the loop body stays deterministic under durable replay. */
|
|
714
|
+
day: string;
|
|
715
|
+
/** The agent's base prompt. A flat string, or a {@link PromptBuilder} resolved per turn. */
|
|
716
|
+
systemPrompt: string | PromptBuilder;
|
|
717
|
+
maxSteps?: number;
|
|
718
|
+
/** Optional host handle threaded to tool ctx (e.g. an ORM EntityManager). */
|
|
719
|
+
host?: unknown;
|
|
720
|
+
/** Agent-level tool allow-list (intersected with the persona's). Undefined → all tools. */
|
|
721
|
+
toolAllowList?: string[];
|
|
722
|
+
/**
|
|
723
|
+
* Per-tool execution timeout in ms. A tool that runs longer is aborted and recorded as failed
|
|
724
|
+
* (the model gets the timeout as its result and can adapt) rather than hanging the turn.
|
|
725
|
+
* Undefined → no timeout.
|
|
726
|
+
*/
|
|
727
|
+
toolTimeoutMs?: number;
|
|
728
|
+
/**
|
|
729
|
+
* When set, after the final turn the loop makes one extra model call to propose up to this many
|
|
730
|
+
* short follow-up questions, stored on the assistant message's `followUps`. Costs an extra call
|
|
731
|
+
* (recorded as `follow_ups` usage). Undefined/0 → disabled.
|
|
732
|
+
*/
|
|
733
|
+
followUpsCount?: number;
|
|
734
|
+
/**
|
|
735
|
+
* Enables always-on ("inject") RAG: before the turn, retrieve passages for the user message and
|
|
736
|
+
* augment the system prompt with them. Its presence IS inject mode — agentic (tool) retrieval sets
|
|
737
|
+
* no retriever here (it rides a normal `read` tool). Undefined → no injection.
|
|
738
|
+
*/
|
|
739
|
+
retriever?: Retriever;
|
|
740
|
+
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
741
|
+
retrievalTopK?: number;
|
|
742
|
+
}
|
|
743
|
+
interface AgentLoopHooks {
|
|
744
|
+
runId: string;
|
|
745
|
+
/** A writer for this run's live token stream (data plane). */
|
|
746
|
+
openSink(): SinkWriter | Promise<SinkWriter>;
|
|
747
|
+
/** HITL gate for an action tool. Inline resolves a pending promise; durable awaits a signal. */
|
|
748
|
+
awaitApproval(call: ToolCallRequest, ctx: AiToolCtx): Promise<Decision>;
|
|
749
|
+
/**
|
|
750
|
+
* Run another named agent and return its answer. Provided only when the host wired multi-agent
|
|
751
|
+
* support (durable → child workflow, inline → nested loop). Exposed to tools as `ctx.runAgent`.
|
|
752
|
+
*/
|
|
753
|
+
runAgent?(agentName: string, task: string): Promise<{
|
|
754
|
+
text: string;
|
|
755
|
+
}>;
|
|
756
|
+
/**
|
|
757
|
+
* Checkpoint wrapper. Inline = call fn directly; durable = ctx.step(name, fn).
|
|
758
|
+
* EVERY side-effect and control-flow read goes through this so durable replay returns
|
|
759
|
+
* cached results (stable ids, no double-write, no re-streaming).
|
|
760
|
+
*/
|
|
761
|
+
step<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
762
|
+
}
|
|
763
|
+
declare class QuotaExceededError extends Error {
|
|
764
|
+
constructor();
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* The provider-agnostic agent turn, reused by both the inline and durable runners.
|
|
768
|
+
* It drives the model→tools→model iteration; the runner supplies the `step`/`awaitApproval`
|
|
769
|
+
* hooks that make the same loop body either in-process or a replay-safe durable workflow.
|
|
770
|
+
*/
|
|
771
|
+
declare function runAgentLoop(deps: AgentLoopDeps, input: AgentRunInput, hooks: AgentLoopHooks): Promise<{
|
|
772
|
+
text: string;
|
|
773
|
+
}>;
|
|
774
|
+
|
|
775
|
+
/** Payloads carried on each `aviary:agent:*` channel. */
|
|
776
|
+
interface AgentRunStarted {
|
|
777
|
+
runId: string;
|
|
778
|
+
threadId: string;
|
|
779
|
+
actorId: string;
|
|
780
|
+
persona?: string;
|
|
781
|
+
}
|
|
782
|
+
interface AgentMessageEvent {
|
|
783
|
+
runId: string;
|
|
784
|
+
threadId: string;
|
|
785
|
+
role: 'user' | 'assistant';
|
|
786
|
+
textLength: number;
|
|
787
|
+
}
|
|
788
|
+
interface AgentToolCallEvent {
|
|
789
|
+
runId: string;
|
|
790
|
+
toolName: string;
|
|
791
|
+
toolType: 'read' | 'action';
|
|
792
|
+
status: string;
|
|
793
|
+
durationMs?: number;
|
|
794
|
+
}
|
|
795
|
+
interface AgentQuotaExceeded {
|
|
796
|
+
actorId: string;
|
|
797
|
+
usedTokens: number;
|
|
798
|
+
limitTokens: number;
|
|
799
|
+
}
|
|
800
|
+
interface AgentRunFinished {
|
|
801
|
+
runId: string;
|
|
802
|
+
threadId: string;
|
|
803
|
+
steps: number;
|
|
804
|
+
inputTokens: number;
|
|
805
|
+
outputTokens: number;
|
|
806
|
+
}
|
|
807
|
+
interface AgentRunFailed {
|
|
808
|
+
runId: string;
|
|
809
|
+
/** Stable failure slug, e.g. `quota_exceeded` or `run_failed`. */
|
|
810
|
+
code: string;
|
|
811
|
+
message: string;
|
|
812
|
+
}
|
|
813
|
+
interface AgentDelegated {
|
|
814
|
+
runId: string;
|
|
815
|
+
fromAgent?: string;
|
|
816
|
+
toAgent: string;
|
|
817
|
+
}
|
|
818
|
+
interface AgentRetrieved {
|
|
819
|
+
runId: string;
|
|
820
|
+
query: string;
|
|
821
|
+
/** How many passages the retriever returned. */
|
|
822
|
+
count: number;
|
|
823
|
+
}
|
|
824
|
+
/** Declaration-merge so `emit('agent', ...)` and telescope infer the agent payloads. */
|
|
825
|
+
declare module '@dudousxd/nestjs-diagnostics' {
|
|
826
|
+
interface ChannelRegistry {
|
|
827
|
+
agent: {
|
|
828
|
+
'run.started': AgentRunStarted;
|
|
829
|
+
message: AgentMessageEvent;
|
|
830
|
+
'tool-call': AgentToolCallEvent;
|
|
831
|
+
'quota.exceeded': AgentQuotaExceeded;
|
|
832
|
+
'run.finished': AgentRunFinished;
|
|
833
|
+
'run.failed': AgentRunFailed;
|
|
834
|
+
delegated: AgentDelegated;
|
|
835
|
+
retrieved: AgentRetrieved;
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
declare function publishAgentRunStarted(payload: AgentRunStarted): void;
|
|
840
|
+
declare function publishAgentMessage(payload: AgentMessageEvent): void;
|
|
841
|
+
declare function publishAgentToolCall(payload: AgentToolCallEvent): void;
|
|
842
|
+
declare function publishAgentQuotaExceeded(payload: AgentQuotaExceeded): void;
|
|
843
|
+
declare function publishAgentRunFinished(payload: AgentRunFinished): void;
|
|
844
|
+
declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
845
|
+
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
846
|
+
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
847
|
+
|
|
848
|
+
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, 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 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 CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type MessageRole, type MessageUsage, type ModelMessage, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type Persona, type PromptBuilder, type PromptContext, QuotaExceededError, type QuotaState, type QuotaStore, 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 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, filterToolsByRole, personaFilterTools, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|