@dudousxd/nestjs-agent 1.24.1 → 1.25.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 +7 -5
- package/dist/durable/index.cjs +67 -10
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.js +68 -11
- package/dist/durable/index.js.map +1 -1
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.d.cts +16 -3
- package/dist/genui/index.d.ts +16 -3
- package/dist/genui/index.js.map +1 -1
- package/dist/index.cjs +48 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -11
- package/dist/index.d.ts +27 -11
- package/dist/index.js +48 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -109,13 +109,15 @@ import { BUILTIN_COMPONENTS } from '@dudousxd/nestjs-agent-core/genui/builtins';
|
|
|
109
109
|
export const catalog = defineCatalog([...BUILTIN_COMPONENTS, DealCard]);
|
|
110
110
|
|
|
111
111
|
// app.module.ts
|
|
112
|
-
AgentGenuiModule.forRoot({ catalog,
|
|
112
|
+
AgentGenuiModule.forRoot({ catalog, terminal: true });
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
It registers the tools (`
|
|
116
|
-
mode
|
|
117
|
-
every call against the catalog. Options: `mode`, `
|
|
118
|
-
`
|
|
115
|
+
It registers the tools (one `ui__render` tree tool by default, `ui__show_<component>` per component
|
|
116
|
+
with `mode: 'per-component'`, plus a generic `ui__show` taking `{ component, props }` with
|
|
117
|
+
`showTool: true`), validating every call against the catalog. Options: `mode`, `treeSchema`,
|
|
118
|
+
`streaming` (`'partial'` draws the tree while the model writes it), `streamingThrottleMs`,
|
|
119
|
+
`terminal`, `treeToolName`, `treeInstructions`, `treeLimits`, `namePrefix`, `showTool`,
|
|
120
|
+
`showInstructions`, `roles`, `presentation`.
|
|
119
121
|
`forRootAsync({ imports, inject, useFactory })` builds them from config. The catalog is injectable
|
|
120
122
|
(`@InjectGenuiCatalog()`, token `GENUI_CATALOG`) and replaceable in a test with
|
|
121
123
|
`overrideProvider(GENUI_CATALOG)` — the tools are built from the injected one.
|
package/dist/durable/index.cjs
CHANGED
|
@@ -159,7 +159,19 @@ var AgentRunSteps = class {
|
|
|
159
159
|
const opened = await deps.sink.open(input.sinkRunId);
|
|
160
160
|
writer = input.childSink ? childSinkWriter(opened) : opened;
|
|
161
161
|
}
|
|
162
|
-
const
|
|
162
|
+
const previews = (0, import_nestjs_agent_core3.previewToolInputs)(writer, (0, import_nestjs_agent_core3.registryInputPreviews)(deps.registry, tools, {
|
|
163
|
+
actor: input.actor,
|
|
164
|
+
...input.threadId !== void 0 ? {
|
|
165
|
+
threadId: input.threadId
|
|
166
|
+
} : {},
|
|
167
|
+
...input.agentName !== void 0 ? {
|
|
168
|
+
agentName: input.agentName
|
|
169
|
+
} : {},
|
|
170
|
+
...input.preflightContext?.uiCapabilities !== void 0 ? {
|
|
171
|
+
uiCapabilities: input.preflightContext.uiCapabilities
|
|
172
|
+
} : {}
|
|
173
|
+
}));
|
|
174
|
+
const frames = (0, import_nestjs_agent_core3.observeTurnFrames)(previews.writer);
|
|
163
175
|
const turn = (0, import_nestjs_agent_core3.withTurnFrames)(await (0, import_nestjs_agent_core3.traceLlmTurn)(input.runId, input.step, () => deps.model.runTurn({
|
|
164
176
|
system: input.system,
|
|
165
177
|
messages: input.messages,
|
|
@@ -231,8 +243,13 @@ var AgentRunSteps = class {
|
|
|
231
243
|
};
|
|
232
244
|
}
|
|
233
245
|
}
|
|
234
|
-
|
|
246
|
+
const shown = previews.shown();
|
|
247
|
+
const previewed = shown.length > 0 ? {
|
|
235
248
|
...stamped,
|
|
249
|
+
previews: shown
|
|
250
|
+
} : stamped;
|
|
251
|
+
return buffer === void 0 ? previewed : {
|
|
252
|
+
...previewed,
|
|
236
253
|
bufferedFrames: buffer.frames()
|
|
237
254
|
};
|
|
238
255
|
}
|
|
@@ -1825,9 +1842,13 @@ var ActionProposalService = class {
|
|
|
1825
1842
|
/** The words a text decision is made of, and what the agent answers — English unless configured. */
|
|
1826
1843
|
vocabulary;
|
|
1827
1844
|
replies;
|
|
1845
|
+
hasCapability() {
|
|
1846
|
+
const store = this.store;
|
|
1847
|
+
return typeof store.getThreadActionProposalScope === "function" && typeof store.listActionProposals === "function";
|
|
1848
|
+
}
|
|
1828
1849
|
capability() {
|
|
1829
1850
|
const store = this.store;
|
|
1830
|
-
if (
|
|
1851
|
+
if (!this.hasCapability()) throw new import_common7.NotImplementedException("Action proposals are unavailable");
|
|
1831
1852
|
return store;
|
|
1832
1853
|
}
|
|
1833
1854
|
async scope(threadId, actor) {
|
|
@@ -1843,7 +1864,16 @@ var ActionProposalService = class {
|
|
|
1843
1864
|
requesterRef: proposal.actorRef
|
|
1844
1865
|
});
|
|
1845
1866
|
}
|
|
1867
|
+
/**
|
|
1868
|
+
* One page of a thread's proposals this actor may see. A store without the proposal capability
|
|
1869
|
+
* can only run blocking approvals, so a thread there has no proposals: an empty, final page rather
|
|
1870
|
+
* than `501` — a client that lists by default (React's `useAgentChat`) needs no flag. Deciding one
|
|
1871
|
+
* still answers `501`.
|
|
1872
|
+
*/
|
|
1846
1873
|
async listPage(threadId, actor, query = {}) {
|
|
1874
|
+
if (!this.hasCapability()) return {
|
|
1875
|
+
items: []
|
|
1876
|
+
};
|
|
1847
1877
|
const scope = await this.scope(threadId, actor);
|
|
1848
1878
|
const rows = await this.capability().listActionProposals(scope, {
|
|
1849
1879
|
limit: 1e3,
|
|
@@ -2577,12 +2607,13 @@ var AgentService = class {
|
|
|
2577
2607
|
}
|
|
2578
2608
|
/**
|
|
2579
2609
|
* The proposals of a thread this actor may see — the thread's own actor, or one the policy lets
|
|
2580
|
-
* decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page).
|
|
2581
|
-
*
|
|
2610
|
+
* decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page).
|
|
2611
|
+
* Without independent approvals (the default blocking mode) there are none, so the read answers an
|
|
2612
|
+
* empty list rather than refusing; deciding one still refuses.
|
|
2582
2613
|
*/
|
|
2583
2614
|
async listActionProposals(actor, threadId) {
|
|
2584
2615
|
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) {
|
|
2585
|
-
|
|
2616
|
+
return [];
|
|
2586
2617
|
}
|
|
2587
2618
|
return this.proposals.list(threadId, actor);
|
|
2588
2619
|
}
|
|
@@ -6461,6 +6492,11 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6461
6492
|
* running it. A cancelled id is dropped once the run settles, so the set tracks live runs only.
|
|
6462
6493
|
*/
|
|
6463
6494
|
cancelled = /* @__PURE__ */ new Set();
|
|
6495
|
+
/**
|
|
6496
|
+
* Aborted by {@link cancel}: what cuts short the model call or tool a stopped run is in (the
|
|
6497
|
+
* loop's `abortSignal` hook). Keyed like {@link cancelled}, and dropped with it.
|
|
6498
|
+
*/
|
|
6499
|
+
aborts = /* @__PURE__ */ new Map();
|
|
6464
6500
|
/** Top-level runs this process is running now — what {@link isRunActive} answers from. */
|
|
6465
6501
|
live = /* @__PURE__ */ new Set();
|
|
6466
6502
|
constructor(factory, store, queue) {
|
|
@@ -6530,7 +6566,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6530
6566
|
await (0, import_nestjs_agent_core37.releaseThreadRun)(this.store, input.threadId, runId);
|
|
6531
6567
|
await writer.fail((0, import_nestjs_agent_core37.streamFailure)(error));
|
|
6532
6568
|
}).finally(() => {
|
|
6533
|
-
this.
|
|
6569
|
+
this.forgetCancel(runId);
|
|
6534
6570
|
this.live.delete(runId);
|
|
6535
6571
|
});
|
|
6536
6572
|
return {
|
|
@@ -6549,8 +6585,10 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6549
6585
|
* Ask a run to stop, and settle whatever it was parked on.
|
|
6550
6586
|
*
|
|
6551
6587
|
* The loop observes the request at its next safe point (between steps, before the turn's tools) and
|
|
6552
|
-
* unwinds from there
|
|
6553
|
-
*
|
|
6588
|
+
* unwinds from there. What the run is in right now is aborted (its `abortSignal`): the model call
|
|
6589
|
+
* streaming the answer ends at once and the step it was writing is not persisted, and a tool that
|
|
6590
|
+
* passes `ctx.abortSignal` on is cut short and recorded failed; a tool that ignores the signal is
|
|
6591
|
+
* left to finish, and its result is recorded exactly as it would have been. What this cannot wait for is a turn parked on a human: that wait
|
|
6554
6592
|
* is a promise nobody is going to resolve, so it is REJECTED here with the same
|
|
6555
6593
|
* {@link RunCancelledError} the loop would have thrown, and the run unwinds through the identical
|
|
6556
6594
|
* path.
|
|
@@ -6561,6 +6599,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6561
6599
|
*/
|
|
6562
6600
|
async cancel(runId) {
|
|
6563
6601
|
this.cancelled.add(runId);
|
|
6602
|
+
this.aborts.get(runId)?.abort(new import_nestjs_agent_core37.RunCancelledError());
|
|
6564
6603
|
for (const [key, waiter] of this.pending) {
|
|
6565
6604
|
if (key.startsWith(`${runId}:`)) {
|
|
6566
6605
|
this.pending.delete(key);
|
|
@@ -6569,6 +6608,20 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6569
6608
|
}
|
|
6570
6609
|
await Promise.resolve();
|
|
6571
6610
|
}
|
|
6611
|
+
/** The signal {@link cancel} aborts for `runId` — one per run, shared by its awaited delegates. */
|
|
6612
|
+
abortSignalFor(runId) {
|
|
6613
|
+
let controller = this.aborts.get(runId);
|
|
6614
|
+
if (controller === void 0) {
|
|
6615
|
+
controller = new AbortController();
|
|
6616
|
+
this.aborts.set(runId, controller);
|
|
6617
|
+
}
|
|
6618
|
+
return controller.signal;
|
|
6619
|
+
}
|
|
6620
|
+
/** Drop a settled run's Stop: its flag and its abort controller. */
|
|
6621
|
+
forgetCancel(runId) {
|
|
6622
|
+
this.cancelled.delete(runId);
|
|
6623
|
+
this.aborts.delete(runId);
|
|
6624
|
+
}
|
|
6572
6625
|
/**
|
|
6573
6626
|
* The single place a cancelled run's state is settled: recorded as its own terminal (never
|
|
6574
6627
|
* `failed` — a user pressing Stop must not land in someone's error rate), the thread released, and
|
|
@@ -6688,6 +6741,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6688
6741
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
6689
6742
|
parallel: import_nestjs_agent_core37.settleAll,
|
|
6690
6743
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
6744
|
+
abortSignal: this.abortSignalFor(runId),
|
|
6691
6745
|
runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested({
|
|
6692
6746
|
agentName,
|
|
6693
6747
|
task,
|
|
@@ -6739,6 +6793,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6739
6793
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
6740
6794
|
parallel: import_nestjs_agent_core37.settleAll,
|
|
6741
6795
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
6796
|
+
abortSignal: this.abortSignalFor(runId),
|
|
6742
6797
|
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
6743
6798
|
agentName: childName,
|
|
6744
6799
|
task: childTask,
|
|
@@ -6814,7 +6869,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6814
6869
|
}
|
|
6815
6870
|
});
|
|
6816
6871
|
}).finally(async () => {
|
|
6817
|
-
this.
|
|
6872
|
+
this.forgetCancel(runId);
|
|
6818
6873
|
await this.store.setActiveStream(subThread.id, null);
|
|
6819
6874
|
});
|
|
6820
6875
|
return {
|
|
@@ -6846,6 +6901,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
6846
6901
|
// A child stops when it is cancelled OR when the run a human is actually watching is: the
|
|
6847
6902
|
// canceller names the top-level run, which is the only id that ever left the server.
|
|
6848
6903
|
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId) || this.cancelled.has(sinkRunId), "cancelled"),
|
|
6904
|
+
// Aborted by a Stop on the run the human is watching, which is the id a canceller names.
|
|
6905
|
+
abortSignal: this.abortSignalFor(sinkRunId),
|
|
6849
6906
|
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
6850
6907
|
agentName: childName,
|
|
6851
6908
|
task: childTask,
|