@dudousxd/nestjs-agent 0.7.0 → 0.8.1

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.
@@ -19,11 +19,24 @@ interface DispatchedLlmInput extends LlmStepEnvelope {
19
19
  * wire-contract change once the durable runtime exposes the attempt.
20
20
  */
21
21
  runId: string;
22
+ /** The turn index within the run (`llm:<step>`) — the `llm.turn` span's `step` metadata. */
23
+ step: number;
22
24
  /** The stream target: `input.sinkRunId ?? ctx.runId` of the dispatching workflow. */
23
25
  sinkRunId: string;
24
26
  /** True for a sub-agent run — wrap the writer with {@link childSinkWriter} (no end/fail). */
25
27
  childSink: boolean;
26
28
  }
29
+ /**
30
+ * Serializable input for the dispatched `tool` step: a {@link ToolStepEnvelope} plus the call
31
+ * identity the `tool.execution` span needs (`toolCallId`/`toolType`) — core's
32
+ * `AgentLoopHooks.dispatchTool` passes those on the separate `ToolCallRequest` argument, so the
33
+ * workflow folds them into the wire payload when it dispatches (same pattern as
34
+ * {@link DispatchedLlmInput}'s sink routing).
35
+ */
36
+ interface DispatchedToolInput extends ToolStepEnvelope {
37
+ toolCallId: string;
38
+ toolType: 'read' | 'action';
39
+ }
27
40
  /**
28
41
  * The two long steps `AgentRunWorkflow` dispatches as routed remote steps (`AgentRunSteps.llm` /
29
42
  * `AgentRunSteps.tool`) — the default under `durable: true`; `dispatchedSteps: false` runs them
@@ -47,7 +60,7 @@ declare class AgentRunSteps {
47
60
  * The timeout is applied HERE, handler-side, via `withToolTimeout` — never as a durable dispatch
48
61
  * `timeoutMs`, which bounds engine liveness (retryable) rather than the tool's own business outcome.
49
62
  */
50
- tool(input: ToolStepEnvelope): Promise<unknown>;
63
+ tool(input: DispatchedToolInput): Promise<unknown>;
51
64
  }
52
65
 
53
66
  /**
@@ -130,4 +143,4 @@ declare function agentDurable(options: AgentModuleOptions): DynamicModule[];
130
143
  */
131
144
  declare const AGENT_DISPATCHED_STEPS: unique symbol;
132
145
 
133
- export { AGENT_DISPATCHED_STEPS, AgentDurableModule, AgentRunSteps, AgentRunWorkflow, type DispatchedLlmInput, DurableAgentRunner, agentDurable };
146
+ export { AGENT_DISPATCHED_STEPS, AgentDurableModule, AgentRunSteps, AgentRunWorkflow, type DispatchedLlmInput, type DispatchedToolInput, DurableAgentRunner, agentDurable };
@@ -19,11 +19,24 @@ interface DispatchedLlmInput extends LlmStepEnvelope {
19
19
  * wire-contract change once the durable runtime exposes the attempt.
20
20
  */
21
21
  runId: string;
22
+ /** The turn index within the run (`llm:<step>`) — the `llm.turn` span's `step` metadata. */
23
+ step: number;
22
24
  /** The stream target: `input.sinkRunId ?? ctx.runId` of the dispatching workflow. */
23
25
  sinkRunId: string;
24
26
  /** True for a sub-agent run — wrap the writer with {@link childSinkWriter} (no end/fail). */
25
27
  childSink: boolean;
26
28
  }
29
+ /**
30
+ * Serializable input for the dispatched `tool` step: a {@link ToolStepEnvelope} plus the call
31
+ * identity the `tool.execution` span needs (`toolCallId`/`toolType`) — core's
32
+ * `AgentLoopHooks.dispatchTool` passes those on the separate `ToolCallRequest` argument, so the
33
+ * workflow folds them into the wire payload when it dispatches (same pattern as
34
+ * {@link DispatchedLlmInput}'s sink routing).
35
+ */
36
+ interface DispatchedToolInput extends ToolStepEnvelope {
37
+ toolCallId: string;
38
+ toolType: 'read' | 'action';
39
+ }
27
40
  /**
28
41
  * The two long steps `AgentRunWorkflow` dispatches as routed remote steps (`AgentRunSteps.llm` /
29
42
  * `AgentRunSteps.tool`) — the default under `durable: true`; `dispatchedSteps: false` runs them
@@ -47,7 +60,7 @@ declare class AgentRunSteps {
47
60
  * The timeout is applied HERE, handler-side, via `withToolTimeout` — never as a durable dispatch
48
61
  * `timeoutMs`, which bounds engine liveness (retryable) rather than the tool's own business outcome.
49
62
  */
50
- tool(input: ToolStepEnvelope): Promise<unknown>;
63
+ tool(input: DispatchedToolInput): Promise<unknown>;
51
64
  }
52
65
 
53
66
  /**
@@ -130,4 +143,4 @@ declare function agentDurable(options: AgentModuleOptions): DynamicModule[];
130
143
  */
131
144
  declare const AGENT_DISPATCHED_STEPS: unique symbol;
132
145
 
133
- export { AGENT_DISPATCHED_STEPS, AgentDurableModule, AgentRunSteps, AgentRunWorkflow, type DispatchedLlmInput, DurableAgentRunner, agentDurable };
146
+ export { AGENT_DISPATCHED_STEPS, AgentDurableModule, AgentRunSteps, AgentRunWorkflow, type DispatchedLlmInput, type DispatchedToolInput, DurableAgentRunner, agentDurable };
@@ -24,7 +24,7 @@ function childSinkWriter(writer) {
24
24
  __name(childSinkWriter, "childSinkWriter");
25
25
 
26
26
  // src/durable/agent-run.steps.ts
27
- import { AGENT_DEPS_FACTORY, withToolTimeout } from "@dudousxd/nestjs-agent-core";
27
+ import { AGENT_DEPS_FACTORY, traceLlmTurn, traceToolExecution, withToolTimeout } from "@dudousxd/nestjs-agent-core";
28
28
  import { Step } from "@dudousxd/nestjs-durable";
29
29
  import { Inject, Injectable } from "@nestjs/common";
30
30
  function _ts_decorate(decorators, target, key, desc) {
@@ -63,12 +63,12 @@ var AgentRunSteps = class {
63
63
  const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
64
64
  const opened = await deps.sink.open(input.sinkRunId);
65
65
  const writer = input.childSink ? childSinkWriter(opened) : opened;
66
- return deps.model.runTurn({
66
+ return traceLlmTurn(input.runId, input.step, () => deps.model.runTurn({
67
67
  system: input.system,
68
68
  messages: input.messages,
69
69
  tools,
70
70
  sink: writer
71
- });
71
+ }));
72
72
  }
73
73
  /**
74
74
  * No retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm` above).
@@ -80,8 +80,14 @@ var AgentRunSteps = class {
80
80
  const ctx = {
81
81
  ...input.ctx
82
82
  };
83
- const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
84
- return input.timeoutMs !== void 0 ? withToolTimeout(invocation, input.timeoutMs, input.toolName) : invocation;
83
+ return traceToolExecution(input.ctx.runId, {
84
+ toolCallId: input.toolCallId,
85
+ toolName: input.toolName,
86
+ toolType: input.toolType
87
+ }, () => {
88
+ const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
89
+ return input.timeoutMs !== void 0 ? withToolTimeout(invocation, input.timeoutMs, input.toolName) : invocation;
90
+ });
85
91
  }
86
92
  };
87
93
  _ts_decorate([
@@ -98,7 +104,7 @@ _ts_decorate([
98
104
  Step(),
99
105
  _ts_metadata("design:type", Function),
100
106
  _ts_metadata("design:paramtypes", [
101
- typeof ToolStepEnvelope === "undefined" ? Object : ToolStepEnvelope
107
+ typeof DispatchedToolInput === "undefined" ? Object : DispatchedToolInput
102
108
  ]),
103
109
  _ts_metadata("design:returntype", Promise)
104
110
  ], AgentRunSteps.prototype, "tool", null);
@@ -187,13 +193,23 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
187
193
  // execution. `sinkRunId`/`childSink` are sink routing this workflow already resolved above —
188
194
  // core's dispatchLlm signature stays sink-topology-agnostic, so we add them here, not in core.
189
195
  ...this.dispatchedSteps ? {
190
- dispatchLlm: /* @__PURE__ */ __name((_index, envelope) => ctx.step(this.steps.llm, {
196
+ dispatchLlm: /* @__PURE__ */ __name((index, envelope) => ctx.step(this.steps.llm, {
191
197
  ...envelope,
192
198
  runId: ctx.runId,
199
+ step: index,
193
200
  sinkRunId,
194
201
  childSink: input.sinkRunId !== void 0
195
202
  }), "dispatchLlm"),
196
- dispatchTool: /* @__PURE__ */ __name((_call, envelope) => ctx.step(this.steps.tool, envelope), "dispatchTool")
203
+ // Fold the call identity (`toolCallId`/`toolType`) into the wire payload — the handler
204
+ // emits the `tool.execution` span with it. Only read/action calls reach dispatchTool
205
+ // ('agent'-kind delegations branch to runAgent earlier in the loop), so anything that
206
+ // isn't 'action' is defensively 'read' — the same posture core takes for an
207
+ // unresolvable `kind`.
208
+ dispatchTool: /* @__PURE__ */ __name((call, envelope) => ctx.step(this.steps.tool, {
209
+ ...envelope,
210
+ toolCallId: call.id,
211
+ toolType: call.kind === "action" ? "action" : "read"
212
+ }), "dispatchTool")
197
213
  } : {}
198
214
  };
199
215
  try {