@dudousxd/nestjs-agent-core 0.3.3 → 0.4.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 +45 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -3
- package/dist/index.d.ts +118 -3
- package/dist/index.js +43 -11
- package/dist/index.js.map +1 -1
- package/package.json +6 -1
package/dist/index.d.cts
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;
|
|
@@ -288,6 +314,17 @@ declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
|
288
314
|
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
289
315
|
/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */
|
|
290
316
|
declare const AGENT_PROMPT_CONTRIBUTORS: unique symbol;
|
|
317
|
+
/**
|
|
318
|
+
* Resolves opaque store `actorRef`s to human display labels for governance/dashboard read surfaces.
|
|
319
|
+
* Optional — see {@link import('./spi/actor-directory.js').ActorDirectory}.
|
|
320
|
+
*/
|
|
321
|
+
declare const AGENT_ACTOR_DIRECTORY: unique symbol;
|
|
322
|
+
/**
|
|
323
|
+
* Persists an uploaded attachment somewhere the model can fetch it from and returns a
|
|
324
|
+
* `MessageAttachment`. Optional — see
|
|
325
|
+
* {@link import('./spi/attachment-staging.js').AttachmentStagingStore}.
|
|
326
|
+
*/
|
|
327
|
+
declare const AGENT_ATTACHMENT_STAGING: unique symbol;
|
|
291
328
|
|
|
292
329
|
/**
|
|
293
330
|
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
@@ -406,20 +443,32 @@ interface ModelProvider {
|
|
|
406
443
|
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
407
444
|
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
408
445
|
*/
|
|
446
|
+
|
|
409
447
|
type AgentStreamEvent = {
|
|
410
448
|
kind: 'step-start';
|
|
411
|
-
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Closes the step opened by the matching `step-start`. Carries the model call's token usage and
|
|
452
|
+
* `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a
|
|
453
|
+
* fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.
|
|
454
|
+
*/
|
|
455
|
+
| {
|
|
412
456
|
kind: 'step-finish';
|
|
457
|
+
usage?: MessageUsage;
|
|
458
|
+
costUsd?: number | null;
|
|
413
459
|
} | {
|
|
414
460
|
kind: 'text';
|
|
415
461
|
text: string;
|
|
416
462
|
} | {
|
|
417
463
|
kind: 'reasoning';
|
|
418
464
|
text: string;
|
|
419
|
-
}
|
|
465
|
+
}
|
|
466
|
+
/** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */
|
|
467
|
+
| {
|
|
420
468
|
kind: 'tool-input-start';
|
|
421
469
|
id: string;
|
|
422
470
|
name: string;
|
|
471
|
+
toolKind: 'read' | 'action';
|
|
423
472
|
} | {
|
|
424
473
|
kind: 'tool-input-delta';
|
|
425
474
|
id: string;
|
|
@@ -429,6 +478,7 @@ type AgentStreamEvent = {
|
|
|
429
478
|
id: string;
|
|
430
479
|
name: string;
|
|
431
480
|
input: unknown;
|
|
481
|
+
toolKind: 'read' | 'action';
|
|
432
482
|
} | {
|
|
433
483
|
kind: 'tool-output';
|
|
434
484
|
id: string;
|
|
@@ -475,6 +525,12 @@ interface UpdateToolCallInput {
|
|
|
475
525
|
executionMs?: number;
|
|
476
526
|
executedByRef?: string;
|
|
477
527
|
}
|
|
528
|
+
/** Patch applied by {@link AgentStore.updateThread}. An omitted key leaves that field untouched. */
|
|
529
|
+
interface UpdateThreadInput {
|
|
530
|
+
title?: string;
|
|
531
|
+
/** `null` clears the thread's default agent (falls back to the module default). */
|
|
532
|
+
defaultAgent?: string | null;
|
|
533
|
+
}
|
|
478
534
|
interface RecordUsageInput {
|
|
479
535
|
threadId: string;
|
|
480
536
|
actorRef: string;
|
|
@@ -500,6 +556,20 @@ interface AgentStore {
|
|
|
500
556
|
*/
|
|
501
557
|
promoteThread(threadId: string): Promise<void>;
|
|
502
558
|
setActiveStream(threadId: string, runId: string | null): Promise<void>;
|
|
559
|
+
/**
|
|
560
|
+
* OPTIONAL: rename a thread and/or set its default agent in one write. Absent on a store that
|
|
561
|
+
* predates this — `setTitle` still covers title-only edits, so nothing else in the lib requires
|
|
562
|
+
* this method; the REST `PATCH /threads/:id` endpoint responds 501 for a `defaultAgent` change
|
|
563
|
+
* against a store that lacks it.
|
|
564
|
+
*/
|
|
565
|
+
updateThread?(threadId: string, patch: UpdateThreadInput): Promise<void>;
|
|
566
|
+
/**
|
|
567
|
+
* OPTIONAL: the runId of a currently-running turn on this thread, or `null` if none is running.
|
|
568
|
+
* Lets a client that reconnects (page refresh) discover a run to reattach to via the existing
|
|
569
|
+
* `GET /chat/:runId/stream`, instead of only being told about a run right after starting it.
|
|
570
|
+
* Absent on a store that predates this — thread read/list payloads report `activeRunId: null`.
|
|
571
|
+
*/
|
|
572
|
+
activeRunForThread?(threadId: string): Promise<string | null>;
|
|
503
573
|
/**
|
|
504
574
|
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
505
575
|
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
@@ -767,6 +837,45 @@ interface AgentGovernanceQueries {
|
|
|
767
837
|
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
768
838
|
}
|
|
769
839
|
|
|
840
|
+
/**
|
|
841
|
+
* Optional read-side lookup from opaque store `actorRef`s to human display labels.
|
|
842
|
+
*
|
|
843
|
+
* The store keeps `actorRef` opaque by design (no FK into the host's user table — hosts own their
|
|
844
|
+
* own identity schema). That's fine for enforcement and accounting, but a governance/dashboard read
|
|
845
|
+
* surface showing a raw ref ("u_8f21...") instead of a name is a bad experience. Binding an
|
|
846
|
+
* `ActorDirectory` lets those surfaces resolve refs to labels; leaving it unbound just means they
|
|
847
|
+
* render the raw ref. Consumers inject via `AGENT_ACTOR_DIRECTORY`.
|
|
848
|
+
*/
|
|
849
|
+
interface ActorDirectory {
|
|
850
|
+
/** Resolve opaque actor refs to display labels. Missing refs may be omitted. */
|
|
851
|
+
resolveDisplay(refs: readonly string[]): Promise<Record<string, string>>;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/** Input to {@link AttachmentStagingStore.stage} — the raw bytes plus who uploaded them. */
|
|
855
|
+
interface StageAttachmentInput {
|
|
856
|
+
data: Buffer;
|
|
857
|
+
filename: string;
|
|
858
|
+
contentType: string;
|
|
859
|
+
sizeBytes: number;
|
|
860
|
+
actor: Actor;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Optional upload-side seam for message attachments (an image/PDF a user attaches to a chat
|
|
864
|
+
* message before the model ever sees it). The lib never fetches bytes itself — {@link MessageAttachment.url}
|
|
865
|
+
* must already be reachable by the model provider — so something has to turn an uploaded file into
|
|
866
|
+
* that URL first. A store adapter (or a thin wrapper over the host's own media pipeline) implements
|
|
867
|
+
* this; consumers inject via `AGENT_ATTACHMENT_STAGING`. Unbound, the optional `POST /agent/attachments`
|
|
868
|
+
* upload controller is never mounted.
|
|
869
|
+
*/
|
|
870
|
+
interface AttachmentStagingStore {
|
|
871
|
+
/**
|
|
872
|
+
* Persist an uploaded file somewhere the model can later fetch (presigned URL etc.) and return the
|
|
873
|
+
* {@link MessageAttachment} to send with the next chat message. The lib never fetches bytes; the
|
|
874
|
+
* returned url must be reachable by the model provider.
|
|
875
|
+
*/
|
|
876
|
+
stage(input: StageAttachmentInput): Promise<MessageAttachment>;
|
|
877
|
+
}
|
|
878
|
+
|
|
770
879
|
/**
|
|
771
880
|
* The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}
|
|
772
881
|
* adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the
|
|
@@ -936,6 +1045,12 @@ interface AgentLoopDeps {
|
|
|
936
1045
|
retriever?: Retriever;
|
|
937
1046
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
938
1047
|
retrievalTopK?: number;
|
|
1048
|
+
/**
|
|
1049
|
+
* Prices each step's token usage into `costUsd` (on the `step-finish` stream frame and the
|
|
1050
|
+
* persisted assistant message's `usage`). The current price list is fetched ONCE per run (not per
|
|
1051
|
+
* message/step) and reused for every step's estimate. Undefined → `costUsd` is always `null`.
|
|
1052
|
+
*/
|
|
1053
|
+
pricingStore?: AgentPricingStore;
|
|
939
1054
|
}
|
|
940
1055
|
interface AgentLoopHooks {
|
|
941
1056
|
runId: string;
|
|
@@ -1043,4 +1158,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
1043
1158
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
1044
1159
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
1045
1160
|
|
|
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 };
|
|
1161
|
+
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 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 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 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 };
|
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;
|
|
@@ -288,6 +314,17 @@ declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
|
288
314
|
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
289
315
|
/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */
|
|
290
316
|
declare const AGENT_PROMPT_CONTRIBUTORS: unique symbol;
|
|
317
|
+
/**
|
|
318
|
+
* Resolves opaque store `actorRef`s to human display labels for governance/dashboard read surfaces.
|
|
319
|
+
* Optional — see {@link import('./spi/actor-directory.js').ActorDirectory}.
|
|
320
|
+
*/
|
|
321
|
+
declare const AGENT_ACTOR_DIRECTORY: unique symbol;
|
|
322
|
+
/**
|
|
323
|
+
* Persists an uploaded attachment somewhere the model can fetch it from and returns a
|
|
324
|
+
* `MessageAttachment`. Optional — see
|
|
325
|
+
* {@link import('./spi/attachment-staging.js').AttachmentStagingStore}.
|
|
326
|
+
*/
|
|
327
|
+
declare const AGENT_ATTACHMENT_STAGING: unique symbol;
|
|
291
328
|
|
|
292
329
|
/**
|
|
293
330
|
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
@@ -406,20 +443,32 @@ interface ModelProvider {
|
|
|
406
443
|
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
407
444
|
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
408
445
|
*/
|
|
446
|
+
|
|
409
447
|
type AgentStreamEvent = {
|
|
410
448
|
kind: 'step-start';
|
|
411
|
-
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Closes the step opened by the matching `step-start`. Carries the model call's token usage and
|
|
452
|
+
* `costUsd` (an estimate from the bound pricing store, or `null` when unpriced/unbound — never a
|
|
453
|
+
* fabricated `0`) so a live client can render running cost without waiting for a thread re-fetch.
|
|
454
|
+
*/
|
|
455
|
+
| {
|
|
412
456
|
kind: 'step-finish';
|
|
457
|
+
usage?: MessageUsage;
|
|
458
|
+
costUsd?: number | null;
|
|
413
459
|
} | {
|
|
414
460
|
kind: 'text';
|
|
415
461
|
text: string;
|
|
416
462
|
} | {
|
|
417
463
|
kind: 'reasoning';
|
|
418
464
|
text: string;
|
|
419
|
-
}
|
|
465
|
+
}
|
|
466
|
+
/** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */
|
|
467
|
+
| {
|
|
420
468
|
kind: 'tool-input-start';
|
|
421
469
|
id: string;
|
|
422
470
|
name: string;
|
|
471
|
+
toolKind: 'read' | 'action';
|
|
423
472
|
} | {
|
|
424
473
|
kind: 'tool-input-delta';
|
|
425
474
|
id: string;
|
|
@@ -429,6 +478,7 @@ type AgentStreamEvent = {
|
|
|
429
478
|
id: string;
|
|
430
479
|
name: string;
|
|
431
480
|
input: unknown;
|
|
481
|
+
toolKind: 'read' | 'action';
|
|
432
482
|
} | {
|
|
433
483
|
kind: 'tool-output';
|
|
434
484
|
id: string;
|
|
@@ -475,6 +525,12 @@ interface UpdateToolCallInput {
|
|
|
475
525
|
executionMs?: number;
|
|
476
526
|
executedByRef?: string;
|
|
477
527
|
}
|
|
528
|
+
/** Patch applied by {@link AgentStore.updateThread}. An omitted key leaves that field untouched. */
|
|
529
|
+
interface UpdateThreadInput {
|
|
530
|
+
title?: string;
|
|
531
|
+
/** `null` clears the thread's default agent (falls back to the module default). */
|
|
532
|
+
defaultAgent?: string | null;
|
|
533
|
+
}
|
|
478
534
|
interface RecordUsageInput {
|
|
479
535
|
threadId: string;
|
|
480
536
|
actorRef: string;
|
|
@@ -500,6 +556,20 @@ interface AgentStore {
|
|
|
500
556
|
*/
|
|
501
557
|
promoteThread(threadId: string): Promise<void>;
|
|
502
558
|
setActiveStream(threadId: string, runId: string | null): Promise<void>;
|
|
559
|
+
/**
|
|
560
|
+
* OPTIONAL: rename a thread and/or set its default agent in one write. Absent on a store that
|
|
561
|
+
* predates this — `setTitle` still covers title-only edits, so nothing else in the lib requires
|
|
562
|
+
* this method; the REST `PATCH /threads/:id` endpoint responds 501 for a `defaultAgent` change
|
|
563
|
+
* against a store that lacks it.
|
|
564
|
+
*/
|
|
565
|
+
updateThread?(threadId: string, patch: UpdateThreadInput): Promise<void>;
|
|
566
|
+
/**
|
|
567
|
+
* OPTIONAL: the runId of a currently-running turn on this thread, or `null` if none is running.
|
|
568
|
+
* Lets a client that reconnects (page refresh) discover a run to reattach to via the existing
|
|
569
|
+
* `GET /chat/:runId/stream`, instead of only being told about a run right after starting it.
|
|
570
|
+
* Absent on a store that predates this — thread read/list payloads report `activeRunId: null`.
|
|
571
|
+
*/
|
|
572
|
+
activeRunForThread?(threadId: string): Promise<string | null>;
|
|
503
573
|
/**
|
|
504
574
|
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
505
575
|
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
@@ -767,6 +837,45 @@ interface AgentGovernanceQueries {
|
|
|
767
837
|
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
768
838
|
}
|
|
769
839
|
|
|
840
|
+
/**
|
|
841
|
+
* Optional read-side lookup from opaque store `actorRef`s to human display labels.
|
|
842
|
+
*
|
|
843
|
+
* The store keeps `actorRef` opaque by design (no FK into the host's user table — hosts own their
|
|
844
|
+
* own identity schema). That's fine for enforcement and accounting, but a governance/dashboard read
|
|
845
|
+
* surface showing a raw ref ("u_8f21...") instead of a name is a bad experience. Binding an
|
|
846
|
+
* `ActorDirectory` lets those surfaces resolve refs to labels; leaving it unbound just means they
|
|
847
|
+
* render the raw ref. Consumers inject via `AGENT_ACTOR_DIRECTORY`.
|
|
848
|
+
*/
|
|
849
|
+
interface ActorDirectory {
|
|
850
|
+
/** Resolve opaque actor refs to display labels. Missing refs may be omitted. */
|
|
851
|
+
resolveDisplay(refs: readonly string[]): Promise<Record<string, string>>;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
/** Input to {@link AttachmentStagingStore.stage} — the raw bytes plus who uploaded them. */
|
|
855
|
+
interface StageAttachmentInput {
|
|
856
|
+
data: Buffer;
|
|
857
|
+
filename: string;
|
|
858
|
+
contentType: string;
|
|
859
|
+
sizeBytes: number;
|
|
860
|
+
actor: Actor;
|
|
861
|
+
}
|
|
862
|
+
/**
|
|
863
|
+
* Optional upload-side seam for message attachments (an image/PDF a user attaches to a chat
|
|
864
|
+
* message before the model ever sees it). The lib never fetches bytes itself — {@link MessageAttachment.url}
|
|
865
|
+
* must already be reachable by the model provider — so something has to turn an uploaded file into
|
|
866
|
+
* that URL first. A store adapter (or a thin wrapper over the host's own media pipeline) implements
|
|
867
|
+
* this; consumers inject via `AGENT_ATTACHMENT_STAGING`. Unbound, the optional `POST /agent/attachments`
|
|
868
|
+
* upload controller is never mounted.
|
|
869
|
+
*/
|
|
870
|
+
interface AttachmentStagingStore {
|
|
871
|
+
/**
|
|
872
|
+
* Persist an uploaded file somewhere the model can later fetch (presigned URL etc.) and return the
|
|
873
|
+
* {@link MessageAttachment} to send with the next chat message. The lib never fetches bytes; the
|
|
874
|
+
* returned url must be reachable by the model provider.
|
|
875
|
+
*/
|
|
876
|
+
stage(input: StageAttachmentInput): Promise<MessageAttachment>;
|
|
877
|
+
}
|
|
878
|
+
|
|
770
879
|
/**
|
|
771
880
|
* The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}
|
|
772
881
|
* adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the
|
|
@@ -936,6 +1045,12 @@ interface AgentLoopDeps {
|
|
|
936
1045
|
retriever?: Retriever;
|
|
937
1046
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
938
1047
|
retrievalTopK?: number;
|
|
1048
|
+
/**
|
|
1049
|
+
* Prices each step's token usage into `costUsd` (on the `step-finish` stream frame and the
|
|
1050
|
+
* persisted assistant message's `usage`). The current price list is fetched ONCE per run (not per
|
|
1051
|
+
* message/step) and reused for every step's estimate. Undefined → `costUsd` is always `null`.
|
|
1052
|
+
*/
|
|
1053
|
+
pricingStore?: AgentPricingStore;
|
|
939
1054
|
}
|
|
940
1055
|
interface AgentLoopHooks {
|
|
941
1056
|
runId: string;
|
|
@@ -1043,4 +1158,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
1043
1158
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
1044
1159
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
1045
1160
|
|
|
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 };
|
|
1161
|
+
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 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 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 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 };
|
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})` : "";
|
|
@@ -562,6 +571,15 @@ ${buildContextBlock(passages)}`;
|
|
|
562
571
|
count: passages.length
|
|
563
572
|
});
|
|
564
573
|
}
|
|
574
|
+
let prices = [];
|
|
575
|
+
if (deps.pricingStore !== void 0) {
|
|
576
|
+
const pricingStore = deps.pricingStore;
|
|
577
|
+
prices = await hooks.step("pricing:list", () => pricingStore.listCurrentPrices());
|
|
578
|
+
}
|
|
579
|
+
const priceByModel = new Map(prices.map((price) => [
|
|
580
|
+
price.modelId,
|
|
581
|
+
price
|
|
582
|
+
]));
|
|
565
583
|
for (let i = 0; i < maxSteps; i += 1) {
|
|
566
584
|
await hooks.step(`stream:step-start:${i}`, async () => {
|
|
567
585
|
await writer.write(encodeStreamEvent({
|
|
@@ -575,11 +593,16 @@ ${buildContextBlock(passages)}`;
|
|
|
575
593
|
tools,
|
|
576
594
|
sink: writer
|
|
577
595
|
}));
|
|
596
|
+
const resolvedModelId = turn.modelId ?? deps.modelId ?? "unknown";
|
|
597
|
+
const costUsd = resolveCostUsd(turn.usage, turn.costUsd, priceByModel.get(resolvedModelId));
|
|
598
|
+
const toolCallsWithKind = turn.toolCalls.map((call) => ({
|
|
599
|
+
...call,
|
|
600
|
+
kind: deps.registry.spec(call.name)?.kind ?? "read"
|
|
601
|
+
}));
|
|
578
602
|
await hooks.step(`persist:usage:${i}`, () => deps.store.recordUsage({
|
|
579
603
|
threadId: input.threadId,
|
|
580
604
|
actorRef: input.actor.id,
|
|
581
|
-
|
|
582
|
-
modelId: turn.modelId ?? deps.modelId ?? "unknown",
|
|
605
|
+
modelId: resolvedModelId,
|
|
583
606
|
purpose: "chat",
|
|
584
607
|
usage: turn.usage,
|
|
585
608
|
// persist the provider's actual cost when reported; the read-model prefers it over pricing
|
|
@@ -627,12 +650,15 @@ ${buildContextBlock(passages)}`;
|
|
|
627
650
|
threadId: input.threadId,
|
|
628
651
|
role: "assistant",
|
|
629
652
|
content: turn.text,
|
|
630
|
-
usage:
|
|
653
|
+
usage: {
|
|
654
|
+
...turn.usage,
|
|
655
|
+
costUsd
|
|
656
|
+
},
|
|
631
657
|
...input.agentName !== void 0 ? {
|
|
632
658
|
agentName: input.agentName
|
|
633
659
|
} : {},
|
|
634
|
-
...
|
|
635
|
-
toolCalls:
|
|
660
|
+
...toolCallsWithKind.length > 0 ? {
|
|
661
|
+
toolCalls: toolCallsWithKind
|
|
636
662
|
} : {},
|
|
637
663
|
...followUps !== void 0 ? {
|
|
638
664
|
followUps
|
|
@@ -641,8 +667,8 @@ ${buildContextBlock(passages)}`;
|
|
|
641
667
|
const assistantMessage = {
|
|
642
668
|
role: "assistant",
|
|
643
669
|
content: turn.text,
|
|
644
|
-
...
|
|
645
|
-
toolCalls:
|
|
670
|
+
...toolCallsWithKind.length > 0 ? {
|
|
671
|
+
toolCalls: toolCallsWithKind
|
|
646
672
|
} : {}
|
|
647
673
|
};
|
|
648
674
|
modelMessages.push(assistantMessage);
|
|
@@ -672,15 +698,17 @@ ${buildContextBlock(passages)}`;
|
|
|
672
698
|
if (isFinalTurn) {
|
|
673
699
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
674
700
|
await writer.write(encodeStreamEvent({
|
|
675
|
-
kind: "step-finish"
|
|
701
|
+
kind: "step-finish",
|
|
702
|
+
usage: turn.usage,
|
|
703
|
+
costUsd
|
|
676
704
|
}));
|
|
677
705
|
});
|
|
678
706
|
break;
|
|
679
707
|
}
|
|
680
708
|
const results = [];
|
|
681
|
-
for (const call of
|
|
709
|
+
for (const call of toolCallsWithKind) {
|
|
682
710
|
const spec = deps.registry.spec(call.name);
|
|
683
|
-
const toolType =
|
|
711
|
+
const toolType = call.kind ?? "read";
|
|
684
712
|
const ctx = {
|
|
685
713
|
actor: input.actor,
|
|
686
714
|
threadId: input.threadId,
|
|
@@ -850,7 +878,9 @@ ${buildContextBlock(passages)}`;
|
|
|
850
878
|
});
|
|
851
879
|
await hooks.step(`stream:step-finish:${i}`, async () => {
|
|
852
880
|
await writer.write(encodeStreamEvent({
|
|
853
|
-
kind: "step-finish"
|
|
881
|
+
kind: "step-finish",
|
|
882
|
+
usage: turn.usage,
|
|
883
|
+
costUsd
|
|
854
884
|
}));
|
|
855
885
|
});
|
|
856
886
|
}
|
|
@@ -871,7 +901,9 @@ ${buildContextBlock(passages)}`;
|
|
|
871
901
|
}
|
|
872
902
|
__name(runAgentLoop, "runAgentLoop");
|
|
873
903
|
export {
|
|
904
|
+
AGENT_ACTOR_DIRECTORY,
|
|
874
905
|
AGENT_ACTOR_RESOLVER,
|
|
906
|
+
AGENT_ATTACHMENT_STAGING,
|
|
875
907
|
AGENT_DEPS_FACTORY,
|
|
876
908
|
AGENT_DURABLE_RUNNER,
|
|
877
909
|
AGENT_EMBEDDING_PROVIDER,
|