@dudousxd/nestjs-agent-core 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +120 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +245 -4
- package/dist/index.d.ts +245 -4
- package/dist/index.js +116 -25
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,13 @@ interface ToolCallRequest {
|
|
|
48
48
|
id: string;
|
|
49
49
|
name: string;
|
|
50
50
|
input: unknown;
|
|
51
|
+
/**
|
|
52
|
+
* The tool's declared kind (`ToolSpec.kind`), stamped by the loop from the tool registry so
|
|
53
|
+
* thread-read consumers know a call's kind without hardcoding a tool-name allowlist. Undefined
|
|
54
|
+
* only for a call the loop couldn't resolve against the registry (defensively treated as `read`
|
|
55
|
+
* wherever a definite value is required).
|
|
56
|
+
*/
|
|
57
|
+
kind?: ToolKind;
|
|
51
58
|
}
|
|
52
59
|
/** Result of running a tool. */
|
|
53
60
|
interface ToolResult {
|
|
@@ -82,6 +89,13 @@ interface MessageUsage {
|
|
|
82
89
|
* non-reasoning models or providers that don't report it.
|
|
83
90
|
*/
|
|
84
91
|
reasoningTokens?: number;
|
|
92
|
+
/**
|
|
93
|
+
* This turn's USD cost: the provider's own reported figure when it has one, else an estimate from
|
|
94
|
+
* the bound `AgentPricingStore` (cached once per run — see `AgentLoopDeps.pricingStore`), else
|
|
95
|
+
* `null` when no pricing store is bound or the model has no price row. Never `0` for an unpriced
|
|
96
|
+
* model — a real $0 turn and "we don't know" must stay distinguishable.
|
|
97
|
+
*/
|
|
98
|
+
costUsd?: number | null;
|
|
85
99
|
}
|
|
86
100
|
type UsagePurpose = 'chat' | 'follow_ups';
|
|
87
101
|
interface QuotaState {
|
|
@@ -229,6 +243,18 @@ interface ThreadSummary {
|
|
|
229
243
|
createdAt: string;
|
|
230
244
|
updatedAt: string;
|
|
231
245
|
lastMessagePreview?: string;
|
|
246
|
+
/**
|
|
247
|
+
* The agent a `chat()` call on this thread uses when the caller doesn't name one explicitly.
|
|
248
|
+
* Optional — undefined for a store that doesn't implement `AgentStore.updateThread` (the only
|
|
249
|
+
* way to set it). The REST/service read-model normalizes this to `null` when absent.
|
|
250
|
+
*/
|
|
251
|
+
defaultAgent?: string | null;
|
|
252
|
+
/**
|
|
253
|
+
* The runId of a currently-running turn on this thread, or `null` if none is running. Optional —
|
|
254
|
+
* undefined for a store that doesn't implement `AgentStore.activeRunForThread`. The REST/service
|
|
255
|
+
* read-model normalizes this to `null` when absent, so a client can always do `?? null`.
|
|
256
|
+
*/
|
|
257
|
+
activeRunId?: string | null;
|
|
232
258
|
}
|
|
233
259
|
interface StoredMessage {
|
|
234
260
|
id: string;
|
|
@@ -249,6 +275,38 @@ interface ThreadDetail extends ThreadSummary {
|
|
|
249
275
|
activeStreamId?: string;
|
|
250
276
|
}
|
|
251
277
|
type ToolCallStatus = 'auto_executed' | 'pending_approval' | 'executed' | 'rejected' | 'failed';
|
|
278
|
+
/**
|
|
279
|
+
* Serializable input for a dispatched model-turn step. Carries only data — the serving worker
|
|
280
|
+
* re-resolves the model/sink/registry from its own DI via AGENT_DEPS_FACTORY.forAgent(agentName).
|
|
281
|
+
*/
|
|
282
|
+
interface LlmStepEnvelope {
|
|
283
|
+
/** Undefined = default agent (same semantics as {@link AgentRunInput.agentName}). */
|
|
284
|
+
agentName?: string;
|
|
285
|
+
system: string;
|
|
286
|
+
messages: ModelMessage[];
|
|
287
|
+
/** The turn's actor — the handler re-derives tool definitions from it (definitionsFor). */
|
|
288
|
+
actor: Actor;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* The serializable subset of `AiToolCtx` — everything except `host` (re-attached handler-side
|
|
292
|
+
* from DI).
|
|
293
|
+
*/
|
|
294
|
+
interface ToolStepCtx {
|
|
295
|
+
actor: Actor;
|
|
296
|
+
threadId: string;
|
|
297
|
+
runId: string;
|
|
298
|
+
requestId: string;
|
|
299
|
+
agentName?: string;
|
|
300
|
+
pageContext?: PageContext;
|
|
301
|
+
}
|
|
302
|
+
/** Serializable input for a dispatched tool-execution step. */
|
|
303
|
+
interface ToolStepEnvelope {
|
|
304
|
+
toolName: string;
|
|
305
|
+
input: unknown;
|
|
306
|
+
ctx: ToolStepCtx;
|
|
307
|
+
/** Applied INSIDE the handler (`withToolTimeout`) — never as a durable step `timeoutMs`. */
|
|
308
|
+
timeoutMs?: number;
|
|
309
|
+
}
|
|
252
310
|
|
|
253
311
|
/**
|
|
254
312
|
* Public, cross-lib-discoverable DI tokens.
|
|
@@ -288,6 +346,17 @@ declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
|
288
346
|
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
289
347
|
/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */
|
|
290
348
|
declare const AGENT_PROMPT_CONTRIBUTORS: unique symbol;
|
|
349
|
+
/**
|
|
350
|
+
* Resolves opaque store `actorRef`s to human display labels for governance/dashboard read surfaces.
|
|
351
|
+
* Optional — see {@link import('./spi/actor-directory.js').ActorDirectory}.
|
|
352
|
+
*/
|
|
353
|
+
declare const AGENT_ACTOR_DIRECTORY: unique symbol;
|
|
354
|
+
/**
|
|
355
|
+
* Persists an uploaded attachment somewhere the model can fetch it from and returns a
|
|
356
|
+
* `MessageAttachment`. Optional — see
|
|
357
|
+
* {@link import('./spi/attachment-staging.js').AttachmentStagingStore}.
|
|
358
|
+
*/
|
|
359
|
+
declare const AGENT_ATTACHMENT_STAGING: unique symbol;
|
|
291
360
|
|
|
292
361
|
/**
|
|
293
362
|
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
@@ -406,20 +475,32 @@ interface ModelProvider {
|
|
|
406
475
|
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
407
476
|
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
408
477
|
*/
|
|
478
|
+
|
|
409
479
|
type AgentStreamEvent = {
|
|
410
480
|
kind: 'step-start';
|
|
411
|
-
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Closes the step opened by the matching `step-start`. Carries the model call's token usage and
|
|
484
|
+
* `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a
|
|
485
|
+
* fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.
|
|
486
|
+
*/
|
|
487
|
+
| {
|
|
412
488
|
kind: 'step-finish';
|
|
489
|
+
usage?: MessageUsage;
|
|
490
|
+
costUsd?: number | null;
|
|
413
491
|
} | {
|
|
414
492
|
kind: 'text';
|
|
415
493
|
text: string;
|
|
416
494
|
} | {
|
|
417
495
|
kind: 'reasoning';
|
|
418
496
|
text: string;
|
|
419
|
-
}
|
|
497
|
+
}
|
|
498
|
+
/** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */
|
|
499
|
+
| {
|
|
420
500
|
kind: 'tool-input-start';
|
|
421
501
|
id: string;
|
|
422
502
|
name: string;
|
|
503
|
+
toolKind: 'read' | 'action';
|
|
423
504
|
} | {
|
|
424
505
|
kind: 'tool-input-delta';
|
|
425
506
|
id: string;
|
|
@@ -429,6 +510,7 @@ type AgentStreamEvent = {
|
|
|
429
510
|
id: string;
|
|
430
511
|
name: string;
|
|
431
512
|
input: unknown;
|
|
513
|
+
toolKind: 'read' | 'action';
|
|
432
514
|
} | {
|
|
433
515
|
kind: 'tool-output';
|
|
434
516
|
id: string;
|
|
@@ -475,6 +557,12 @@ interface UpdateToolCallInput {
|
|
|
475
557
|
executionMs?: number;
|
|
476
558
|
executedByRef?: string;
|
|
477
559
|
}
|
|
560
|
+
/** Patch applied by {@link AgentStore.updateThread}. An omitted key leaves that field untouched. */
|
|
561
|
+
interface UpdateThreadInput {
|
|
562
|
+
title?: string;
|
|
563
|
+
/** `null` clears the thread's default agent (falls back to the module default). */
|
|
564
|
+
defaultAgent?: string | null;
|
|
565
|
+
}
|
|
478
566
|
interface RecordUsageInput {
|
|
479
567
|
threadId: string;
|
|
480
568
|
actorRef: string;
|
|
@@ -485,6 +573,19 @@ interface RecordUsageInput {
|
|
|
485
573
|
/** Provider-reported actual USD cost for this turn, when known (gateways report it). */
|
|
486
574
|
costUsd?: number;
|
|
487
575
|
}
|
|
576
|
+
interface RecordRunStartInput {
|
|
577
|
+
runId: string;
|
|
578
|
+
threadId: string;
|
|
579
|
+
actorRef: string;
|
|
580
|
+
agentName?: string;
|
|
581
|
+
}
|
|
582
|
+
interface RecordRunEndInput {
|
|
583
|
+
runId: string;
|
|
584
|
+
status: 'completed' | 'failed';
|
|
585
|
+
durationMs?: number;
|
|
586
|
+
errorCode?: string;
|
|
587
|
+
errorMessage?: string;
|
|
588
|
+
}
|
|
488
589
|
/** ORM-agnostic persistence. Refs are string ids; adapters may add real relations. */
|
|
489
590
|
interface AgentStore {
|
|
490
591
|
createThread(input: CreateThreadInput): Promise<ThreadSummary>;
|
|
@@ -500,6 +601,29 @@ interface AgentStore {
|
|
|
500
601
|
*/
|
|
501
602
|
promoteThread(threadId: string): Promise<void>;
|
|
502
603
|
setActiveStream(threadId: string, runId: string | null): Promise<void>;
|
|
604
|
+
/**
|
|
605
|
+
* OPTIONAL: rename a thread and/or set its default agent in one write. Absent on a store that
|
|
606
|
+
* predates this — `setTitle` still covers title-only edits, so nothing else in the lib requires
|
|
607
|
+
* this method; the REST `PATCH /threads/:id` endpoint responds 501 for a `defaultAgent` change
|
|
608
|
+
* against a store that lacks it.
|
|
609
|
+
*/
|
|
610
|
+
updateThread?(threadId: string, patch: UpdateThreadInput): Promise<void>;
|
|
611
|
+
/**
|
|
612
|
+
* OPTIONAL: the runId of a currently-running turn on this thread, or `null` if none is running.
|
|
613
|
+
* Lets a client that reconnects (page refresh) discover a run to reattach to via the existing
|
|
614
|
+
* `GET /chat/:runId/stream`, instead of only being told about a run right after starting it.
|
|
615
|
+
* Absent on a store that predates this — thread read/list payloads report `activeRunId: null`.
|
|
616
|
+
*/
|
|
617
|
+
activeRunForThread?(threadId: string): Promise<string | null>;
|
|
618
|
+
/**
|
|
619
|
+
* OPTIONAL: persist the start of a run (turn). Replay-safe: called under a durable localStep.
|
|
620
|
+
* Absent on a store that predates run recording — reliability metrics degrade to zeros/empty.
|
|
621
|
+
*/
|
|
622
|
+
recordRunStart?(run: RecordRunStartInput): Promise<void>;
|
|
623
|
+
/** OPTIONAL: settle a run's outcome. `errorCode`/`errorMessage` only when status is 'failed'. */
|
|
624
|
+
recordRunEnd?(end: RecordRunEndInput): Promise<void>;
|
|
625
|
+
/** OPTIONAL: bump the run's llm-step retry counter (dispatched-step attempt > 1). */
|
|
626
|
+
bumpRunRetries?(runId: string): Promise<void>;
|
|
503
627
|
/**
|
|
504
628
|
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
505
629
|
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
@@ -752,6 +876,52 @@ interface ThreadActivityRow {
|
|
|
752
876
|
totalTokens: number;
|
|
753
877
|
lastActivityAt: string;
|
|
754
878
|
}
|
|
879
|
+
/** Aggregated run reliability over a range. */
|
|
880
|
+
interface RunMetrics {
|
|
881
|
+
runs: number;
|
|
882
|
+
completed: number;
|
|
883
|
+
failed: number;
|
|
884
|
+
/** completed / runs, 0 when runs = 0. */
|
|
885
|
+
successRate: number;
|
|
886
|
+
/** Total llm-step retries across the range's runs. */
|
|
887
|
+
retries: number;
|
|
888
|
+
durationP50Ms: number | null;
|
|
889
|
+
durationP95Ms: number | null;
|
|
890
|
+
}
|
|
891
|
+
/** Run/failure/retry rollup for one agent over a range. */
|
|
892
|
+
interface RunAgentBreakdownRow {
|
|
893
|
+
/** '(default)' when the run had none. */
|
|
894
|
+
agentName: string;
|
|
895
|
+
runs: number;
|
|
896
|
+
failed: number;
|
|
897
|
+
retries: number;
|
|
898
|
+
}
|
|
899
|
+
/** Failed-run count for one error code over a range. */
|
|
900
|
+
interface RunErrorBreakdownRow {
|
|
901
|
+
errorCode: string;
|
|
902
|
+
count: number;
|
|
903
|
+
}
|
|
904
|
+
/** One point on the daily run/failure trend. */
|
|
905
|
+
interface RunTrendPoint {
|
|
906
|
+
day: string;
|
|
907
|
+
runs: number;
|
|
908
|
+
failed: number;
|
|
909
|
+
}
|
|
910
|
+
/** A recent run for the reliability feed. */
|
|
911
|
+
interface RecentRunRow {
|
|
912
|
+
runId: string;
|
|
913
|
+
threadId: string;
|
|
914
|
+
actorRef: string;
|
|
915
|
+
agentName: string | null;
|
|
916
|
+
/** 'running' | 'completed' | 'failed'. */
|
|
917
|
+
status: string;
|
|
918
|
+
durationMs: number | null;
|
|
919
|
+
errorCode: string | null;
|
|
920
|
+
errorMessage: string | null;
|
|
921
|
+
retries: number;
|
|
922
|
+
/** ISO timestamp. */
|
|
923
|
+
startedAt: string;
|
|
924
|
+
}
|
|
755
925
|
/**
|
|
756
926
|
* The governance read-model. Cost is `inputTokens/1e6 * inputPricePer1m + outputTokens/1e6 *
|
|
757
927
|
* outputPricePer1m` against the current pricing row per model; an unpriced model contributes 0 cost
|
|
@@ -765,6 +935,50 @@ interface AgentGovernanceQueries {
|
|
|
765
935
|
usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;
|
|
766
936
|
recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;
|
|
767
937
|
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
938
|
+
runMetrics(range: GovernanceRange): Promise<RunMetrics>;
|
|
939
|
+
runsByAgent(range: GovernanceRange): Promise<RunAgentBreakdownRow[]>;
|
|
940
|
+
runErrors(range: GovernanceRange): Promise<RunErrorBreakdownRow[]>;
|
|
941
|
+
runTrend(range: GovernanceRange): Promise<RunTrendPoint[]>;
|
|
942
|
+
recentRuns(limit: number): Promise<RecentRunRow[]>;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Optional read-side lookup from opaque store `actorRef`s to human display labels.
|
|
947
|
+
*
|
|
948
|
+
* The store keeps `actorRef` opaque by design (no FK into the host's user table — hosts own their
|
|
949
|
+
* own identity schema). That's fine for enforcement and accounting, but a governance/dashboard read
|
|
950
|
+
* surface showing a raw ref ("u_8f21...") instead of a name is a bad experience. Binding an
|
|
951
|
+
* `ActorDirectory` lets those surfaces resolve refs to labels; leaving it unbound just means they
|
|
952
|
+
* render the raw ref. Consumers inject via `AGENT_ACTOR_DIRECTORY`.
|
|
953
|
+
*/
|
|
954
|
+
interface ActorDirectory {
|
|
955
|
+
/** Resolve opaque actor refs to display labels. Missing refs may be omitted. */
|
|
956
|
+
resolveDisplay(refs: readonly string[]): Promise<Record<string, string>>;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** Input to {@link AttachmentStagingStore.stage} — the raw bytes plus who uploaded them. */
|
|
960
|
+
interface StageAttachmentInput {
|
|
961
|
+
data: Buffer;
|
|
962
|
+
filename: string;
|
|
963
|
+
contentType: string;
|
|
964
|
+
sizeBytes: number;
|
|
965
|
+
actor: Actor;
|
|
966
|
+
}
|
|
967
|
+
/**
|
|
968
|
+
* Optional upload-side seam for message attachments (an image/PDF a user attaches to a chat
|
|
969
|
+
* message before the model ever sees it). The lib never fetches bytes itself — {@link MessageAttachment.url}
|
|
970
|
+
* must already be reachable by the model provider — so something has to turn an uploaded file into
|
|
971
|
+
* that URL first. A store adapter (or a thin wrapper over the host's own media pipeline) implements
|
|
972
|
+
* this; consumers inject via `AGENT_ATTACHMENT_STAGING`. Unbound, the optional `POST /agent/attachments`
|
|
973
|
+
* upload controller is never mounted.
|
|
974
|
+
*/
|
|
975
|
+
interface AttachmentStagingStore {
|
|
976
|
+
/**
|
|
977
|
+
* Persist an uploaded file somewhere the model can later fetch (presigned URL etc.) and return the
|
|
978
|
+
* {@link MessageAttachment} to send with the next chat message. The lib never fetches bytes; the
|
|
979
|
+
* returned url must be reachable by the model provider.
|
|
980
|
+
*/
|
|
981
|
+
stage(input: StageAttachmentInput): Promise<MessageAttachment>;
|
|
768
982
|
}
|
|
769
983
|
|
|
770
984
|
/**
|
|
@@ -936,6 +1150,12 @@ interface AgentLoopDeps {
|
|
|
936
1150
|
retriever?: Retriever;
|
|
937
1151
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
938
1152
|
retrievalTopK?: number;
|
|
1153
|
+
/**
|
|
1154
|
+
* Prices each step's token usage into `costUsd` (on the `step-finish` stream frame and the
|
|
1155
|
+
* persisted assistant message's `usage`). The current price list is fetched ONCE per run (not per
|
|
1156
|
+
* message/step) and reused for every step's estimate. Undefined → `costUsd` is always `null`.
|
|
1157
|
+
*/
|
|
1158
|
+
pricingStore?: AgentPricingStore;
|
|
939
1159
|
}
|
|
940
1160
|
interface AgentLoopHooks {
|
|
941
1161
|
runId: string;
|
|
@@ -951,15 +1171,36 @@ interface AgentLoopHooks {
|
|
|
951
1171
|
text: string;
|
|
952
1172
|
}>;
|
|
953
1173
|
/**
|
|
954
|
-
* Checkpoint wrapper. Inline = call fn directly; durable = ctx.
|
|
1174
|
+
* Checkpoint wrapper. Inline = call fn directly; durable = ctx.localStep(name, fn) — the
|
|
1175
|
+
* in-process checkpointed primitive (`name` is a checkpoint identity, not a worker group).
|
|
955
1176
|
* EVERY side-effect and control-flow read goes through this so durable replay returns
|
|
956
1177
|
* cached results (stable ids, no double-write, no re-streaming).
|
|
957
1178
|
*/
|
|
958
1179
|
step<T>(name: string, fn: () => Promise<T>): Promise<T>;
|
|
1180
|
+
/**
|
|
1181
|
+
* Dispatch the model turn as a routed remote step. When present the loop uses it INSTEAD of
|
|
1182
|
+
* running the model inline under hooks.step. Must resolve to exactly what deps.model.runTurn
|
|
1183
|
+
* resolves. The durable runner enriches the envelope with sink routing (sinkRunId/childSink)
|
|
1184
|
+
* on its side — core stays sink-topology-agnostic.
|
|
1185
|
+
*/
|
|
1186
|
+
dispatchLlm?(index: number, envelope: LlmStepEnvelope): Promise<ModelTurnResult>;
|
|
1187
|
+
/**
|
|
1188
|
+
* Dispatch one tool execution as a routed remote step. Replaces ONLY the registry.invoke call
|
|
1189
|
+
* (+ its timeout, applied handler-side); all persist steps around it stay local.
|
|
1190
|
+
*/
|
|
1191
|
+
dispatchTool?(call: ToolCallRequest, envelope: ToolStepEnvelope): Promise<unknown>;
|
|
1192
|
+
/**
|
|
1193
|
+
* Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so the loop
|
|
1194
|
+
* rethrows them untouched instead of recording a failure. Inline runners omit it — they have no
|
|
1195
|
+
* control-flow exceptions.
|
|
1196
|
+
*/
|
|
1197
|
+
isControlFlowError?(error: unknown): boolean;
|
|
959
1198
|
}
|
|
960
1199
|
declare class QuotaExceededError extends Error {
|
|
961
1200
|
constructor();
|
|
962
1201
|
}
|
|
1202
|
+
/** Reject if `work` doesn't settle within `ms`. The underlying work is left to finish on its own. */
|
|
1203
|
+
declare function withToolTimeout<T>(work: Promise<T>, ms: number, toolName: string): Promise<T>;
|
|
963
1204
|
/**
|
|
964
1205
|
* The provider-agnostic agent turn, reused by both the inline and durable runners.
|
|
965
1206
|
* It drives the model→tools→model iteration; the runner supplies the `step`/`awaitApproval`
|
|
@@ -1043,4 +1284,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
1043
1284
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
1044
1285
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
1045
1286
|
|
|
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 };
|
|
1287
|
+
export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING, 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 ActorDirectory, 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 AttachmentStagingStore, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type LlmStepEnvelope, 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 RecentRunRow, type RecordRunEndInput, type RecordRunStartInput, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type RunAgentBreakdownRow, type RunErrorBreakdownRow, type RunMetrics, type RunTrendPoint, type SinkWriter, type StageAttachmentInput, 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 ToolStepCtx, type ToolStepEnvelope, type UpdateThreadInput, 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, withToolTimeout };
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,8 @@ var AGENT_RETRIEVER = Symbol.for("@dudousxd/nestjs-agent:retriever");
|
|
|
19
19
|
var AGENT_EMBEDDING_PROVIDER = Symbol.for("@dudousxd/nestjs-agent:embedding-provider");
|
|
20
20
|
var AGENT_DEPS_FACTORY = Symbol.for("@dudousxd/nestjs-agent:deps-factory");
|
|
21
21
|
var AGENT_PROMPT_CONTRIBUTORS = Symbol.for("@dudousxd/nestjs-agent:prompt-contributors");
|
|
22
|
+
var AGENT_ACTOR_DIRECTORY = Symbol.for("@dudousxd/nestjs-agent:actor-directory");
|
|
23
|
+
var AGENT_ATTACHMENT_STAGING = Symbol.for("@dudousxd/nestjs-agent:attachment-staging");
|
|
22
24
|
|
|
23
25
|
// src/spi/token-stream-sink.ts
|
|
24
26
|
var AgentStreamError = class extends Error {
|
|
@@ -358,6 +360,13 @@ function publishAgentRetrieved(payload) {
|
|
|
358
360
|
__name(publishAgentRetrieved, "publishAgentRetrieved");
|
|
359
361
|
|
|
360
362
|
// src/agent-loop.ts
|
|
363
|
+
function resolveCostUsd(usage, reportedCostUsd, price) {
|
|
364
|
+
if (reportedCostUsd !== void 0) {
|
|
365
|
+
return reportedCostUsd;
|
|
366
|
+
}
|
|
367
|
+
return price === void 0 ? null : estimateCost(usage, price);
|
|
368
|
+
}
|
|
369
|
+
__name(resolveCostUsd, "resolveCostUsd");
|
|
361
370
|
function buildContextBlock(passages) {
|
|
362
371
|
const items = passages.map((passage, index) => {
|
|
363
372
|
const label = passage.source !== void 0 ? ` (${passage.source})` : "";
|
|
@@ -427,7 +436,7 @@ var ToolTimeoutError = class ToolTimeoutError2 extends Error {
|
|
|
427
436
|
this.name = "ToolTimeoutError";
|
|
428
437
|
}
|
|
429
438
|
};
|
|
430
|
-
function
|
|
439
|
+
function withToolTimeout(work, ms, toolName) {
|
|
431
440
|
return new Promise((resolve, reject) => {
|
|
432
441
|
const timer = setTimeout(() => reject(new ToolTimeoutError(toolName, ms)), ms);
|
|
433
442
|
work.then((value) => {
|
|
@@ -439,7 +448,7 @@ function withTimeout(work, ms, toolName) {
|
|
|
439
448
|
});
|
|
440
449
|
});
|
|
441
450
|
}
|
|
442
|
-
__name(
|
|
451
|
+
__name(withToolTimeout, "withToolTimeout");
|
|
443
452
|
function parseFollowUps(text, count) {
|
|
444
453
|
const source = text.match(/\[[\s\S]*\]/)?.[0] ?? text;
|
|
445
454
|
try {
|
|
@@ -544,6 +553,17 @@ async function runAgentLoop(deps, input, hooks) {
|
|
|
544
553
|
agentName: input.agentName
|
|
545
554
|
} : {}
|
|
546
555
|
});
|
|
556
|
+
const startedAt = await hooks.step("run:started-at", () => Promise.resolve(Date.now()));
|
|
557
|
+
await hooks.step("persist:run:start", async () => {
|
|
558
|
+
await deps.store.recordRunStart?.({
|
|
559
|
+
runId: hooks.runId,
|
|
560
|
+
threadId: input.threadId,
|
|
561
|
+
actorRef: input.actor.id,
|
|
562
|
+
...input.agentName !== void 0 ? {
|
|
563
|
+
agentName: input.agentName
|
|
564
|
+
} : {}
|
|
565
|
+
});
|
|
566
|
+
});
|
|
547
567
|
let injectedPassages;
|
|
548
568
|
if (deps.retriever !== void 0) {
|
|
549
569
|
const retriever = deps.retriever;
|
|
@@ -562,24 +582,50 @@ ${buildContextBlock(passages)}`;
|
|
|
562
582
|
count: passages.length
|
|
563
583
|
});
|
|
564
584
|
}
|
|
585
|
+
let prices = [];
|
|
586
|
+
if (deps.pricingStore !== void 0) {
|
|
587
|
+
const pricingStore = deps.pricingStore;
|
|
588
|
+
prices = await hooks.step("pricing:list", () => pricingStore.listCurrentPrices());
|
|
589
|
+
}
|
|
590
|
+
const priceByModel = new Map(prices.map((price) => [
|
|
591
|
+
price.modelId,
|
|
592
|
+
price
|
|
593
|
+
]));
|
|
565
594
|
for (let i = 0; i < maxSteps; i += 1) {
|
|
566
595
|
await hooks.step(`stream:step-start:${i}`, async () => {
|
|
567
596
|
await writer.write(encodeStreamEvent({
|
|
568
597
|
kind: "step-start"
|
|
569
598
|
}));
|
|
570
599
|
});
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
600
|
+
let turn;
|
|
601
|
+
if (hooks.dispatchLlm) {
|
|
602
|
+
turn = await hooks.dispatchLlm(i, {
|
|
603
|
+
...input.agentName !== void 0 ? {
|
|
604
|
+
agentName: input.agentName
|
|
605
|
+
} : {},
|
|
606
|
+
system,
|
|
607
|
+
messages: modelMessages,
|
|
608
|
+
actor: input.actor
|
|
609
|
+
});
|
|
610
|
+
} else {
|
|
611
|
+
const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
|
|
612
|
+
turn = await hooks.step(`llm:${i}`, () => deps.model.runTurn({
|
|
613
|
+
system,
|
|
614
|
+
messages: modelMessages,
|
|
615
|
+
tools,
|
|
616
|
+
sink: writer
|
|
617
|
+
}));
|
|
618
|
+
}
|
|
619
|
+
const resolvedModelId = turn.modelId ?? deps.modelId ?? "unknown";
|
|
620
|
+
const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));
|
|
621
|
+
const toolCallsWithKind = turn.toolCalls.map((call) => ({
|
|
622
|
+
...call,
|
|
623
|
+
kind: deps.registry.spec(call.name)?.kind ?? "read"
|
|
577
624
|
}));
|
|
578
625
|
await hooks.step(`persist:usage:${i}`, () => deps.store.recordUsage({
|
|
579
626
|
threadId: input.threadId,
|
|
580
627
|
actorRef: input.actor.id,
|
|
581
|
-
|
|
582
|
-
modelId: turn.modelId ?? deps.modelId ?? "unknown",
|
|
628
|
+
modelId: resolvedModelId,
|
|
583
629
|
purpose: "chat",
|
|
584
630
|
usage: turn.usage,
|
|
585
631
|
// persist the provider's actual cost when reported; the read-model prefers it over pricing
|
|
@@ -627,12 +673,15 @@ ${buildContextBlock(passages)}`;
|
|
|
627
673
|
threadId: input.threadId,
|
|
628
674
|
role: "assistant",
|
|
629
675
|
content: turn.text,
|
|
630
|
-
usage:
|
|
676
|
+
usage: {
|
|
677
|
+
...turn.usage,
|
|
678
|
+
costUsd
|
|
679
|
+
},
|
|
631
680
|
...input.agentName !== void 0 ? {
|
|
632
681
|
agentName: input.agentName
|
|
633
682
|
} : {},
|
|
634
|
-
...
|
|
635
|
-
toolCalls:
|
|
683
|
+
...toolCallsWithKind.length > 0 ? {
|
|
684
|
+
toolCalls: toolCallsWithKind
|
|
636
685
|
} : {},
|
|
637
686
|
...followUps !== void 0 ? {
|
|
638
687
|
followUps
|
|
@@ -641,8 +690,8 @@ ${buildContextBlock(passages)}`;
|
|
|
641
690
|
const assistantMessage = {
|
|
642
691
|
role: "assistant",
|
|
643
692
|
content: turn.text,
|
|
644
|
-
...
|
|
645
|
-
toolCalls:
|
|
693
|
+
...toolCallsWithKind.length > 0 ? {
|
|
694
|
+
toolCalls: toolCallsWithKind
|
|
646
695
|
} : {}
|
|
647
696
|
};
|
|
648
697
|
modelMessages.push(assistantMessage);
|
|
@@ -672,15 +721,17 @@ ${buildContextBlock(passages)}`;
|
|
|
672
721
|
if (isFinalTurn) {
|
|
673
722
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
674
723
|
await writer.write(encodeStreamEvent({
|
|
675
|
-
kind: "step-finish"
|
|
724
|
+
kind: "step-finish",
|
|
725
|
+
usage: turn.usage,
|
|
726
|
+
costUsd
|
|
676
727
|
}));
|
|
677
728
|
});
|
|
678
729
|
break;
|
|
679
730
|
}
|
|
680
731
|
const results = [];
|
|
681
|
-
for (const call of
|
|
732
|
+
for (const call of toolCallsWithKind) {
|
|
682
733
|
const spec = deps.registry.spec(call.name);
|
|
683
|
-
const toolType =
|
|
734
|
+
const toolType = call.kind ?? "read";
|
|
684
735
|
const ctx = {
|
|
685
736
|
actor: input.actor,
|
|
686
737
|
threadId: input.threadId,
|
|
@@ -784,11 +835,36 @@ ${buildContextBlock(passages)}`;
|
|
|
784
835
|
status: "auto_executed"
|
|
785
836
|
}));
|
|
786
837
|
}
|
|
787
|
-
const
|
|
838
|
+
const startedAt2 = Date.now();
|
|
788
839
|
try {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
840
|
+
let output;
|
|
841
|
+
if (hooks.dispatchTool) {
|
|
842
|
+
const stepCtx = {
|
|
843
|
+
actor: input.actor,
|
|
844
|
+
threadId: input.threadId,
|
|
845
|
+
runId: hooks.runId,
|
|
846
|
+
requestId: hooks.runId,
|
|
847
|
+
...input.agentName !== void 0 ? {
|
|
848
|
+
agentName: input.agentName
|
|
849
|
+
} : {},
|
|
850
|
+
...input.pageContext !== void 0 ? {
|
|
851
|
+
pageContext: input.pageContext
|
|
852
|
+
} : {}
|
|
853
|
+
};
|
|
854
|
+
const envelope = {
|
|
855
|
+
toolName: call.name,
|
|
856
|
+
input: call.input,
|
|
857
|
+
ctx: stepCtx,
|
|
858
|
+
...deps.toolTimeoutMs !== void 0 ? {
|
|
859
|
+
timeoutMs: deps.toolTimeoutMs
|
|
860
|
+
} : {}
|
|
861
|
+
};
|
|
862
|
+
output = await hooks.dispatchTool(call, envelope);
|
|
863
|
+
} else {
|
|
864
|
+
const invocation = hooks.step(`tool:${call.id}`, () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy));
|
|
865
|
+
output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
866
|
+
}
|
|
867
|
+
const executionMs = Date.now() - startedAt2;
|
|
792
868
|
await hooks.step(`persist:toolexec:${call.id}`, () => deps.store.updateToolCall({
|
|
793
869
|
toolCallId: call.id,
|
|
794
870
|
status: "executed",
|
|
@@ -811,7 +887,10 @@ ${buildContextBlock(passages)}`;
|
|
|
811
887
|
durationMs: executionMs
|
|
812
888
|
});
|
|
813
889
|
} catch (error) {
|
|
814
|
-
|
|
890
|
+
if (hooks.isControlFlowError?.(error) === true) {
|
|
891
|
+
throw error;
|
|
892
|
+
}
|
|
893
|
+
const executionMs = Date.now() - startedAt2;
|
|
815
894
|
const message = error instanceof Error ? error.message : String(error);
|
|
816
895
|
await hooks.step(`persist:toolfail:${call.id}`, () => deps.store.updateToolCall({
|
|
817
896
|
toolCallId: call.id,
|
|
@@ -850,13 +929,22 @@ ${buildContextBlock(passages)}`;
|
|
|
850
929
|
});
|
|
851
930
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
852
931
|
await writer.write(encodeStreamEvent({
|
|
853
|
-
kind: "step-finish"
|
|
932
|
+
kind: "step-finish",
|
|
933
|
+
usage: turn.usage,
|
|
934
|
+
costUsd
|
|
854
935
|
}));
|
|
855
936
|
});
|
|
856
937
|
}
|
|
857
938
|
if (thread !== null && (thread.title === "" || thread.title === "New chat")) {
|
|
858
939
|
await hooks.step("persist:title", () => deps.store.setTitle(input.threadId, deriveTitle(input.userText)));
|
|
859
940
|
}
|
|
941
|
+
await hooks.step("persist:run:end", async () => {
|
|
942
|
+
await deps.store.recordRunEnd?.({
|
|
943
|
+
runId: hooks.runId,
|
|
944
|
+
status: "completed",
|
|
945
|
+
durationMs: Date.now() - startedAt
|
|
946
|
+
});
|
|
947
|
+
});
|
|
860
948
|
await writer.end();
|
|
861
949
|
publishAgentRunFinished({
|
|
862
950
|
runId: hooks.runId,
|
|
@@ -871,7 +959,9 @@ ${buildContextBlock(passages)}`;
|
|
|
871
959
|
}
|
|
872
960
|
__name(runAgentLoop, "runAgentLoop");
|
|
873
961
|
export {
|
|
962
|
+
AGENT_ACTOR_DIRECTORY,
|
|
874
963
|
AGENT_ACTOR_RESOLVER,
|
|
964
|
+
AGENT_ATTACHMENT_STAGING,
|
|
875
965
|
AGENT_DEPS_FACTORY,
|
|
876
966
|
AGENT_DURABLE_RUNNER,
|
|
877
967
|
AGENT_EMBEDDING_PROVIDER,
|
|
@@ -914,6 +1004,7 @@ export {
|
|
|
914
1004
|
publishAgentRunStarted,
|
|
915
1005
|
publishAgentToolCall,
|
|
916
1006
|
runAgentLoop,
|
|
917
|
-
seedModelPrices
|
|
1007
|
+
seedModelPrices,
|
|
1008
|
+
withToolTimeout
|
|
918
1009
|
};
|
|
919
1010
|
//# sourceMappingURL=index.js.map
|