@dudousxd/nestjs-agent-core 0.3.2 → 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 +91 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +188 -1
- package/dist/index.d.ts +188 -1
- package/dist/index.js +88 -16
- 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 {
|
|
@@ -107,12 +121,30 @@ interface Decision {
|
|
|
107
121
|
reason?: string;
|
|
108
122
|
}
|
|
109
123
|
type MessageRole = 'user' | 'assistant' | 'system';
|
|
124
|
+
/**
|
|
125
|
+
* A file a user attached to a message so a vision-capable model sees it natively (an image, a PDF).
|
|
126
|
+
* The lib stays provider-agnostic: it passes {@link MessageAttachment.url} straight through as the
|
|
127
|
+
* model's image/file part data — making that URL reachable by the provider (presigned S3, a proxy)
|
|
128
|
+
* is the consumer's job. The lib never fetches bytes or talks to a store.
|
|
129
|
+
*/
|
|
130
|
+
interface MessageAttachment {
|
|
131
|
+
/** Stable id of the stored media object in the consumer's media store. Provenance + replay key. */
|
|
132
|
+
mediaId: string;
|
|
133
|
+
/** A URL the model provider can fetch the bytes from at turn time. */
|
|
134
|
+
url: string;
|
|
135
|
+
/** MIME type — routes the part: `image/*` → image part, otherwise → file part. */
|
|
136
|
+
contentType: string;
|
|
137
|
+
/** Original filename, for display and the file part's filename. */
|
|
138
|
+
name: string;
|
|
139
|
+
}
|
|
110
140
|
/** A neutral chat message exchanged with the model. */
|
|
111
141
|
interface ModelMessage {
|
|
112
142
|
role: MessageRole;
|
|
113
143
|
content: string;
|
|
114
144
|
toolCalls?: ToolCallRequest[];
|
|
115
145
|
toolResults?: ToolResult[];
|
|
146
|
+
/** User-message attachments (image/PDF), rendered as native model content parts by the adapter. */
|
|
147
|
+
attachments?: MessageAttachment[];
|
|
116
148
|
}
|
|
117
149
|
interface PageContext {
|
|
118
150
|
kind?: string;
|
|
@@ -148,6 +180,8 @@ interface AgentRunInput {
|
|
|
148
180
|
actor: Actor;
|
|
149
181
|
/** The latest user message text. */
|
|
150
182
|
userText: string;
|
|
183
|
+
/** Files attached to the latest user message (image/PDF). Persisted with it and sent to the model. */
|
|
184
|
+
attachments?: MessageAttachment[];
|
|
151
185
|
pageContext?: PageContext;
|
|
152
186
|
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
153
187
|
day?: string;
|
|
@@ -209,6 +243,18 @@ interface ThreadSummary {
|
|
|
209
243
|
createdAt: string;
|
|
210
244
|
updatedAt: string;
|
|
211
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;
|
|
212
258
|
}
|
|
213
259
|
interface StoredMessage {
|
|
214
260
|
id: string;
|
|
@@ -218,6 +264,8 @@ interface StoredMessage {
|
|
|
218
264
|
agentName?: string;
|
|
219
265
|
toolCalls?: ToolCallRequest[];
|
|
220
266
|
toolResults?: ToolResult[];
|
|
267
|
+
/** Files the user attached to this message (image/PDF). Persisted with the message, replayed as-is. */
|
|
268
|
+
attachments?: MessageAttachment[];
|
|
221
269
|
followUps?: string[];
|
|
222
270
|
usage?: MessageUsage;
|
|
223
271
|
createdAt: string;
|
|
@@ -266,6 +314,17 @@ declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
|
266
314
|
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
267
315
|
/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */
|
|
268
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;
|
|
269
328
|
|
|
270
329
|
/**
|
|
271
330
|
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
@@ -371,6 +430,67 @@ interface ModelProvider {
|
|
|
371
430
|
runTurn(args: ModelTurnArgs): Promise<ModelTurnResult>;
|
|
372
431
|
}
|
|
373
432
|
|
|
433
|
+
/**
|
|
434
|
+
* The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
|
|
435
|
+
*
|
|
436
|
+
* The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
|
|
437
|
+
* `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
|
|
438
|
+
* SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
|
|
439
|
+
* protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
|
|
440
|
+
* rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
|
|
441
|
+
* client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
|
|
442
|
+
*
|
|
443
|
+
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
444
|
+
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
445
|
+
*/
|
|
446
|
+
|
|
447
|
+
type AgentStreamEvent = {
|
|
448
|
+
kind: 'step-start';
|
|
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
|
+
| {
|
|
456
|
+
kind: 'step-finish';
|
|
457
|
+
usage?: MessageUsage;
|
|
458
|
+
costUsd?: number | null;
|
|
459
|
+
} | {
|
|
460
|
+
kind: 'text';
|
|
461
|
+
text: string;
|
|
462
|
+
} | {
|
|
463
|
+
kind: 'reasoning';
|
|
464
|
+
text: string;
|
|
465
|
+
}
|
|
466
|
+
/** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */
|
|
467
|
+
| {
|
|
468
|
+
kind: 'tool-input-start';
|
|
469
|
+
id: string;
|
|
470
|
+
name: string;
|
|
471
|
+
toolKind: 'read' | 'action';
|
|
472
|
+
} | {
|
|
473
|
+
kind: 'tool-input-delta';
|
|
474
|
+
id: string;
|
|
475
|
+
delta: string;
|
|
476
|
+
} | {
|
|
477
|
+
kind: 'tool-input-available';
|
|
478
|
+
id: string;
|
|
479
|
+
name: string;
|
|
480
|
+
input: unknown;
|
|
481
|
+
toolKind: 'read' | 'action';
|
|
482
|
+
} | {
|
|
483
|
+
kind: 'tool-output';
|
|
484
|
+
id: string;
|
|
485
|
+
output: unknown;
|
|
486
|
+
} | {
|
|
487
|
+
kind: 'tool-output-error';
|
|
488
|
+
id: string;
|
|
489
|
+
error: string;
|
|
490
|
+
};
|
|
491
|
+
/** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
|
|
492
|
+
declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
|
|
493
|
+
|
|
374
494
|
interface CreateThreadInput {
|
|
375
495
|
actor: Actor;
|
|
376
496
|
transient?: boolean;
|
|
@@ -384,6 +504,8 @@ interface AppendMessageInput {
|
|
|
384
504
|
agentName?: string;
|
|
385
505
|
toolCalls?: ToolCallRequest[];
|
|
386
506
|
toolResults?: ToolResult[];
|
|
507
|
+
/** Files the user attached to this message (image/PDF). Persisted verbatim. */
|
|
508
|
+
attachments?: MessageAttachment[];
|
|
387
509
|
followUps?: string[];
|
|
388
510
|
usage?: MessageUsage;
|
|
389
511
|
}
|
|
@@ -403,6 +525,12 @@ interface UpdateToolCallInput {
|
|
|
403
525
|
executionMs?: number;
|
|
404
526
|
executedByRef?: string;
|
|
405
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
|
+
}
|
|
406
534
|
interface RecordUsageInput {
|
|
407
535
|
threadId: string;
|
|
408
536
|
actorRef: string;
|
|
@@ -428,6 +556,20 @@ interface AgentStore {
|
|
|
428
556
|
*/
|
|
429
557
|
promoteThread(threadId: string): Promise<void>;
|
|
430
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>;
|
|
431
573
|
/**
|
|
432
574
|
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
433
575
|
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
@@ -695,6 +837,45 @@ interface AgentGovernanceQueries {
|
|
|
695
837
|
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
696
838
|
}
|
|
697
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
|
+
|
|
698
879
|
/**
|
|
699
880
|
* The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}
|
|
700
881
|
* adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the
|
|
@@ -864,6 +1045,12 @@ interface AgentLoopDeps {
|
|
|
864
1045
|
retriever?: Retriever;
|
|
865
1046
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
866
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;
|
|
867
1054
|
}
|
|
868
1055
|
interface AgentLoopHooks {
|
|
869
1056
|
runId: string;
|
|
@@ -971,4 +1158,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
971
1158
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
972
1159
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
973
1160
|
|
|
974
|
-
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
|
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 {
|
|
@@ -107,12 +121,30 @@ interface Decision {
|
|
|
107
121
|
reason?: string;
|
|
108
122
|
}
|
|
109
123
|
type MessageRole = 'user' | 'assistant' | 'system';
|
|
124
|
+
/**
|
|
125
|
+
* A file a user attached to a message so a vision-capable model sees it natively (an image, a PDF).
|
|
126
|
+
* The lib stays provider-agnostic: it passes {@link MessageAttachment.url} straight through as the
|
|
127
|
+
* model's image/file part data — making that URL reachable by the provider (presigned S3, a proxy)
|
|
128
|
+
* is the consumer's job. The lib never fetches bytes or talks to a store.
|
|
129
|
+
*/
|
|
130
|
+
interface MessageAttachment {
|
|
131
|
+
/** Stable id of the stored media object in the consumer's media store. Provenance + replay key. */
|
|
132
|
+
mediaId: string;
|
|
133
|
+
/** A URL the model provider can fetch the bytes from at turn time. */
|
|
134
|
+
url: string;
|
|
135
|
+
/** MIME type — routes the part: `image/*` → image part, otherwise → file part. */
|
|
136
|
+
contentType: string;
|
|
137
|
+
/** Original filename, for display and the file part's filename. */
|
|
138
|
+
name: string;
|
|
139
|
+
}
|
|
110
140
|
/** A neutral chat message exchanged with the model. */
|
|
111
141
|
interface ModelMessage {
|
|
112
142
|
role: MessageRole;
|
|
113
143
|
content: string;
|
|
114
144
|
toolCalls?: ToolCallRequest[];
|
|
115
145
|
toolResults?: ToolResult[];
|
|
146
|
+
/** User-message attachments (image/PDF), rendered as native model content parts by the adapter. */
|
|
147
|
+
attachments?: MessageAttachment[];
|
|
116
148
|
}
|
|
117
149
|
interface PageContext {
|
|
118
150
|
kind?: string;
|
|
@@ -148,6 +180,8 @@ interface AgentRunInput {
|
|
|
148
180
|
actor: Actor;
|
|
149
181
|
/** The latest user message text. */
|
|
150
182
|
userText: string;
|
|
183
|
+
/** Files attached to the latest user message (image/PDF). Persisted with it and sent to the model. */
|
|
184
|
+
attachments?: MessageAttachment[];
|
|
151
185
|
pageContext?: PageContext;
|
|
152
186
|
/** YYYY-MM-DD stamped by the runner so quota/day stays deterministic under durable replay. */
|
|
153
187
|
day?: string;
|
|
@@ -209,6 +243,18 @@ interface ThreadSummary {
|
|
|
209
243
|
createdAt: string;
|
|
210
244
|
updatedAt: string;
|
|
211
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;
|
|
212
258
|
}
|
|
213
259
|
interface StoredMessage {
|
|
214
260
|
id: string;
|
|
@@ -218,6 +264,8 @@ interface StoredMessage {
|
|
|
218
264
|
agentName?: string;
|
|
219
265
|
toolCalls?: ToolCallRequest[];
|
|
220
266
|
toolResults?: ToolResult[];
|
|
267
|
+
/** Files the user attached to this message (image/PDF). Persisted with the message, replayed as-is. */
|
|
268
|
+
attachments?: MessageAttachment[];
|
|
221
269
|
followUps?: string[];
|
|
222
270
|
usage?: MessageUsage;
|
|
223
271
|
createdAt: string;
|
|
@@ -266,6 +314,17 @@ declare const AGENT_EMBEDDING_PROVIDER: unique symbol;
|
|
|
266
314
|
declare const AGENT_DEPS_FACTORY: unique symbol;
|
|
267
315
|
/** App-wide, ordered `@SystemPromptContributor()` functions the loop appends after the agent base. */
|
|
268
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;
|
|
269
328
|
|
|
270
329
|
/**
|
|
271
330
|
* Per-invocation context handed to a tool handler. Host-supplied bits are optional. Identity lives
|
|
@@ -371,6 +430,67 @@ interface ModelProvider {
|
|
|
371
430
|
runTurn(args: ModelTurnArgs): Promise<ModelTurnResult>;
|
|
372
431
|
}
|
|
373
432
|
|
|
433
|
+
/**
|
|
434
|
+
* The structured live-stream vocabulary carried over the {@link SinkWriter} byte channel.
|
|
435
|
+
*
|
|
436
|
+
* The model turn (via the AI-SDK adapter) and the agent loop write these events as NDJSON — one
|
|
437
|
+
* `JSON.stringify(event)\n` per {@link SinkWriter.write}. The HTTP layer forwards each line as an
|
|
438
|
+
* SSE `data:` frame, and the client transport maps them back to the AI SDK UI-message chunk
|
|
439
|
+
* protocol so the browser renders text, reasoning, and tool cards (input + output) LIVE — the same
|
|
440
|
+
* rich rendering a raw `streamText().toUIMessageStream()` would give, but reconstructed on the
|
|
441
|
+
* client so the sink stays a format-agnostic byte buffer (durable buffering/replay is untouched).
|
|
442
|
+
*
|
|
443
|
+
* Keeping this vocabulary neutral (not AI-SDK `UIMessageChunk`) means core never depends on `ai`:
|
|
444
|
+
* the adapter owns model-parts → event, the transport owns event → UI-chunk.
|
|
445
|
+
*/
|
|
446
|
+
|
|
447
|
+
type AgentStreamEvent = {
|
|
448
|
+
kind: 'step-start';
|
|
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
|
+
| {
|
|
456
|
+
kind: 'step-finish';
|
|
457
|
+
usage?: MessageUsage;
|
|
458
|
+
costUsd?: number | null;
|
|
459
|
+
} | {
|
|
460
|
+
kind: 'text';
|
|
461
|
+
text: string;
|
|
462
|
+
} | {
|
|
463
|
+
kind: 'reasoning';
|
|
464
|
+
text: string;
|
|
465
|
+
}
|
|
466
|
+
/** `toolKind` collapses `ToolKind`'s `'agent'` into `'read'` — delegation tools auto-execute like a read tool. */
|
|
467
|
+
| {
|
|
468
|
+
kind: 'tool-input-start';
|
|
469
|
+
id: string;
|
|
470
|
+
name: string;
|
|
471
|
+
toolKind: 'read' | 'action';
|
|
472
|
+
} | {
|
|
473
|
+
kind: 'tool-input-delta';
|
|
474
|
+
id: string;
|
|
475
|
+
delta: string;
|
|
476
|
+
} | {
|
|
477
|
+
kind: 'tool-input-available';
|
|
478
|
+
id: string;
|
|
479
|
+
name: string;
|
|
480
|
+
input: unknown;
|
|
481
|
+
toolKind: 'read' | 'action';
|
|
482
|
+
} | {
|
|
483
|
+
kind: 'tool-output';
|
|
484
|
+
id: string;
|
|
485
|
+
output: unknown;
|
|
486
|
+
} | {
|
|
487
|
+
kind: 'tool-output-error';
|
|
488
|
+
id: string;
|
|
489
|
+
error: string;
|
|
490
|
+
};
|
|
491
|
+
/** Encode one event as an NDJSON line (`{...}\n`) for {@link SinkWriter.write}. */
|
|
492
|
+
declare function encodeStreamEvent(event: AgentStreamEvent): Uint8Array;
|
|
493
|
+
|
|
374
494
|
interface CreateThreadInput {
|
|
375
495
|
actor: Actor;
|
|
376
496
|
transient?: boolean;
|
|
@@ -384,6 +504,8 @@ interface AppendMessageInput {
|
|
|
384
504
|
agentName?: string;
|
|
385
505
|
toolCalls?: ToolCallRequest[];
|
|
386
506
|
toolResults?: ToolResult[];
|
|
507
|
+
/** Files the user attached to this message (image/PDF). Persisted verbatim. */
|
|
508
|
+
attachments?: MessageAttachment[];
|
|
387
509
|
followUps?: string[];
|
|
388
510
|
usage?: MessageUsage;
|
|
389
511
|
}
|
|
@@ -403,6 +525,12 @@ interface UpdateToolCallInput {
|
|
|
403
525
|
executionMs?: number;
|
|
404
526
|
executedByRef?: string;
|
|
405
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
|
+
}
|
|
406
534
|
interface RecordUsageInput {
|
|
407
535
|
threadId: string;
|
|
408
536
|
actorRef: string;
|
|
@@ -428,6 +556,20 @@ interface AgentStore {
|
|
|
428
556
|
*/
|
|
429
557
|
promoteThread(threadId: string): Promise<void>;
|
|
430
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>;
|
|
431
573
|
/**
|
|
432
574
|
* The `actorRef` that owns a thread, or `null` if no such thread exists. The authorization seam
|
|
433
575
|
* for thread-scoped endpoints (detail / delete / fork): the service compares this against the
|
|
@@ -695,6 +837,45 @@ interface AgentGovernanceQueries {
|
|
|
695
837
|
recentThreads(limit: number): Promise<ThreadActivityRow[]>;
|
|
696
838
|
}
|
|
697
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
|
+
|
|
698
879
|
/**
|
|
699
880
|
* The pure aggregation core shared by every {@link import('../spi/governance-queries.js').AgentGovernanceQueries}
|
|
700
881
|
* adapter (MikroORM, Drizzle, in-memory). An adapter's only job is the DB-specific row fetch; the
|
|
@@ -864,6 +1045,12 @@ interface AgentLoopDeps {
|
|
|
864
1045
|
retriever?: Retriever;
|
|
865
1046
|
/** How many passages inject-mode retrieval requests. Undefined → 5. */
|
|
866
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;
|
|
867
1054
|
}
|
|
868
1055
|
interface AgentLoopHooks {
|
|
869
1056
|
runId: string;
|
|
@@ -971,4 +1158,4 @@ declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
|
971
1158
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
972
1159
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
973
1160
|
|
|
974
|
-
export { AGENT_ACTOR_RESOLVER, AGENT_DEPS_FACTORY, AGENT_DURABLE_RUNNER, AGENT_EMBEDDING_PROVIDER, AGENT_GOVERNANCE_QUERIES, AGENT_MODEL, AGENT_OPTIONS, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_RETRIEVER, AGENT_ROLES_POLICY, AGENT_RUNNER, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorResolver, type ActorSpendRow, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentGovernanceQueries, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentStore, AgentStreamError, type AgentToolCallEvent, type AiToolCtx, type AppendMessageInput, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernanceRange, type GovernanceUsageInput, type MessageRole, type MessageUsage, type ModelMessage, type ModelPrice, type ModelPriceInput, type ModelProvider, type ModelSpendRow, type ModelTurnArgs, type ModelTurnResult, type PageContext, type Passage, type PromptBuilder, type PromptContext, type PromptContributor, QuotaExceededError, type QuotaState, type QuotaStore, type QuotaView, type RecordToolCallInput, type RecordUsageInput, type RerankOptions, type Reranker, type RetrieveOptions, type Retriever, type RolesPolicy, type SinkWriter, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices };
|
|
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 };
|