@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 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,