@dudousxd/nestjs-agent-core 0.9.0 → 0.11.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 +157 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +252 -3
- package/dist/index.d.ts +252 -3
- package/dist/index.js +148 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
2
|
import { ChannelRegistry } from '@dudousxd/nestjs-diagnostics';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Transient tool-error classification + the retry loop that wraps a tool's own invocation. A
|
|
6
|
+
* classified-transient error (a DB deadlock, a lock-wait timeout, a serialization failure) means
|
|
7
|
+
* the server rolled the tool's work back — retrying THAT class is safe, unlike a tool's general
|
|
8
|
+
* business failure, which stays a one-shot outcome (no durable step retries: a tool may not be
|
|
9
|
+
* idempotent). See `runAgentLoop`'s `tool:<call.id>` step body and `AgentRunSteps.tool` — both wrap
|
|
10
|
+
* `registry.invoke(...)` with {@link invokeWithTransientRetry} so a retry never becomes a new
|
|
11
|
+
* checkpoint; history still shows exactly one step per tool call.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Default transient-tool-error classifier: true for a recognized MySQL/Postgres/SQLite
|
|
15
|
+
* lock-contention shape (by driver `code`/`errno`/`sqlState`, or a matching message), checked on
|
|
16
|
+
* the error itself and one level of `cause` (drivers commonly wrap the original error). A plain
|
|
17
|
+
* `Error` with none of these markers — any other business failure — is `false`.
|
|
18
|
+
*/
|
|
19
|
+
declare function isTransientToolError(error: unknown): boolean;
|
|
20
|
+
/** Total attempts (initial try + retries) when `toolTransientRetry` doesn't set `attempts`. */
|
|
21
|
+
declare const DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
|
|
22
|
+
/** Backoff base in ms — the wait between attempt N and N+1 is `backoffMs * N`. */
|
|
23
|
+
declare const DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
|
|
24
|
+
/** The host-configurable half of the policy — everything except the (non-wire-safe) `classify` fn. */
|
|
25
|
+
interface ToolTransientRetryOptions {
|
|
26
|
+
/** Total attempts (initial try + retries). Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS}. */
|
|
27
|
+
attempts?: number;
|
|
28
|
+
/** Backoff base in ms. Defaults to {@link DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS}. */
|
|
29
|
+
backoffMs?: number;
|
|
30
|
+
/** Overrides the default classifier — widen or narrow which errors are treated as transient. */
|
|
31
|
+
classify?: (error: unknown) => boolean;
|
|
32
|
+
}
|
|
33
|
+
/** `false` disables transient retry entirely — a tool's own thrown error surfaces immediately. */
|
|
34
|
+
type ToolTransientRetrySetting = ToolTransientRetryOptions | false;
|
|
35
|
+
/** Just the wire-safe (numeric) half of a resolved policy — what a dispatched envelope carries. */
|
|
36
|
+
interface ToolTransientRetryNumbers {
|
|
37
|
+
attempts: number;
|
|
38
|
+
backoffMs: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolves the numeric half of `toolTransientRetry` for the dispatched wire envelope: `false` when
|
|
42
|
+
* explicitly disabled, else concrete `{ attempts, backoffMs }` (defaults filled in) — never
|
|
43
|
+
* `undefined`, so the dispatched handler always gets a definite answer instead of re-deriving its
|
|
44
|
+
* own default. The `classify` function never rides this — it isn't wire-safe; the dispatched
|
|
45
|
+
* handler resolves its own `classify` from its local module options (see `AgentRunSteps.tool`).
|
|
46
|
+
*/
|
|
47
|
+
declare function resolveToolTransientRetryNumbers(setting: ToolTransientRetrySetting | undefined): ToolTransientRetryNumbers | false;
|
|
48
|
+
interface InvokeWithTransientRetryOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Recognizes the runner's control-flow signals (durable suspend / continue-as-new) so a retry
|
|
51
|
+
* never swallows one — same rule the loop's tool catch already applies. Undefined for a call site
|
|
52
|
+
* with no such notion (e.g. the dispatched step handler, which has no workflow ctx of its own).
|
|
53
|
+
*/
|
|
54
|
+
isControlFlowError?: (error: unknown) => boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Called before each wait-and-retry, with the 1-based ordinal of the attempt that just failed and
|
|
57
|
+
* the error it threw. The call site uses this to emit the `tool.retry` diagnostics point event —
|
|
58
|
+
* `invokeWithTransientRetry` itself carries no tool identity (name/callId), only the thunk.
|
|
59
|
+
*/
|
|
60
|
+
onRetry?: (attempt: number, error: unknown) => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Retries `fn` in place — never a new durable step/checkpoint, just repeated attempts inside
|
|
64
|
+
* whichever step body already wraps this call. `setting: false` runs `fn` once, unwrapped (no
|
|
65
|
+
* classify/backoff bookkeeping at all). Otherwise: try; on a thrown error, rethrow immediately if
|
|
66
|
+
* it's a recognized control-flow signal, else if the (possibly custom) classifier calls it
|
|
67
|
+
* transient AND attempts remain, wait `backoffMs * attemptNumber` and retry; otherwise rethrow the
|
|
68
|
+
* error as-is.
|
|
69
|
+
*/
|
|
70
|
+
declare function invokeWithTransientRetry<T>(fn: () => Promise<T>, setting: ToolTransientRetrySetting, options?: InvokeWithTransientRetryOptions): Promise<T>;
|
|
71
|
+
|
|
4
72
|
/** Who is driving the turn. Roles + tenant come from the host app (nestjs-context/authz). */
|
|
5
73
|
interface Actor {
|
|
6
74
|
id: string;
|
|
@@ -312,6 +380,15 @@ interface ToolStepEnvelope {
|
|
|
312
380
|
ctx: ToolStepCtx;
|
|
313
381
|
/** Applied INSIDE the handler (`withToolTimeout`) — never as a durable step `timeoutMs`. */
|
|
314
382
|
timeoutMs?: number;
|
|
383
|
+
/**
|
|
384
|
+
* The numeric half of `toolTransientRetry` (resolved by the loop from `AgentLoopDeps`, always a
|
|
385
|
+
* definite value — `false` when disabled, else concrete `{ attempts, backoffMs }` with defaults
|
|
386
|
+
* already filled in) — never `undefined`, so the dispatched handler gets the SAME policy the
|
|
387
|
+
* loop would have used locally. The `classify` function is deliberately absent: it isn't
|
|
388
|
+
* wire-safe, so the handler resolves its own from its local module options (see
|
|
389
|
+
* `AgentRunSteps.tool`) instead of trying to serialize a function.
|
|
390
|
+
*/
|
|
391
|
+
transientRetry: ToolTransientRetryNumbers | false;
|
|
315
392
|
}
|
|
316
393
|
|
|
317
394
|
/**
|
|
@@ -967,6 +1044,13 @@ interface ToolStatRow {
|
|
|
967
1044
|
calls: number;
|
|
968
1045
|
failed: number;
|
|
969
1046
|
rejected: number;
|
|
1047
|
+
/**
|
|
1048
|
+
* p50 (median) of executionMs across calls that recorded one; null when none carry it. Reported
|
|
1049
|
+
* alongside p95 rather than a mean: tool latency is long-tailed (a retry or a slow upstream drags
|
|
1050
|
+
* an average somewhere no single call ever was), so the pair "typical / tail" is what an operator
|
|
1051
|
+
* can actually act on.
|
|
1052
|
+
*/
|
|
1053
|
+
p50ExecutionMs: number | null;
|
|
970
1054
|
/** p95 of executionMs across executed calls; null when none carry it. */
|
|
971
1055
|
p95ExecutionMs: number | null;
|
|
972
1056
|
}
|
|
@@ -1018,6 +1102,115 @@ interface RunWhere {
|
|
|
1018
1102
|
fromDay?: string;
|
|
1019
1103
|
toDay?: string;
|
|
1020
1104
|
}
|
|
1105
|
+
/** Filters for {@link AgentGovernanceQueries.approvalsPage}. */
|
|
1106
|
+
interface ApprovalWhere {
|
|
1107
|
+
toolName?: string;
|
|
1108
|
+
threadId?: string;
|
|
1109
|
+
/** The requesting thread's owner. */
|
|
1110
|
+
actorRef?: string;
|
|
1111
|
+
agentName?: string;
|
|
1112
|
+
/** Inclusive UTC day bounds on when the approval was requested, `YYYY-MM-DD`. */
|
|
1113
|
+
fromDay?: string;
|
|
1114
|
+
toDay?: string;
|
|
1115
|
+
}
|
|
1116
|
+
/** One tool call inside a {@link GovernanceRunDetail}, with the execution outcome a list row can't afford to carry. */
|
|
1117
|
+
interface RunToolCallRow {
|
|
1118
|
+
toolCallId: string;
|
|
1119
|
+
toolName: string;
|
|
1120
|
+
toolType: string;
|
|
1121
|
+
status: string;
|
|
1122
|
+
/** Wall time of the execution; null for a call that never executed (rejected/still pending). */
|
|
1123
|
+
executionMs: number | null;
|
|
1124
|
+
/** Who executed/decided it, when the store recorded an attribution. */
|
|
1125
|
+
executedByRef: string | null;
|
|
1126
|
+
/** The failure text for a `failed` call; null otherwise. */
|
|
1127
|
+
error: string | null;
|
|
1128
|
+
/** ISO timestamp. */
|
|
1129
|
+
createdAt: string;
|
|
1130
|
+
}
|
|
1131
|
+
/** The owning thread's headline, carried on a drill-down so it can be named without a second read. */
|
|
1132
|
+
interface DetailThreadRef {
|
|
1133
|
+
threadId: string;
|
|
1134
|
+
title: string;
|
|
1135
|
+
actorRef: string;
|
|
1136
|
+
/** True when the thread is soft-deleted — its history is still readable, the thread is not. */
|
|
1137
|
+
deleted: boolean;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Everything a run drill-down renders: the run row itself, its owning thread's headline, and the
|
|
1141
|
+
* tool calls attributed to it.
|
|
1142
|
+
*
|
|
1143
|
+
* `toolCalls` is empty for a run recorded before tool calls carried a `runId` (the column is
|
|
1144
|
+
* nullable and pre-rollout rows have none) — indistinguishable, from here, from a run that called
|
|
1145
|
+
* no tools. There is deliberately no cost figure: the token ledger has no run column, so per-run
|
|
1146
|
+
* spend is not attributable without a store migration.
|
|
1147
|
+
*/
|
|
1148
|
+
interface GovernanceRunDetail {
|
|
1149
|
+
run: RecentRunRow;
|
|
1150
|
+
thread: DetailThreadRef;
|
|
1151
|
+
/** The run's tool calls, oldest first — the order they were requested in. */
|
|
1152
|
+
toolCalls: RunToolCallRow[];
|
|
1153
|
+
}
|
|
1154
|
+
/** One message inside a {@link GovernanceThreadDetail}. `content` is capped server-side. */
|
|
1155
|
+
interface ThreadMessageRow {
|
|
1156
|
+
messageId: string;
|
|
1157
|
+
role: string;
|
|
1158
|
+
/** Message text, cut to {@link THREAD_DETAIL_CONTENT_CHARS}; see `truncated`. */
|
|
1159
|
+
content: string;
|
|
1160
|
+
/** True when `content` was cut — the console shows an explicit "…" rather than implying the tail. */
|
|
1161
|
+
truncated: boolean;
|
|
1162
|
+
agentName: string | null;
|
|
1163
|
+
/** How many tool calls this message requested. */
|
|
1164
|
+
toolCallCount: number;
|
|
1165
|
+
/** ISO timestamp. */
|
|
1166
|
+
createdAt: string;
|
|
1167
|
+
}
|
|
1168
|
+
/** Token/cost rollup across a thread's whole ledger (not range-scoped — a thread's lifetime). */
|
|
1169
|
+
interface ThreadUsageRollup {
|
|
1170
|
+
/** Ledger rows, i.e. billed turns. */
|
|
1171
|
+
requests: number;
|
|
1172
|
+
inputTokens: number;
|
|
1173
|
+
outputTokens: number;
|
|
1174
|
+
totalTokens: number;
|
|
1175
|
+
costUsd: number;
|
|
1176
|
+
}
|
|
1177
|
+
/** Everything a thread drill-down renders, in one call. */
|
|
1178
|
+
interface GovernanceThreadDetail {
|
|
1179
|
+
/** The thread's own activity row (`messageCount` is the thread total, not the page below). */
|
|
1180
|
+
thread: ThreadActivityRow;
|
|
1181
|
+
/** True when the thread is soft-deleted. */
|
|
1182
|
+
deleted: boolean;
|
|
1183
|
+
usage: ThreadUsageRollup;
|
|
1184
|
+
/** The thread's runs, newest first, capped at the query's `runLimit`. */
|
|
1185
|
+
runs: RecentRunRow[];
|
|
1186
|
+
/** Runs on this thread in total — `runs.length < runTotal` means the cap bit. */
|
|
1187
|
+
runTotal: number;
|
|
1188
|
+
/** The thread's messages, newest first, capped at the query's `messageLimit`. */
|
|
1189
|
+
messages: ThreadMessageRow[];
|
|
1190
|
+
}
|
|
1191
|
+
/** Row caps for {@link AgentGovernanceQueries.threadDetail}, already clamped by the caller. */
|
|
1192
|
+
interface GovernanceThreadDetailQuery {
|
|
1193
|
+
threadId: string;
|
|
1194
|
+
/** Max messages returned, newest first. */
|
|
1195
|
+
messageLimit: number;
|
|
1196
|
+
/** Max runs returned, newest first. */
|
|
1197
|
+
runLimit: number;
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Per-message content cap for {@link ThreadMessageRow.content}. A drill-down is a triage view, not a
|
|
1201
|
+
* transcript reader: capping here keeps one response bounded regardless of how long an assistant
|
|
1202
|
+
* turn ran. Shared by every adapter so the cut is identical wherever the console is served from.
|
|
1203
|
+
*/
|
|
1204
|
+
declare const THREAD_DETAIL_CONTENT_CHARS = 2000;
|
|
1205
|
+
/**
|
|
1206
|
+
* Cut a message body to {@link THREAD_DETAIL_CONTENT_CHARS}, reporting whether it was cut. Lives
|
|
1207
|
+
* next to the cap so every adapter truncates at the same boundary — a console comparing two stores
|
|
1208
|
+
* must not see two different "…".
|
|
1209
|
+
*/
|
|
1210
|
+
declare function truncateDetailContent(content: string): {
|
|
1211
|
+
content: string;
|
|
1212
|
+
truncated: boolean;
|
|
1213
|
+
};
|
|
1021
1214
|
/**
|
|
1022
1215
|
* The governance read-model. Cost is `inputTokens/1e6 * inputPricePer1m + outputTokens/1e6 *
|
|
1023
1216
|
* outputPricePer1m` against the current pricing row per model; an unpriced model contributes 0 cost
|
|
@@ -1036,8 +1229,19 @@ interface AgentGovernanceQueries {
|
|
|
1036
1229
|
runErrors(range: GovernanceRange): Promise<RunErrorBreakdownRow[]>;
|
|
1037
1230
|
runTrend(range: GovernanceRange): Promise<RunTrendPoint[]>;
|
|
1038
1231
|
recentRuns(limit: number): Promise<RecentRunRow[]>;
|
|
1039
|
-
/**
|
|
1232
|
+
/**
|
|
1233
|
+
* Tool calls sitting `pending_approval`, oldest first — an inbox drains from the back. Capped at
|
|
1234
|
+
* `limit`, with NO total: a caller that needs to know whether the cap hid anything wants
|
|
1235
|
+
* {@link approvalsPage} instead.
|
|
1236
|
+
*/
|
|
1040
1237
|
pendingApprovals(limit: number): Promise<PendingApprovalRow[]>;
|
|
1238
|
+
/**
|
|
1239
|
+
* Paged, filterable approvals inbox, oldest first (same ordering as `pendingApprovals`). Unlike
|
|
1240
|
+
* that method this reports `total`, so a console can page a backlog and say how much of it is
|
|
1241
|
+
* off-screen — the one failure this surface cannot afford is a pending approval nobody sees.
|
|
1242
|
+
* An adapter without the backing data returns an empty page (`total: 0`) rather than throwing.
|
|
1243
|
+
*/
|
|
1244
|
+
approvalsPage(query: GovernancePageQuery<ApprovalWhere>): Promise<GovernancePage<PendingApprovalRow>>;
|
|
1041
1245
|
/** Per-tool call/failure/rejection/latency rollup over the range, highest call count first. */
|
|
1042
1246
|
toolStats(range: GovernanceRange): Promise<ToolStatRow[]>;
|
|
1043
1247
|
/**
|
|
@@ -1055,6 +1259,21 @@ interface AgentGovernanceQueries {
|
|
|
1055
1259
|
* by a store without run recording (no `recordRunStart`) returns an empty page (`total: 0`).
|
|
1056
1260
|
*/
|
|
1057
1261
|
runsPage(query: GovernancePageQuery<RunWhere>): Promise<GovernancePage<RecentRunRow>>;
|
|
1262
|
+
/**
|
|
1263
|
+
* One run with its owning thread and its tool calls — the drill-down behind a row in the runs
|
|
1264
|
+
* table. `null` when no run has that id. ONE call, not one per tool call: a failed run is the
|
|
1265
|
+
* thing an operator opens first and it should not cost a query per step.
|
|
1266
|
+
*
|
|
1267
|
+
* An adapter backed by a store without run recording returns `null` for every id.
|
|
1268
|
+
*/
|
|
1269
|
+
runDetail(runId: string): Promise<GovernanceRunDetail | null>;
|
|
1270
|
+
/**
|
|
1271
|
+
* One thread with its lifetime usage rollup, its recent runs and its recent messages — the
|
|
1272
|
+
* drill-down behind a row in the threads table. `null` when no thread has that id; a soft-deleted
|
|
1273
|
+
* thread IS returned (with `deleted: true`), because "what did the thread we just deleted do" is
|
|
1274
|
+
* exactly the question an audit asks.
|
|
1275
|
+
*/
|
|
1276
|
+
threadDetail(query: GovernanceThreadDetailQuery): Promise<GovernanceThreadDetail | null>;
|
|
1058
1277
|
}
|
|
1059
1278
|
|
|
1060
1279
|
/**
|
|
@@ -1171,6 +1390,12 @@ declare function bucketByThread(rows: GovernanceUsageInput[], prices: ReadonlyMa
|
|
|
1171
1390
|
limit: number;
|
|
1172
1391
|
includeUnknownThreads: boolean;
|
|
1173
1392
|
}): ThreadSpendRow[];
|
|
1393
|
+
/**
|
|
1394
|
+
* Sum an already-scoped set of usage rows into one rollup — the thread drill-down's headline. Same
|
|
1395
|
+
* `rowCost` as every bucketer above (provider-reported cost wins, else the cache-aware estimate), so
|
|
1396
|
+
* a thread's detail cost and its row in the by-thread ranking can never disagree.
|
|
1397
|
+
*/
|
|
1398
|
+
declare function rollupThreadUsage(rows: GovernanceUsageInput[], prices: ReadonlyMap<string, ModelPrice>): ThreadUsageRollup;
|
|
1174
1399
|
/** Aggregate usage rows into a daily token/cost trend, ascending by day. */
|
|
1175
1400
|
declare function bucketUsageTrend(rows: GovernanceUsageInput[], prices: ReadonlyMap<string, ModelPrice>): UsageTrendPoint[];
|
|
1176
1401
|
/** Turn an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used to filter usage rows. */
|
|
@@ -1266,6 +1491,16 @@ interface AgentLoopDeps {
|
|
|
1266
1491
|
* Undefined → no timeout.
|
|
1267
1492
|
*/
|
|
1268
1493
|
toolTimeoutMs?: number;
|
|
1494
|
+
/**
|
|
1495
|
+
* Retries a tool's own invocation, in place, when it throws a classified-transient error (a DB
|
|
1496
|
+
* deadlock, a lock-wait timeout, a serialization failure — see `isTransientToolError`) — never a
|
|
1497
|
+
* new durable step/checkpoint, just repeated attempts inside the same `tool:<call.id>` step body.
|
|
1498
|
+
* Default ON (`{ attempts: 2, backoffMs: 150 }` with the default classifier) when undefined; set
|
|
1499
|
+
* `{ classify }` to widen/narrow which errors count as transient, or `false` to disable entirely.
|
|
1500
|
+
* A tool's other (non-transient) failures are unaffected — they remain a one-shot business
|
|
1501
|
+
* outcome, exactly as before.
|
|
1502
|
+
*/
|
|
1503
|
+
toolTransientRetry?: ToolTransientRetrySetting;
|
|
1269
1504
|
/**
|
|
1270
1505
|
* When set, after the final turn the loop makes one extra model call to propose up to this many
|
|
1271
1506
|
* short follow-up questions, stored on the assistant message's `followUps`. Costs an extra call
|
|
@@ -1406,6 +1641,18 @@ interface AgentRetrieved {
|
|
|
1406
1641
|
/** How many passages the retriever returned. */
|
|
1407
1642
|
count: number;
|
|
1408
1643
|
}
|
|
1644
|
+
/**
|
|
1645
|
+
* A transient-classified tool error being retried in place (no new checkpoint) — see
|
|
1646
|
+
* `invokeWithTransientRetry`. Emitted once per retry (not for the final, non-retried outcome).
|
|
1647
|
+
*/
|
|
1648
|
+
interface AgentToolRetry {
|
|
1649
|
+
toolName: string;
|
|
1650
|
+
toolCallId: string;
|
|
1651
|
+
/** 1-based ordinal of the attempt that just failed and is about to be retried. */
|
|
1652
|
+
attempt: number;
|
|
1653
|
+
/** The failed attempt's error message. */
|
|
1654
|
+
message: string;
|
|
1655
|
+
}
|
|
1409
1656
|
/** START payload of an `aviary:agent:llm.turn:*` span — one model call within a run. */
|
|
1410
1657
|
interface AgentLlmTurnSpan {
|
|
1411
1658
|
runId: string;
|
|
@@ -1446,6 +1693,7 @@ declare module '@dudousxd/nestjs-diagnostics' {
|
|
|
1446
1693
|
'run.failed': AgentRunFailed;
|
|
1447
1694
|
delegated: AgentDelegated;
|
|
1448
1695
|
retrieved: AgentRetrieved;
|
|
1696
|
+
'tool.retry': AgentToolRetry;
|
|
1449
1697
|
'llm.turn': AgentLlmTurnSpan;
|
|
1450
1698
|
'tool.execution': AgentToolExecutionSpan;
|
|
1451
1699
|
retrieval: AgentRetrievalSpan;
|
|
@@ -1461,6 +1709,7 @@ declare function publishAgentRunFinished(payload: AgentRunFinished): void;
|
|
|
1461
1709
|
declare function publishAgentRunFailed(payload: AgentRunFailed): void;
|
|
1462
1710
|
declare function publishAgentDelegated(payload: AgentDelegated): void;
|
|
1463
1711
|
declare function publishAgentRetrieved(payload: AgentRetrieved): void;
|
|
1712
|
+
declare function publishAgentToolRetry(payload: AgentToolRetry): void;
|
|
1464
1713
|
/**
|
|
1465
1714
|
* Events published ONLY as spans — via `trace('agent', ...)` on the five `:start`/`:end`/
|
|
1466
1715
|
* `:asyncStart`/`:asyncEnd`/`:error` sub-channels — never as point events on the base channel.
|
|
@@ -1474,7 +1723,7 @@ declare const AGENT_SPAN_EVENTS: readonly AgentSpanEvent[];
|
|
|
1474
1723
|
/** Every POINT event key declared on `ChannelRegistry['agent']` above — derived, not hand-copied. */
|
|
1475
1724
|
type AgentDiagnosticEvent = Exclude<keyof ChannelRegistry['agent'], AgentSpanEvent>;
|
|
1476
1725
|
/**
|
|
1477
|
-
* All
|
|
1726
|
+
* All 9 point events on `ChannelRegistry['agent']`, in a stable order — handy for wiring
|
|
1478
1727
|
* subscribers (mirrors nestjs-media's `MEDIA_DIAGNOSTIC_EVENTS`). Span-only events (see
|
|
1479
1728
|
* {@link AgentSpanEvent}) are excluded. A drift between this list and the registry is a compile
|
|
1480
1729
|
* error in both directions: an extra/misspelled entry fails this array's own
|
|
@@ -1496,4 +1745,4 @@ type AgentDiagnosticKey = `agent:${AgentDiagnosticEvent}`;
|
|
|
1496
1745
|
*/
|
|
1497
1746
|
declare function agentDiagnosticKey(event: AgentDiagnosticEvent): AgentDiagnosticKey;
|
|
1498
1747
|
|
|
1499
|
-
export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, 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_SPAN_EVENTS, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorDirectory, type ActorResolver, type ActorSpendRow, type AgentApprovalPort, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentDiagnosticEvent, type AgentDiagnosticKey, type AgentFollowUpsSpan, type AgentGovernanceQueries, type AgentLlmTurnSpan, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrievalSpan, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentSpanEvent, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AgentToolExecutionSpan, type AiToolCtx, type AppendMessageInput, type AttachmentStagingStore, type CostUsage, type CreateThreadInput, type CurrentModelPrice, type Decision, DefaultRolesPolicy, type EmbeddingProvider, type GovernancePage, type GovernancePageQuery, 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 PendingApprovalRow, 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 RunWhere, type SinkWriter, type StageAttachmentInput, type StoredMessage, type StreamError, type ThreadActivityRow, type ThreadDetail, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type ThreadWhere, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolCallWhere, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type ToolStatRow, type ToolStepCtx, type ToolStepEnvelope, type UpdateThreadInput, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, agentDiagnosticKey, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, runAgentLoop, seedModelPrices, traceLlmTurn, traceToolExecution, withToolTimeout };
|
|
1748
|
+
export { AGENT_ACTOR_DIRECTORY, AGENT_ACTOR_RESOLVER, AGENT_APPROVAL_PORT, AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_DIAGNOSTIC_EVENTS, 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_SPAN_EVENTS, AGENT_STORE, AGENT_TOOL_REGISTRY, type Actor, type ActorDirectory, type ActorResolver, type ActorSpendRow, type AgentApprovalPort, type AgentCatalogEntry, type AgentDefinition, type AgentDelegated, type AgentDiagnosticEvent, type AgentDiagnosticKey, type AgentFollowUpsSpan, type AgentGovernanceQueries, type AgentLlmTurnSpan, type AgentLoopDeps, type AgentLoopHooks, type AgentMessageEvent, type AgentPricingStore, type AgentQuotaExceeded, AgentRegistry, type AgentRetrievalSpan, type AgentRetrieved, type AgentRunFailed, type AgentRunFinished, type AgentRunInput, type AgentRunStarted, type AgentRunner, type AgentSpanEvent, type AgentStore, AgentStreamError, type AgentStreamEvent, type AgentToolCallEvent, type AgentToolExecutionSpan, type AgentToolRetry, type AiToolCtx, type AppendMessageInput, type ApprovalWhere, type AttachmentStagingStore, type CostUsage, type CreateThreadInput, type CurrentModelPrice, DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS, DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS, type Decision, DefaultRolesPolicy, type DetailThreadRef, type EmbeddingProvider, type GovernancePage, type GovernancePageQuery, type GovernanceRange, type GovernanceRunDetail, type GovernanceThreadDetail, type GovernanceThreadDetailQuery, type GovernanceUsageInput, type InvokeWithTransientRetryOptions, 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 PendingApprovalRow, 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 RunToolCallRow, type RunTrendPoint, type RunWhere, type SinkWriter, type StageAttachmentInput, type StoredMessage, type StreamError, THREAD_DETAIL_CONTENT_CHARS, type ThreadActivityRow, type ThreadDetail, type ThreadMessageRow, type ThreadMeta, type ThreadSpendRow, type ThreadSummary, type ThreadUsageRollup, type ThreadWhere, type TokenStreamSink, type ToolCallActivityRow, type ToolCallRequest, type ToolCallStatus, type ToolCallWhere, type ToolDefinition, ToolForbiddenError, type ToolHandler, ToolInputInvalidError, type ToolKind, ToolNotFoundError, ToolRegistry, type ToolResult, type ToolSpec, type ToolStatRow, type ToolStepCtx, type ToolStepEnvelope, type ToolTransientRetryNumbers, type ToolTransientRetryOptions, type ToolTransientRetrySetting, type UpdateThreadInput, type UpdateToolCallInput, type UsagePurpose, type UsageTrendPoint, agentDiagnosticKey, bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, encodeStreamEvent, estimateCost, filterToolsByAllowList, filterToolsByRole, invokeWithTransientRetry, isTransientToolError, publishAgentDelegated, publishAgentMessage, publishAgentQuotaExceeded, publishAgentRetrieved, publishAgentRunFailed, publishAgentRunFinished, publishAgentRunStarted, publishAgentToolCall, publishAgentToolRetry, resolveToolTransientRetryNumbers, rollupThreadUsage, runAgentLoop, seedModelPrices, traceLlmTurn, traceToolExecution, truncateDetailContent, withToolTimeout };
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,22 @@ async function seedModelPrices(store, prices) {
|
|
|
52
52
|
}
|
|
53
53
|
__name(seedModelPrices, "seedModelPrices");
|
|
54
54
|
|
|
55
|
+
// src/spi/governance-queries.ts
|
|
56
|
+
var THREAD_DETAIL_CONTENT_CHARS = 2e3;
|
|
57
|
+
function truncateDetailContent(content) {
|
|
58
|
+
if (content.length <= THREAD_DETAIL_CONTENT_CHARS) {
|
|
59
|
+
return {
|
|
60
|
+
content,
|
|
61
|
+
truncated: false
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
content: content.slice(0, THREAD_DETAIL_CONTENT_CHARS),
|
|
66
|
+
truncated: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
__name(truncateDetailContent, "truncateDetailContent");
|
|
70
|
+
|
|
55
71
|
// src/governance/compute.ts
|
|
56
72
|
function estimateCost(usage, price) {
|
|
57
73
|
if (price === void 0) {
|
|
@@ -157,6 +173,24 @@ function bucketByThread(rows, prices, threads, options) {
|
|
|
157
173
|
return result.slice(0, options.limit);
|
|
158
174
|
}
|
|
159
175
|
__name(bucketByThread, "bucketByThread");
|
|
176
|
+
function rollupThreadUsage(rows, prices) {
|
|
177
|
+
const rollup = {
|
|
178
|
+
requests: 0,
|
|
179
|
+
inputTokens: 0,
|
|
180
|
+
outputTokens: 0,
|
|
181
|
+
totalTokens: 0,
|
|
182
|
+
costUsd: 0
|
|
183
|
+
};
|
|
184
|
+
for (const row of rows) {
|
|
185
|
+
rollup.requests += 1;
|
|
186
|
+
rollup.inputTokens += row.inputTokens;
|
|
187
|
+
rollup.outputTokens += row.outputTokens;
|
|
188
|
+
rollup.totalTokens += row.inputTokens + row.outputTokens;
|
|
189
|
+
rollup.costUsd += rowCost(row, prices);
|
|
190
|
+
}
|
|
191
|
+
return rollup;
|
|
192
|
+
}
|
|
193
|
+
__name(rollupThreadUsage, "rollupThreadUsage");
|
|
160
194
|
function bucketUsageTrend(rows, prices) {
|
|
161
195
|
const byDay = /* @__PURE__ */ new Map();
|
|
162
196
|
for (const row of rows) {
|
|
@@ -363,6 +397,10 @@ function publishAgentRetrieved(payload) {
|
|
|
363
397
|
emit("agent", "retrieved", payload);
|
|
364
398
|
}
|
|
365
399
|
__name(publishAgentRetrieved, "publishAgentRetrieved");
|
|
400
|
+
function publishAgentToolRetry(payload) {
|
|
401
|
+
emit("agent", "tool.retry", payload);
|
|
402
|
+
}
|
|
403
|
+
__name(publishAgentToolRetry, "publishAgentToolRetry");
|
|
366
404
|
var AGENT_SPAN_EVENTS = [
|
|
367
405
|
"llm.turn",
|
|
368
406
|
"tool.execution",
|
|
@@ -377,13 +415,96 @@ var AGENT_DIAGNOSTIC_EVENTS = [
|
|
|
377
415
|
"run.finished",
|
|
378
416
|
"run.failed",
|
|
379
417
|
"delegated",
|
|
380
|
-
"retrieved"
|
|
418
|
+
"retrieved",
|
|
419
|
+
"tool.retry"
|
|
381
420
|
];
|
|
382
421
|
function agentDiagnosticKey(event) {
|
|
383
422
|
return `agent:${event}`;
|
|
384
423
|
}
|
|
385
424
|
__name(agentDiagnosticKey, "agentDiagnosticKey");
|
|
386
425
|
|
|
426
|
+
// src/tool-retry.ts
|
|
427
|
+
function hasTransientShape(error) {
|
|
428
|
+
if (typeof error !== "object" || error === null) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
const code = "code" in error ? error.code : void 0;
|
|
432
|
+
const errno = "errno" in error ? error.errno : void 0;
|
|
433
|
+
const sqlState = "sqlState" in error ? error.sqlState : void 0;
|
|
434
|
+
if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
if (code === "ER_LOCK_DEADLOCK" || code === "ER_LOCK_WAIT_TIMEOUT") {
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
if (code === "40001" || code === "40P01" || sqlState === "40001" || sqlState === "40P01") {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
if (code === "SQLITE_BUSY") {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
const message = "message" in error ? error.message : void 0;
|
|
447
|
+
return typeof message === "string" && /deadlock|lock wait timeout|serialization failure/i.test(message);
|
|
448
|
+
}
|
|
449
|
+
__name(hasTransientShape, "hasTransientShape");
|
|
450
|
+
function isTransientToolError(error) {
|
|
451
|
+
if (hasTransientShape(error)) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
if (typeof error === "object" && error !== null && "cause" in error) {
|
|
455
|
+
const cause = error.cause;
|
|
456
|
+
if (cause !== void 0 && cause !== error && hasTransientShape(cause)) {
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
__name(isTransientToolError, "isTransientToolError");
|
|
463
|
+
var DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
|
|
464
|
+
var DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
|
|
465
|
+
function resolveToolTransientRetryNumbers(setting) {
|
|
466
|
+
if (setting === false) {
|
|
467
|
+
return false;
|
|
468
|
+
}
|
|
469
|
+
return {
|
|
470
|
+
attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
471
|
+
backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
__name(resolveToolTransientRetryNumbers, "resolveToolTransientRetryNumbers");
|
|
475
|
+
function delay(ms) {
|
|
476
|
+
return new Promise((resolve) => {
|
|
477
|
+
setTimeout(resolve, ms);
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
__name(delay, "delay");
|
|
481
|
+
async function invokeWithTransientRetry(fn, setting, options) {
|
|
482
|
+
if (setting === false) {
|
|
483
|
+
return fn();
|
|
484
|
+
}
|
|
485
|
+
const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;
|
|
486
|
+
const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;
|
|
487
|
+
const classify = setting.classify ?? isTransientToolError;
|
|
488
|
+
let attempt = 1;
|
|
489
|
+
for (; ; ) {
|
|
490
|
+
try {
|
|
491
|
+
return await fn();
|
|
492
|
+
} catch (error) {
|
|
493
|
+
if (options?.isControlFlowError?.(error) === true) {
|
|
494
|
+
throw error;
|
|
495
|
+
}
|
|
496
|
+
const attemptsRemain = attempt < attempts;
|
|
497
|
+
if (!attemptsRemain || !classify(error)) {
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
500
|
+
options?.onRetry?.(attempt, error);
|
|
501
|
+
await delay(backoffMs * attempt);
|
|
502
|
+
attempt += 1;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
__name(invokeWithTransientRetry, "invokeWithTransientRetry");
|
|
507
|
+
|
|
387
508
|
// src/agent-loop.ts
|
|
388
509
|
function resolveCostUsd(usage, reportedCostUsd, price) {
|
|
389
510
|
if (reportedCostUsd !== void 0) {
|
|
@@ -942,7 +1063,10 @@ ${buildContextBlock(passages)}`;
|
|
|
942
1063
|
ctx: stepCtx,
|
|
943
1064
|
...deps.toolTimeoutMs !== void 0 ? {
|
|
944
1065
|
timeoutMs: deps.toolTimeoutMs
|
|
945
|
-
} : {}
|
|
1066
|
+
} : {},
|
|
1067
|
+
// Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see
|
|
1068
|
+
// ToolStepEnvelope.transientRetry.
|
|
1069
|
+
transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry)
|
|
946
1070
|
};
|
|
947
1071
|
output = await hooks.dispatchTool(call, envelope);
|
|
948
1072
|
} else {
|
|
@@ -950,7 +1074,19 @@ ${buildContextBlock(passages)}`;
|
|
|
950
1074
|
toolCallId: call.id,
|
|
951
1075
|
toolName: call.name,
|
|
952
1076
|
toolType
|
|
953
|
-
}, () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy)
|
|
1077
|
+
}, () => invokeWithTransientRetry(() => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy), deps.toolTransientRetry ?? {}, {
|
|
1078
|
+
...hooks.isControlFlowError !== void 0 ? {
|
|
1079
|
+
isControlFlowError: hooks.isControlFlowError
|
|
1080
|
+
} : {},
|
|
1081
|
+
onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
|
|
1082
|
+
publishAgentToolRetry({
|
|
1083
|
+
toolName: call.name,
|
|
1084
|
+
toolCallId: call.id,
|
|
1085
|
+
attempt,
|
|
1086
|
+
message: retryError instanceof Error ? retryError.message : String(retryError)
|
|
1087
|
+
});
|
|
1088
|
+
}, "onRetry")
|
|
1089
|
+
})));
|
|
954
1090
|
output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
955
1091
|
}
|
|
956
1092
|
const executionMs = Date.now() - startedAt2;
|
|
@@ -1072,8 +1208,11 @@ export {
|
|
|
1072
1208
|
AGENT_TOOL_REGISTRY,
|
|
1073
1209
|
AgentRegistry,
|
|
1074
1210
|
AgentStreamError,
|
|
1211
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
1212
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
1075
1213
|
DefaultRolesPolicy,
|
|
1076
1214
|
QuotaExceededError,
|
|
1215
|
+
THREAD_DETAIL_CONTENT_CHARS,
|
|
1077
1216
|
ToolForbiddenError,
|
|
1078
1217
|
ToolInputInvalidError,
|
|
1079
1218
|
ToolNotFoundError,
|
|
@@ -1088,6 +1227,8 @@ export {
|
|
|
1088
1227
|
estimateCost,
|
|
1089
1228
|
filterToolsByAllowList,
|
|
1090
1229
|
filterToolsByRole,
|
|
1230
|
+
invokeWithTransientRetry,
|
|
1231
|
+
isTransientToolError,
|
|
1091
1232
|
publishAgentDelegated,
|
|
1092
1233
|
publishAgentMessage,
|
|
1093
1234
|
publishAgentQuotaExceeded,
|
|
@@ -1096,10 +1237,14 @@ export {
|
|
|
1096
1237
|
publishAgentRunFinished,
|
|
1097
1238
|
publishAgentRunStarted,
|
|
1098
1239
|
publishAgentToolCall,
|
|
1240
|
+
publishAgentToolRetry,
|
|
1241
|
+
resolveToolTransientRetryNumbers,
|
|
1242
|
+
rollupThreadUsage,
|
|
1099
1243
|
runAgentLoop,
|
|
1100
1244
|
seedModelPrices,
|
|
1101
1245
|
traceLlmTurn,
|
|
1102
1246
|
traceToolExecution,
|
|
1247
|
+
truncateDetailContent,
|
|
1103
1248
|
withToolTimeout
|
|
1104
1249
|
};
|
|
1105
1250
|
//# sourceMappingURL=index.js.map
|