@dudousxd/nestjs-agent 0.8.2 → 0.9.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.
@@ -1,4 +1,4 @@
1
- import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Retriever, AgentPricingStore, ToolSpec, ToolHandler, ActorResolver, AgentRegistry } from '@dudousxd/nestjs-agent-core';
1
+ import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, ToolSpec, ToolHandler, ActorResolver, AgentRegistry } from '@dudousxd/nestjs-agent-core';
2
2
  import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
3
3
 
4
4
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -19,6 +19,11 @@ interface AgentDeps {
19
19
  toolAllowList?: string[];
20
20
  /** Per-tool execution timeout in ms (from module options). Undefined → no timeout. */
21
21
  toolTimeoutMs?: number;
22
+ /**
23
+ * Transient-tool-error retry policy (from module options). Undefined → default ON
24
+ * (`{ attempts: 2, backoffMs: 150 }` with the default classifier); `false` → disabled.
25
+ */
26
+ toolTransientRetry?: ToolTransientRetrySetting;
22
27
  /** How many follow-up suggestions to generate after the final turn. Undefined/0 → off. */
23
28
  followUpsCount?: number;
24
29
  /** Inject-mode retriever (from `forRoot({ retrieval })`). Undefined → no prompt augmentation. */
@@ -138,6 +143,16 @@ interface AgentModuleOptions {
138
143
  * model receives the timeout as its result and can adapt) instead of hanging the turn. Omit → none.
139
144
  */
140
145
  toolTimeoutMs?: number;
146
+ /**
147
+ * Retries a tool's own invocation, in place, when it throws a classified-transient error (a DB
148
+ * deadlock, a lock-wait timeout, a serialization failure) — never a new durable checkpoint, just
149
+ * repeated attempts inside the same tool-call step. Default ON: `{ attempts: 2, backoffMs: 150 }`
150
+ * with the default classifier. Set `{ classify }` to widen/narrow which errors count as transient
151
+ * (checked in BOTH the inline and durable-dispatched execution paths via DI, since the classify
152
+ * function itself can't ride a durable step's wire envelope), or `false` to disable entirely. A
153
+ * tool's other (non-transient) failures are unaffected — they remain a one-shot business outcome.
154
+ */
155
+ toolTransientRetry?: ToolTransientRetrySetting;
141
156
  /**
142
157
  * Suggest follow-up questions after the final turn. `true` → 3 suggestions; `{ count }` → that many.
143
158
  * Costs one extra model call per turn (recorded as `follow_ups` usage), stored on the assistant
@@ -1,4 +1,4 @@
1
- import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, Retriever, AgentPricingStore, ToolSpec, ToolHandler, ActorResolver, AgentRegistry } from '@dudousxd/nestjs-agent-core';
1
+ import { ModelProvider, AgentStore, ToolRegistry, RolesPolicy, QuotaStore, TokenStreamSink, PromptBuilder, PromptContributor, ToolTransientRetrySetting, Retriever, AgentPricingStore, ToolSpec, ToolHandler, ActorResolver, AgentRegistry } from '@dudousxd/nestjs-agent-core';
2
2
  import { Provider, FactoryProvider, Type, CanActivate, ModuleMetadata, InjectionToken, OptionalFactoryDependency } from '@nestjs/common';
3
3
 
4
4
  /** Everything `runAgentLoop` needs, minus the per-run `day` the runner stamps. */
@@ -19,6 +19,11 @@ interface AgentDeps {
19
19
  toolAllowList?: string[];
20
20
  /** Per-tool execution timeout in ms (from module options). Undefined → no timeout. */
21
21
  toolTimeoutMs?: number;
22
+ /**
23
+ * Transient-tool-error retry policy (from module options). Undefined → default ON
24
+ * (`{ attempts: 2, backoffMs: 150 }` with the default classifier); `false` → disabled.
25
+ */
26
+ toolTransientRetry?: ToolTransientRetrySetting;
22
27
  /** How many follow-up suggestions to generate after the final turn. Undefined/0 → off. */
23
28
  followUpsCount?: number;
24
29
  /** Inject-mode retriever (from `forRoot({ retrieval })`). Undefined → no prompt augmentation. */
@@ -138,6 +143,16 @@ interface AgentModuleOptions {
138
143
  * model receives the timeout as its result and can adapt) instead of hanging the turn. Omit → none.
139
144
  */
140
145
  toolTimeoutMs?: number;
146
+ /**
147
+ * Retries a tool's own invocation, in place, when it throws a classified-transient error (a DB
148
+ * deadlock, a lock-wait timeout, a serialization failure) — never a new durable checkpoint, just
149
+ * repeated attempts inside the same tool-call step. Default ON: `{ attempts: 2, backoffMs: 150 }`
150
+ * with the default classifier. Set `{ classify }` to widen/narrow which errors count as transient
151
+ * (checked in BOTH the inline and durable-dispatched execution paths via DI, since the classify
152
+ * function itself can't ride a durable step's wire envelope), or `false` to disable entirely. A
153
+ * tool's other (non-transient) failures are unaffected — they remain a one-shot business outcome.
154
+ */
155
+ toolTransientRetry?: ToolTransientRetrySetting;
141
156
  /**
142
157
  * Suggest follow-up questions after the final turn. `true` → 3 suggestions; `{ count }` → that many.
143
158
  * Costs one extra model call per turn (recorded as `follow_ups` usage), stored on the assistant
@@ -100,23 +100,45 @@ var AgentRunSteps = class {
100
100
  }));
101
101
  }
102
102
  /**
103
- * No retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm` above).
104
- * The timeout is applied HERE, handler-side, via `withToolTimeout` — never as a durable dispatch
105
- * `timeoutMs`, which bounds engine liveness (retryable) rather than the tool's own business outcome.
103
+ * NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
104
+ * above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
105
+ * invocation (a DB deadlock, a lock-wait timeout — see `isTransientToolError`): the server rolled
106
+ * that work back, so re-invoking it is safe, and doing it here (inside this one step, never a new
107
+ * checkpoint) is exactly how the non-dispatched loop path handles it too. The timeout is applied
108
+ * HERE, handler-side, via `withToolTimeout` — never as a durable dispatch `timeoutMs`, which
109
+ * bounds engine liveness (retryable) rather than the tool's own business outcome — and per
110
+ * ATTEMPT, so a retried invocation gets its own fresh timeout window.
106
111
  */
107
112
  async tool(input) {
108
113
  const deps = this.factory.forAgent(input.ctx.agentName);
109
114
  const ctx = {
110
115
  ...input.ctx
111
116
  };
117
+ const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
118
+ const transientRetry = input.transientRetry === false ? false : {
119
+ attempts: input.transientRetry.attempts,
120
+ backoffMs: input.transientRetry.backoffMs,
121
+ ...localClassify !== void 0 ? {
122
+ classify: localClassify
123
+ } : {}
124
+ };
112
125
  return (0, import_nestjs_agent_core.traceToolExecution)(input.ctx.runId, {
113
126
  toolCallId: input.toolCallId,
114
127
  toolName: input.toolName,
115
128
  toolType: input.toolType
116
- }, () => {
129
+ }, () => (0, import_nestjs_agent_core.invokeWithTransientRetry)(() => {
117
130
  const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
118
131
  return input.timeoutMs !== void 0 ? (0, import_nestjs_agent_core.withToolTimeout)(invocation, input.timeoutMs, input.toolName) : invocation;
119
- });
132
+ }, transientRetry, {
133
+ onRetry: /* @__PURE__ */ __name((attempt, error) => {
134
+ (0, import_nestjs_agent_core.publishAgentToolRetry)({
135
+ toolName: input.toolName,
136
+ toolCallId: input.toolCallId,
137
+ attempt,
138
+ message: error instanceof Error ? error.message : String(error)
139
+ });
140
+ }, "onRetry")
141
+ }));
120
142
  }
121
143
  };
122
144
  _ts_decorate([
@@ -591,6 +613,9 @@ var AgentDepsFactory2 = class {
591
613
  ...this.options.toolTimeoutMs !== void 0 ? {
592
614
  toolTimeoutMs: this.options.toolTimeoutMs
593
615
  } : {},
616
+ ...this.options.toolTransientRetry !== void 0 ? {
617
+ toolTransientRetry: this.options.toolTransientRetry
618
+ } : {},
594
619
  ...followUpsCount !== void 0 ? {
595
620
  followUpsCount
596
621
  } : {},