@dudousxd/nestjs-agent 0.11.0 → 0.12.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/README.md +60 -0
- package/dist/{agent-deps.factory-D7GdhqdK.d.cts → agent-deps.factory-EROMcBNh.d.cts} +182 -5
- package/dist/{agent-deps.factory-D7GdhqdK.d.ts → agent-deps.factory-EROMcBNh.d.ts} +182 -5
- package/dist/durable/index.cjs +1733 -497
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +78 -32
- package/dist/durable/index.d.ts +78 -32
- package/dist/durable/index.js +1673 -437
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +1349 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +415 -26
- package/dist/index.d.ts +415 -26
- package/dist/index.js +1289 -234
- package/dist/index.js.map +1 -1
- package/package.json +13 -12
package/dist/durable/index.d.cts
CHANGED
|
@@ -1,8 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { WorkflowCtx } from '@dudousxd/nestjs-durable-core';
|
|
3
|
-
import { A as AgentDepsFactory, a as AgentSurface, b as AgentModuleOptions } from '../agent-deps.factory-
|
|
1
|
+
import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, BufferedModelTurnResult, ToolStepEnvelope, AgentRunner, TokenStreamSink, HumanReply } from '@dudousxd/nestjs-agent-core';
|
|
2
|
+
import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
|
|
3
|
+
import { A as AgentDepsFactory, a as AgentSurface, b as AgentModuleOptions } from '../agent-deps.factory-EROMcBNh.cjs';
|
|
4
4
|
import { WorkflowService } from '@dudousxd/nestjs-durable';
|
|
5
5
|
import { DynamicModule } from '@nestjs/common';
|
|
6
|
+
import '@standard-schema/spec';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The agent turn AS a durable workflow. Persist/stream checkpoints are `ctx.localStep`s — the
|
|
10
|
+
* in-process primitive, NOT the always-dispatched `ctx.step`: their names are dynamic checkpoint
|
|
11
|
+
* identities (`persist:toolcall:<id>`), not routable worker groups, and their deps (store, sink)
|
|
12
|
+
* live in THIS workflow worker's DI. The two LONG steps (model call, tool execution) are dispatched
|
|
13
|
+
* through `AgentRunSteps` by default (`AGENT_DISPATCHED_STEPS`, ON under `durable: true`) so the
|
|
14
|
+
* run isn't pinned to this pod while they execute; `dispatchedSteps: false` keeps them localSteps
|
|
15
|
+
* too. HITL is `ctx.waitForSignal`, and sub-agent delegation is `ctx.child(AgentRunWorkflow)` — a
|
|
16
|
+
* replay-safe, observable child run (it shows up as a node in the durable dashboard). A child
|
|
17
|
+
* streams into its top-level ancestor's sink (`sinkRunId`) so the human watching the parent sees it
|
|
18
|
+
* and can approve its action tools; the approval routes to the child's own run via `runForToolCall`.
|
|
19
|
+
*/
|
|
20
|
+
declare class AgentRunWorkflow {
|
|
21
|
+
private readonly factory;
|
|
22
|
+
private readonly store;
|
|
23
|
+
private readonly dispatchedSteps;
|
|
24
|
+
private readonly runs?;
|
|
25
|
+
constructor(factory: AgentDepsFactory, store: AgentStore, dispatchedSteps: boolean, runs?: RunGateway | undefined);
|
|
26
|
+
/**
|
|
27
|
+
* Has someone asked this run to stop? Read from the runtime's own run status, which is where
|
|
28
|
+
* `DurableAgentRunner.cancel` puts it — `cancelling` while a compensating cancel is in flight,
|
|
29
|
+
* `cancelled` once it has settled.
|
|
30
|
+
*
|
|
31
|
+
* Costs a run read at each of the loop's observation points (two per step). That is a row the
|
|
32
|
+
* control plane already has, against a turn that is otherwise making model calls, and it buys the
|
|
33
|
+
* property that matters: the answer comes from a place BOTH the canceller and every pod that might
|
|
34
|
+
* replay this run can see.
|
|
35
|
+
*
|
|
36
|
+
* Failing to ask is not a cancel. A tenant with no gateway wired, or an operator briefly
|
|
37
|
+
* unreachable, answers "no" and the run carries on — the alternative is failing healthy runs
|
|
38
|
+
* because a status read timed out. The loop journals that answer like any other, so two processes
|
|
39
|
+
* can never disagree about what was seen here.
|
|
40
|
+
*/
|
|
41
|
+
private isCancelled;
|
|
42
|
+
/**
|
|
43
|
+
* Settle the delegation a DETACHED run was started for, when that run ends without an answer.
|
|
44
|
+
*
|
|
45
|
+
* The loop delivers its own success (`deliver:detached`) but cannot catch its own crash, and the
|
|
46
|
+
* runtime settles the run row without knowing anything delegated it. Left alone, the card in the
|
|
47
|
+
* calling conversation says "started" for ever — the one state a reader can neither wait on nor
|
|
48
|
+
* act on. A no-op for every other run: only a detached one carries a delivery address.
|
|
49
|
+
*/
|
|
50
|
+
private settleDetachedParent;
|
|
51
|
+
run(ctx: WorkflowCtx, input: AgentRunInput): Promise<AgentLoopResult>;
|
|
52
|
+
}
|
|
6
53
|
|
|
7
54
|
/**
|
|
8
55
|
* Serializable input for the dispatched `llm` step: a {@link LlmStepEnvelope} plus the sink routing
|
|
@@ -54,7 +101,7 @@ declare class AgentRunSteps {
|
|
|
54
101
|
* double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
|
|
55
102
|
* across however many turns/retries it takes.
|
|
56
103
|
*/
|
|
57
|
-
llm(input: DispatchedLlmInput): Promise<
|
|
104
|
+
llm(input: DispatchedLlmInput): Promise<BufferedModelTurnResult>;
|
|
58
105
|
/**
|
|
59
106
|
* NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
|
|
60
107
|
* above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
|
|
@@ -68,42 +115,41 @@ declare class AgentRunSteps {
|
|
|
68
115
|
tool(input: DispatchedToolInput): Promise<unknown>;
|
|
69
116
|
}
|
|
70
117
|
|
|
71
|
-
/**
|
|
72
|
-
* The agent turn AS a durable workflow. Persist/stream checkpoints are `ctx.localStep`s — the
|
|
73
|
-
* in-process primitive, NOT the always-dispatched `ctx.step`: their names are dynamic checkpoint
|
|
74
|
-
* identities (`persist:toolcall:<id>`), not routable worker groups, and their deps (store, sink)
|
|
75
|
-
* live in THIS workflow worker's DI. The two LONG steps (model call, tool execution) are dispatched
|
|
76
|
-
* through `AgentRunSteps` by default (`AGENT_DISPATCHED_STEPS`, ON under `durable: true`) so the
|
|
77
|
-
* run isn't pinned to this pod while they execute; `dispatchedSteps: false` keeps them localSteps
|
|
78
|
-
* too. HITL is `ctx.waitForSignal`, and sub-agent delegation is `ctx.child(AgentRunWorkflow)` — a
|
|
79
|
-
* replay-safe, observable child run (it shows up as a node in the durable dashboard). A child
|
|
80
|
-
* streams into its top-level ancestor's sink (`sinkRunId`) so the human watching the parent sees it
|
|
81
|
-
* and can approve its action tools; the approval routes to the child's own run via `runForToolCall`.
|
|
82
|
-
*/
|
|
83
|
-
declare class AgentRunWorkflow {
|
|
84
|
-
private readonly factory;
|
|
85
|
-
private readonly store;
|
|
86
|
-
private readonly steps;
|
|
87
|
-
private readonly dispatchedSteps;
|
|
88
|
-
constructor(factory: AgentDepsFactory, store: AgentStore, steps: AgentRunSteps | undefined, dispatchedSteps: boolean);
|
|
89
|
-
run(ctx: WorkflowCtx, input: AgentRunInput): Promise<{
|
|
90
|
-
text: string;
|
|
91
|
-
}>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
118
|
/**
|
|
95
119
|
* Runs the agent turn as a `@dudousxd/nestjs-durable` workflow. `start` creates the run and returns
|
|
96
|
-
* its id immediately; a worker runs the body and streams tokens to the sink.
|
|
97
|
-
*
|
|
120
|
+
* its id immediately; a worker runs the body and streams tokens to the sink. Everything a human
|
|
121
|
+
* sends back into a parked run — a HITL approval, or the answers to a question set — is delivered as
|
|
122
|
+
* a durable signal namespaced by run, so it can never cross-resolve another run.
|
|
98
123
|
*/
|
|
99
124
|
declare class DurableAgentRunner implements AgentRunner {
|
|
100
125
|
private readonly workflows;
|
|
101
|
-
|
|
126
|
+
private readonly runs;
|
|
127
|
+
private readonly store;
|
|
128
|
+
private readonly sink;
|
|
129
|
+
private readonly logger;
|
|
130
|
+
constructor(workflows: WorkflowService, runs: RunGateway, store: AgentStore, sink: TokenStreamSink);
|
|
102
131
|
start(input: AgentRunInput): Promise<{
|
|
103
132
|
runId: string;
|
|
104
133
|
}>;
|
|
105
|
-
signal(runId: string, toolCallId: string,
|
|
106
|
-
|
|
134
|
+
signal(runId: string, toolCallId: string, reply: HumanReply): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Stop a run, and settle what the durable runtime knows nothing about.
|
|
137
|
+
*
|
|
138
|
+
* `compensate: true` is the form that gives the BODY a chance: it moves the run to `cancelling`
|
|
139
|
+
* (which is what the workflow's own cancel observation reads) and then re-drives it, so a turn
|
|
140
|
+
* running in-process unwinds at its next safe point instead of finishing. It also guarantees the
|
|
141
|
+
* outcome for the turn that CANNOT observe anything — one parked on `waitForSignal`, suspended
|
|
142
|
+
* inside a position its journal already holds — because that re-drive re-suspends and the runtime
|
|
143
|
+
* settles the run `cancelled` regardless. The cascade to child runs comes with it.
|
|
144
|
+
*
|
|
145
|
+
* Neither of those settles the agent's own state, so this does: the run row gets its own terminal,
|
|
146
|
+
* and the subscriber gets a `cancelled` frame followed by a normal end. Both are keyed by runId
|
|
147
|
+
* alone, which is why they belong here rather than in the body — the body is the only place that
|
|
148
|
+
* knows which THREAD was streaming, so releasing that stays there (see `AgentRunWorkflow`).
|
|
149
|
+
*
|
|
150
|
+
* A tool already executing is not interrupted, here or anywhere: see `haltIfCancelled` in core.
|
|
151
|
+
*/
|
|
152
|
+
cancel(runId: string): Promise<void>;
|
|
107
153
|
}
|
|
108
154
|
|
|
109
155
|
/**
|
package/dist/durable/index.d.ts
CHANGED
|
@@ -1,8 +1,55 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { WorkflowCtx } from '@dudousxd/nestjs-durable-core';
|
|
3
|
-
import { A as AgentDepsFactory, a as AgentSurface, b as AgentModuleOptions } from '../agent-deps.factory-
|
|
1
|
+
import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, BufferedModelTurnResult, ToolStepEnvelope, AgentRunner, TokenStreamSink, HumanReply } from '@dudousxd/nestjs-agent-core';
|
|
2
|
+
import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
|
|
3
|
+
import { A as AgentDepsFactory, a as AgentSurface, b as AgentModuleOptions } from '../agent-deps.factory-EROMcBNh.js';
|
|
4
4
|
import { WorkflowService } from '@dudousxd/nestjs-durable';
|
|
5
5
|
import { DynamicModule } from '@nestjs/common';
|
|
6
|
+
import '@standard-schema/spec';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The agent turn AS a durable workflow. Persist/stream checkpoints are `ctx.localStep`s — the
|
|
10
|
+
* in-process primitive, NOT the always-dispatched `ctx.step`: their names are dynamic checkpoint
|
|
11
|
+
* identities (`persist:toolcall:<id>`), not routable worker groups, and their deps (store, sink)
|
|
12
|
+
* live in THIS workflow worker's DI. The two LONG steps (model call, tool execution) are dispatched
|
|
13
|
+
* through `AgentRunSteps` by default (`AGENT_DISPATCHED_STEPS`, ON under `durable: true`) so the
|
|
14
|
+
* run isn't pinned to this pod while they execute; `dispatchedSteps: false` keeps them localSteps
|
|
15
|
+
* too. HITL is `ctx.waitForSignal`, and sub-agent delegation is `ctx.child(AgentRunWorkflow)` — a
|
|
16
|
+
* replay-safe, observable child run (it shows up as a node in the durable dashboard). A child
|
|
17
|
+
* streams into its top-level ancestor's sink (`sinkRunId`) so the human watching the parent sees it
|
|
18
|
+
* and can approve its action tools; the approval routes to the child's own run via `runForToolCall`.
|
|
19
|
+
*/
|
|
20
|
+
declare class AgentRunWorkflow {
|
|
21
|
+
private readonly factory;
|
|
22
|
+
private readonly store;
|
|
23
|
+
private readonly dispatchedSteps;
|
|
24
|
+
private readonly runs?;
|
|
25
|
+
constructor(factory: AgentDepsFactory, store: AgentStore, dispatchedSteps: boolean, runs?: RunGateway | undefined);
|
|
26
|
+
/**
|
|
27
|
+
* Has someone asked this run to stop? Read from the runtime's own run status, which is where
|
|
28
|
+
* `DurableAgentRunner.cancel` puts it — `cancelling` while a compensating cancel is in flight,
|
|
29
|
+
* `cancelled` once it has settled.
|
|
30
|
+
*
|
|
31
|
+
* Costs a run read at each of the loop's observation points (two per step). That is a row the
|
|
32
|
+
* control plane already has, against a turn that is otherwise making model calls, and it buys the
|
|
33
|
+
* property that matters: the answer comes from a place BOTH the canceller and every pod that might
|
|
34
|
+
* replay this run can see.
|
|
35
|
+
*
|
|
36
|
+
* Failing to ask is not a cancel. A tenant with no gateway wired, or an operator briefly
|
|
37
|
+
* unreachable, answers "no" and the run carries on — the alternative is failing healthy runs
|
|
38
|
+
* because a status read timed out. The loop journals that answer like any other, so two processes
|
|
39
|
+
* can never disagree about what was seen here.
|
|
40
|
+
*/
|
|
41
|
+
private isCancelled;
|
|
42
|
+
/**
|
|
43
|
+
* Settle the delegation a DETACHED run was started for, when that run ends without an answer.
|
|
44
|
+
*
|
|
45
|
+
* The loop delivers its own success (`deliver:detached`) but cannot catch its own crash, and the
|
|
46
|
+
* runtime settles the run row without knowing anything delegated it. Left alone, the card in the
|
|
47
|
+
* calling conversation says "started" for ever — the one state a reader can neither wait on nor
|
|
48
|
+
* act on. A no-op for every other run: only a detached one carries a delivery address.
|
|
49
|
+
*/
|
|
50
|
+
private settleDetachedParent;
|
|
51
|
+
run(ctx: WorkflowCtx, input: AgentRunInput): Promise<AgentLoopResult>;
|
|
52
|
+
}
|
|
6
53
|
|
|
7
54
|
/**
|
|
8
55
|
* Serializable input for the dispatched `llm` step: a {@link LlmStepEnvelope} plus the sink routing
|
|
@@ -54,7 +101,7 @@ declare class AgentRunSteps {
|
|
|
54
101
|
* double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
|
|
55
102
|
* across however many turns/retries it takes.
|
|
56
103
|
*/
|
|
57
|
-
llm(input: DispatchedLlmInput): Promise<
|
|
104
|
+
llm(input: DispatchedLlmInput): Promise<BufferedModelTurnResult>;
|
|
58
105
|
/**
|
|
59
106
|
* NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
|
|
60
107
|
* above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
|
|
@@ -68,42 +115,41 @@ declare class AgentRunSteps {
|
|
|
68
115
|
tool(input: DispatchedToolInput): Promise<unknown>;
|
|
69
116
|
}
|
|
70
117
|
|
|
71
|
-
/**
|
|
72
|
-
* The agent turn AS a durable workflow. Persist/stream checkpoints are `ctx.localStep`s — the
|
|
73
|
-
* in-process primitive, NOT the always-dispatched `ctx.step`: their names are dynamic checkpoint
|
|
74
|
-
* identities (`persist:toolcall:<id>`), not routable worker groups, and their deps (store, sink)
|
|
75
|
-
* live in THIS workflow worker's DI. The two LONG steps (model call, tool execution) are dispatched
|
|
76
|
-
* through `AgentRunSteps` by default (`AGENT_DISPATCHED_STEPS`, ON under `durable: true`) so the
|
|
77
|
-
* run isn't pinned to this pod while they execute; `dispatchedSteps: false` keeps them localSteps
|
|
78
|
-
* too. HITL is `ctx.waitForSignal`, and sub-agent delegation is `ctx.child(AgentRunWorkflow)` — a
|
|
79
|
-
* replay-safe, observable child run (it shows up as a node in the durable dashboard). A child
|
|
80
|
-
* streams into its top-level ancestor's sink (`sinkRunId`) so the human watching the parent sees it
|
|
81
|
-
* and can approve its action tools; the approval routes to the child's own run via `runForToolCall`.
|
|
82
|
-
*/
|
|
83
|
-
declare class AgentRunWorkflow {
|
|
84
|
-
private readonly factory;
|
|
85
|
-
private readonly store;
|
|
86
|
-
private readonly steps;
|
|
87
|
-
private readonly dispatchedSteps;
|
|
88
|
-
constructor(factory: AgentDepsFactory, store: AgentStore, steps: AgentRunSteps | undefined, dispatchedSteps: boolean);
|
|
89
|
-
run(ctx: WorkflowCtx, input: AgentRunInput): Promise<{
|
|
90
|
-
text: string;
|
|
91
|
-
}>;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
118
|
/**
|
|
95
119
|
* Runs the agent turn as a `@dudousxd/nestjs-durable` workflow. `start` creates the run and returns
|
|
96
|
-
* its id immediately; a worker runs the body and streams tokens to the sink.
|
|
97
|
-
*
|
|
120
|
+
* its id immediately; a worker runs the body and streams tokens to the sink. Everything a human
|
|
121
|
+
* sends back into a parked run — a HITL approval, or the answers to a question set — is delivered as
|
|
122
|
+
* a durable signal namespaced by run, so it can never cross-resolve another run.
|
|
98
123
|
*/
|
|
99
124
|
declare class DurableAgentRunner implements AgentRunner {
|
|
100
125
|
private readonly workflows;
|
|
101
|
-
|
|
126
|
+
private readonly runs;
|
|
127
|
+
private readonly store;
|
|
128
|
+
private readonly sink;
|
|
129
|
+
private readonly logger;
|
|
130
|
+
constructor(workflows: WorkflowService, runs: RunGateway, store: AgentStore, sink: TokenStreamSink);
|
|
102
131
|
start(input: AgentRunInput): Promise<{
|
|
103
132
|
runId: string;
|
|
104
133
|
}>;
|
|
105
|
-
signal(runId: string, toolCallId: string,
|
|
106
|
-
|
|
134
|
+
signal(runId: string, toolCallId: string, reply: HumanReply): Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Stop a run, and settle what the durable runtime knows nothing about.
|
|
137
|
+
*
|
|
138
|
+
* `compensate: true` is the form that gives the BODY a chance: it moves the run to `cancelling`
|
|
139
|
+
* (which is what the workflow's own cancel observation reads) and then re-drives it, so a turn
|
|
140
|
+
* running in-process unwinds at its next safe point instead of finishing. It also guarantees the
|
|
141
|
+
* outcome for the turn that CANNOT observe anything — one parked on `waitForSignal`, suspended
|
|
142
|
+
* inside a position its journal already holds — because that re-drive re-suspends and the runtime
|
|
143
|
+
* settles the run `cancelled` regardless. The cascade to child runs comes with it.
|
|
144
|
+
*
|
|
145
|
+
* Neither of those settles the agent's own state, so this does: the run row gets its own terminal,
|
|
146
|
+
* and the subscriber gets a `cancelled` frame followed by a normal end. Both are keyed by runId
|
|
147
|
+
* alone, which is why they belong here rather than in the body — the body is the only place that
|
|
148
|
+
* knows which THREAD was streaming, so releasing that stays there (see `AgentRunWorkflow`).
|
|
149
|
+
*
|
|
150
|
+
* A tool already executing is not interrupted, here or anywhere: see `haltIfCancelled` in core.
|
|
151
|
+
*/
|
|
152
|
+
cancel(runId: string): Promise<void>;
|
|
107
153
|
}
|
|
108
154
|
|
|
109
155
|
/**
|