@dudousxd/nestjs-agent-core 0.9.0 → 0.10.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 +117 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -2
- package/dist/index.d.ts +103 -2
- package/dist/index.js +111 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,8 @@ __export(index_exports, {
|
|
|
45
45
|
AGENT_TOOL_REGISTRY: () => AGENT_TOOL_REGISTRY,
|
|
46
46
|
AgentRegistry: () => AgentRegistry,
|
|
47
47
|
AgentStreamError: () => AgentStreamError,
|
|
48
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS: () => DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
49
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS: () => DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
48
50
|
DefaultRolesPolicy: () => DefaultRolesPolicy,
|
|
49
51
|
QuotaExceededError: () => QuotaExceededError,
|
|
50
52
|
ToolForbiddenError: () => ToolForbiddenError,
|
|
@@ -61,6 +63,8 @@ __export(index_exports, {
|
|
|
61
63
|
estimateCost: () => estimateCost,
|
|
62
64
|
filterToolsByAllowList: () => filterToolsByAllowList,
|
|
63
65
|
filterToolsByRole: () => filterToolsByRole,
|
|
66
|
+
invokeWithTransientRetry: () => invokeWithTransientRetry,
|
|
67
|
+
isTransientToolError: () => isTransientToolError,
|
|
64
68
|
publishAgentDelegated: () => publishAgentDelegated,
|
|
65
69
|
publishAgentMessage: () => publishAgentMessage,
|
|
66
70
|
publishAgentQuotaExceeded: () => publishAgentQuotaExceeded,
|
|
@@ -69,6 +73,8 @@ __export(index_exports, {
|
|
|
69
73
|
publishAgentRunFinished: () => publishAgentRunFinished,
|
|
70
74
|
publishAgentRunStarted: () => publishAgentRunStarted,
|
|
71
75
|
publishAgentToolCall: () => publishAgentToolCall,
|
|
76
|
+
publishAgentToolRetry: () => publishAgentToolRetry,
|
|
77
|
+
resolveToolTransientRetryNumbers: () => resolveToolTransientRetryNumbers,
|
|
72
78
|
runAgentLoop: () => runAgentLoop,
|
|
73
79
|
seedModelPrices: () => seedModelPrices,
|
|
74
80
|
traceLlmTurn: () => traceLlmTurn,
|
|
@@ -439,6 +445,10 @@ function publishAgentRetrieved(payload) {
|
|
|
439
445
|
(0, import_nestjs_diagnostics.emit)("agent", "retrieved", payload);
|
|
440
446
|
}
|
|
441
447
|
__name(publishAgentRetrieved, "publishAgentRetrieved");
|
|
448
|
+
function publishAgentToolRetry(payload) {
|
|
449
|
+
(0, import_nestjs_diagnostics.emit)("agent", "tool.retry", payload);
|
|
450
|
+
}
|
|
451
|
+
__name(publishAgentToolRetry, "publishAgentToolRetry");
|
|
442
452
|
var AGENT_SPAN_EVENTS = [
|
|
443
453
|
"llm.turn",
|
|
444
454
|
"tool.execution",
|
|
@@ -453,13 +463,96 @@ var AGENT_DIAGNOSTIC_EVENTS = [
|
|
|
453
463
|
"run.finished",
|
|
454
464
|
"run.failed",
|
|
455
465
|
"delegated",
|
|
456
|
-
"retrieved"
|
|
466
|
+
"retrieved",
|
|
467
|
+
"tool.retry"
|
|
457
468
|
];
|
|
458
469
|
function agentDiagnosticKey(event) {
|
|
459
470
|
return `agent:${event}`;
|
|
460
471
|
}
|
|
461
472
|
__name(agentDiagnosticKey, "agentDiagnosticKey");
|
|
462
473
|
|
|
474
|
+
// src/tool-retry.ts
|
|
475
|
+
function hasTransientShape(error) {
|
|
476
|
+
if (typeof error !== "object" || error === null) {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
const code = "code" in error ? error.code : void 0;
|
|
480
|
+
const errno = "errno" in error ? error.errno : void 0;
|
|
481
|
+
const sqlState = "sqlState" in error ? error.sqlState : void 0;
|
|
482
|
+
if (code === 1213 || code === 1205 || errno === 1213 || errno === 1205) {
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
if (code === "ER_LOCK_DEADLOCK" || code === "ER_LOCK_WAIT_TIMEOUT") {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
if (code === "40001" || code === "40P01" || sqlState === "40001" || sqlState === "40P01") {
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
if (code === "SQLITE_BUSY") {
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
const message = "message" in error ? error.message : void 0;
|
|
495
|
+
return typeof message === "string" && /deadlock|lock wait timeout|serialization failure/i.test(message);
|
|
496
|
+
}
|
|
497
|
+
__name(hasTransientShape, "hasTransientShape");
|
|
498
|
+
function isTransientToolError(error) {
|
|
499
|
+
if (hasTransientShape(error)) {
|
|
500
|
+
return true;
|
|
501
|
+
}
|
|
502
|
+
if (typeof error === "object" && error !== null && "cause" in error) {
|
|
503
|
+
const cause = error.cause;
|
|
504
|
+
if (cause !== void 0 && cause !== error && hasTransientShape(cause)) {
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
__name(isTransientToolError, "isTransientToolError");
|
|
511
|
+
var DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS = 2;
|
|
512
|
+
var DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS = 150;
|
|
513
|
+
function resolveToolTransientRetryNumbers(setting) {
|
|
514
|
+
if (setting === false) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
attempts: setting?.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
519
|
+
backoffMs: setting?.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
__name(resolveToolTransientRetryNumbers, "resolveToolTransientRetryNumbers");
|
|
523
|
+
function delay(ms) {
|
|
524
|
+
return new Promise((resolve) => {
|
|
525
|
+
setTimeout(resolve, ms);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
__name(delay, "delay");
|
|
529
|
+
async function invokeWithTransientRetry(fn, setting, options) {
|
|
530
|
+
if (setting === false) {
|
|
531
|
+
return fn();
|
|
532
|
+
}
|
|
533
|
+
const attempts = setting.attempts ?? DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS;
|
|
534
|
+
const backoffMs = setting.backoffMs ?? DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS;
|
|
535
|
+
const classify = setting.classify ?? isTransientToolError;
|
|
536
|
+
let attempt = 1;
|
|
537
|
+
for (; ; ) {
|
|
538
|
+
try {
|
|
539
|
+
return await fn();
|
|
540
|
+
} catch (error) {
|
|
541
|
+
if (options?.isControlFlowError?.(error) === true) {
|
|
542
|
+
throw error;
|
|
543
|
+
}
|
|
544
|
+
const attemptsRemain = attempt < attempts;
|
|
545
|
+
if (!attemptsRemain || !classify(error)) {
|
|
546
|
+
throw error;
|
|
547
|
+
}
|
|
548
|
+
options?.onRetry?.(attempt, error);
|
|
549
|
+
await delay(backoffMs * attempt);
|
|
550
|
+
attempt += 1;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
__name(invokeWithTransientRetry, "invokeWithTransientRetry");
|
|
555
|
+
|
|
463
556
|
// src/agent-loop.ts
|
|
464
557
|
function resolveCostUsd(usage, reportedCostUsd, price) {
|
|
465
558
|
if (reportedCostUsd !== void 0) {
|
|
@@ -1018,7 +1111,10 @@ ${buildContextBlock(passages)}`;
|
|
|
1018
1111
|
ctx: stepCtx,
|
|
1019
1112
|
...deps.toolTimeoutMs !== void 0 ? {
|
|
1020
1113
|
timeoutMs: deps.toolTimeoutMs
|
|
1021
|
-
} : {}
|
|
1114
|
+
} : {},
|
|
1115
|
+
// Numeric-only: the handler applies withToolTimeout AND its own local `classify` — see
|
|
1116
|
+
// ToolStepEnvelope.transientRetry.
|
|
1117
|
+
transientRetry: resolveToolTransientRetryNumbers(deps.toolTransientRetry)
|
|
1022
1118
|
};
|
|
1023
1119
|
output = await hooks.dispatchTool(call, envelope);
|
|
1024
1120
|
} else {
|
|
@@ -1026,7 +1122,19 @@ ${buildContextBlock(passages)}`;
|
|
|
1026
1122
|
toolCallId: call.id,
|
|
1027
1123
|
toolName: call.name,
|
|
1028
1124
|
toolType
|
|
1029
|
-
}, () => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy)
|
|
1125
|
+
}, () => invokeWithTransientRetry(() => deps.registry.invoke(call.name, call.input, ctx, deps.rolesPolicy), deps.toolTransientRetry ?? {}, {
|
|
1126
|
+
...hooks.isControlFlowError !== void 0 ? {
|
|
1127
|
+
isControlFlowError: hooks.isControlFlowError
|
|
1128
|
+
} : {},
|
|
1129
|
+
onRetry: /* @__PURE__ */ __name((attempt, retryError) => {
|
|
1130
|
+
publishAgentToolRetry({
|
|
1131
|
+
toolName: call.name,
|
|
1132
|
+
toolCallId: call.id,
|
|
1133
|
+
attempt,
|
|
1134
|
+
message: retryError instanceof Error ? retryError.message : String(retryError)
|
|
1135
|
+
});
|
|
1136
|
+
}, "onRetry")
|
|
1137
|
+
})));
|
|
1030
1138
|
output = deps.toolTimeoutMs !== void 0 ? await withToolTimeout(invocation, deps.toolTimeoutMs, call.name) : await invocation;
|
|
1031
1139
|
}
|
|
1032
1140
|
const executionMs = Date.now() - startedAt2;
|
|
@@ -1149,6 +1257,8 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
1149
1257
|
AGENT_TOOL_REGISTRY,
|
|
1150
1258
|
AgentRegistry,
|
|
1151
1259
|
AgentStreamError,
|
|
1260
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_ATTEMPTS,
|
|
1261
|
+
DEFAULT_TOOL_TRANSIENT_RETRY_BACKOFF_MS,
|
|
1152
1262
|
DefaultRolesPolicy,
|
|
1153
1263
|
QuotaExceededError,
|
|
1154
1264
|
ToolForbiddenError,
|
|
@@ -1165,6 +1275,8 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
1165
1275
|
estimateCost,
|
|
1166
1276
|
filterToolsByAllowList,
|
|
1167
1277
|
filterToolsByRole,
|
|
1278
|
+
invokeWithTransientRetry,
|
|
1279
|
+
isTransientToolError,
|
|
1168
1280
|
publishAgentDelegated,
|
|
1169
1281
|
publishAgentMessage,
|
|
1170
1282
|
publishAgentQuotaExceeded,
|
|
@@ -1173,6 +1285,8 @@ __name(runAgentLoop, "runAgentLoop");
|
|
|
1173
1285
|
publishAgentRunFinished,
|
|
1174
1286
|
publishAgentRunStarted,
|
|
1175
1287
|
publishAgentToolCall,
|
|
1288
|
+
publishAgentToolRetry,
|
|
1289
|
+
resolveToolTransientRetryNumbers,
|
|
1176
1290
|
runAgentLoop,
|
|
1177
1291
|
seedModelPrices,
|
|
1178
1292
|
traceLlmTurn,
|