@dudousxd/nestjs-agent 0.11.1 → 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.
@@ -31,10 +31,10 @@ __export(durable_exports, {
31
31
  module.exports = __toCommonJS(durable_exports);
32
32
 
33
33
  // src/durable/agent-run.workflow.ts
34
- var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
35
- var import_nestjs_durable = require("@dudousxd/nestjs-durable");
34
+ var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
35
+ var import_nestjs_durable2 = require("@dudousxd/nestjs-durable");
36
36
  var import_nestjs_durable_core = require("@dudousxd/nestjs-durable-core");
37
- var import_common = require("@nestjs/common");
37
+ var import_common2 = require("@nestjs/common");
38
38
 
39
39
  // src/agent-deps.ts
40
40
  function utcDay(date = /* @__PURE__ */ new Date()) {
@@ -52,10 +52,10 @@ function childSinkWriter(writer) {
52
52
  }
53
53
  __name(childSinkWriter, "childSinkWriter");
54
54
 
55
- // src/durable/dispatched-steps.token.ts
56
- var AGENT_DISPATCHED_STEPS = Symbol.for("@dudousxd/nestjs-agent:dispatched-steps");
57
-
58
- // src/durable/agent-run.workflow.ts
55
+ // src/durable/agent-run.steps.ts
56
+ var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
57
+ var import_nestjs_durable = require("@dudousxd/nestjs-durable");
58
+ var import_common = require("@nestjs/common");
59
59
  function _ts_decorate(decorators, target, key, desc) {
60
60
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
61
61
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -73,34 +73,236 @@ function _ts_param(paramIndex, decorator) {
73
73
  };
74
74
  }
75
75
  __name(_ts_param, "_ts_param");
76
+ var AgentRunSteps = class {
77
+ static {
78
+ __name(this, "AgentRunSteps");
79
+ }
80
+ factory;
81
+ constructor(factory) {
82
+ this.factory = factory;
83
+ }
84
+ /**
85
+ * Retryable: every side effect (persist/quota/stream markers) happens loop-side under
86
+ * `hooks.step`, so a durable retry only re-runs the model call and re-streams its tokens — never
87
+ * double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
88
+ * across however many turns/retries it takes.
89
+ */
90
+ async llm(input) {
91
+ const deps = this.factory.forAgent(input.agentName);
92
+ const tools = (0, import_nestjs_agent_core.withMemoryTool)({
93
+ tools: (0, import_nestjs_agent_core.withSkillTool)({
94
+ tools: (0, import_nestjs_agent_core.withAskTool)({
95
+ tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList),
96
+ ask: deps.ask
97
+ }),
98
+ enabled: deps.skills !== void 0
99
+ }),
100
+ enabled: deps.memory?.provider.write !== void 0
101
+ });
102
+ const buffer = input.bufferOutput === true ? (0, import_nestjs_agent_core.createFrameBuffer)() : void 0;
103
+ let writer;
104
+ if (buffer !== void 0) {
105
+ writer = buffer.writer;
106
+ } else {
107
+ const opened = await deps.sink.open(input.sinkRunId);
108
+ writer = input.childSink ? childSinkWriter(opened) : opened;
109
+ }
110
+ const turn = await (0, import_nestjs_agent_core.traceLlmTurn)(input.runId, input.step, () => deps.model.runTurn({
111
+ system: input.system,
112
+ messages: input.messages,
113
+ tools,
114
+ sink: writer
115
+ }));
116
+ return buffer === void 0 ? turn : {
117
+ ...turn,
118
+ bufferedFrames: buffer.frames()
119
+ };
120
+ }
121
+ /**
122
+ * NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
123
+ * above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
124
+ * invocation (a DB deadlock, a lock-wait timeout — see `isTransientToolError`): the server rolled
125
+ * that work back, so re-invoking it is safe, and doing it here (inside this one step, never a new
126
+ * checkpoint) is exactly how the non-dispatched loop path handles it too. The timeout is applied
127
+ * HERE, handler-side, via `withToolTimeout` — never as a durable dispatch `timeoutMs`, which
128
+ * bounds engine liveness (retryable) rather than the tool's own business outcome — and per
129
+ * ATTEMPT, so a retried invocation gets its own fresh timeout window.
130
+ */
131
+ async tool(input) {
132
+ const deps = this.factory.forAgent(input.ctx.agentName);
133
+ if (deps.registry.spec(input.toolName)?.kind === "action" && input.toolType !== "action") {
134
+ throw new Error(`tool "${input.toolName}" is an action tool but was dispatched without approval: the dispatching process resolved its kind against a registry that does not have it`);
135
+ }
136
+ const ctx = {
137
+ ...input.ctx
138
+ };
139
+ const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
140
+ const transientRetry = input.transientRetry === false ? false : {
141
+ attempts: input.transientRetry.attempts,
142
+ backoffMs: input.transientRetry.backoffMs,
143
+ ...localClassify !== void 0 ? {
144
+ classify: localClassify
145
+ } : {}
146
+ };
147
+ return (0, import_nestjs_agent_core.traceToolExecution)(input.ctx.runId, {
148
+ toolCallId: input.toolCallId,
149
+ toolName: input.toolName,
150
+ toolType: input.toolType
151
+ }, () => (0, import_nestjs_agent_core.invokeWithTransientRetry)(() => {
152
+ const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
153
+ return input.timeoutMs !== void 0 ? (0, import_nestjs_agent_core.withToolTimeout)(invocation, input.timeoutMs, input.toolName) : invocation;
154
+ }, transientRetry, {
155
+ onRetry: /* @__PURE__ */ __name((attempt, error) => {
156
+ (0, import_nestjs_agent_core.publishAgentToolRetry)({
157
+ toolName: input.toolName,
158
+ toolCallId: input.toolCallId,
159
+ attempt,
160
+ message: error instanceof Error ? error.message : String(error)
161
+ });
162
+ }, "onRetry")
163
+ }));
164
+ }
165
+ };
166
+ _ts_decorate([
167
+ (0, import_nestjs_durable.Step)({
168
+ retries: 3
169
+ }),
170
+ _ts_metadata("design:type", Function),
171
+ _ts_metadata("design:paramtypes", [
172
+ typeof DispatchedLlmInput === "undefined" ? Object : DispatchedLlmInput
173
+ ]),
174
+ _ts_metadata("design:returntype", Promise)
175
+ ], AgentRunSteps.prototype, "llm", null);
176
+ _ts_decorate([
177
+ (0, import_nestjs_durable.Step)(),
178
+ _ts_metadata("design:type", Function),
179
+ _ts_metadata("design:paramtypes", [
180
+ typeof DispatchedToolInput === "undefined" ? Object : DispatchedToolInput
181
+ ]),
182
+ _ts_metadata("design:returntype", Promise)
183
+ ], AgentRunSteps.prototype, "tool", null);
184
+ AgentRunSteps = _ts_decorate([
185
+ (0, import_common.Injectable)(),
186
+ _ts_param(0, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_DEPS_FACTORY)),
187
+ _ts_metadata("design:type", Function),
188
+ _ts_metadata("design:paramtypes", [
189
+ typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
190
+ ])
191
+ ], AgentRunSteps);
192
+
193
+ // src/durable/dispatched-steps.token.ts
194
+ var AGENT_DISPATCHED_STEPS = Symbol.for("@dudousxd/nestjs-agent:dispatched-steps");
195
+
196
+ // src/durable/agent-run.workflow.ts
197
+ function _ts_decorate2(decorators, target, key, desc) {
198
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
199
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
200
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
201
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
202
+ }
203
+ __name(_ts_decorate2, "_ts_decorate");
204
+ function _ts_metadata2(k, v) {
205
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
206
+ }
207
+ __name(_ts_metadata2, "_ts_metadata");
208
+ function _ts_param2(paramIndex, decorator) {
209
+ return function(target, key) {
210
+ decorator(target, key, paramIndex);
211
+ };
212
+ }
213
+ __name(_ts_param2, "_ts_param");
76
214
  var AgentRunWorkflow = class _AgentRunWorkflow {
77
215
  static {
78
216
  __name(this, "AgentRunWorkflow");
79
217
  }
80
218
  factory;
81
219
  store;
82
- steps;
83
220
  dispatchedSteps;
84
- constructor(factory, store, steps, dispatchedSteps) {
221
+ runs;
222
+ constructor(factory, store, dispatchedSteps, runs) {
85
223
  this.factory = factory;
86
224
  this.store = store;
87
- this.steps = steps;
88
225
  this.dispatchedSteps = dispatchedSteps;
226
+ this.runs = runs;
227
+ }
228
+ /**
229
+ * Has someone asked this run to stop? Read from the runtime's own run status, which is where
230
+ * `DurableAgentRunner.cancel` puts it — `cancelling` while a compensating cancel is in flight,
231
+ * `cancelled` once it has settled.
232
+ *
233
+ * Costs a run read at each of the loop's observation points (two per step). That is a row the
234
+ * control plane already has, against a turn that is otherwise making model calls, and it buys the
235
+ * property that matters: the answer comes from a place BOTH the canceller and every pod that might
236
+ * replay this run can see.
237
+ *
238
+ * Failing to ask is not a cancel. A tenant with no gateway wired, or an operator briefly
239
+ * unreachable, answers "no" and the run carries on — the alternative is failing healthy runs
240
+ * because a status read timed out. The loop journals that answer like any other, so two processes
241
+ * can never disagree about what was seen here.
242
+ */
243
+ async isCancelled(runId) {
244
+ try {
245
+ const status = (await this.runs?.getRunDetail(runId))?.run.status;
246
+ return status === "cancelled" || status === "cancelling";
247
+ } catch {
248
+ return false;
249
+ }
250
+ }
251
+ /**
252
+ * Settle the delegation a DETACHED run was started for, when that run ends without an answer.
253
+ *
254
+ * The loop delivers its own success (`deliver:detached`) but cannot catch its own crash, and the
255
+ * runtime settles the run row without knowing anything delegated it. Left alone, the card in the
256
+ * calling conversation says "started" for ever — the one state a reader can neither wait on nor
257
+ * act on. A no-op for every other run: only a detached one carries a delivery address.
258
+ */
259
+ async settleDetachedParent(ctx, input, outcome) {
260
+ const delivery = input.deliverTo;
261
+ if (delivery === void 0) {
262
+ return;
263
+ }
264
+ await ctx.localStep("deliver:detached:unsettled", () => (0, import_nestjs_agent_core2.settleUnsettledDelegation)({
265
+ store: this.store,
266
+ delivery,
267
+ agent: input.agentName ?? "default",
268
+ runId: ctx.runId,
269
+ status: outcome.status,
270
+ ...outcome.error !== void 0 ? {
271
+ error: outcome.error
272
+ } : {}
273
+ }));
89
274
  }
90
275
  async run(ctx, input) {
91
276
  const day = input.day ?? utcDay();
92
277
  const deps = this.factory.forAgent(input.agentName);
93
- const dispatchSteps = this.dispatchedSteps ? this.steps : void 0;
94
- if (input.sinkRunId !== void 0) {
278
+ const dispatchSteps = this.dispatchedSteps && await ctx.patched("agent:dispatched-steps");
279
+ if (input.sinkRunId !== void 0 || input.deliverTo !== void 0) {
95
280
  await ctx.localStep("activate", () => this.store.setActiveStream(input.threadId, ctx.runId));
96
281
  }
97
282
  const sinkRunId = input.sinkRunId ?? ctx.runId;
283
+ const chainBelow = [
284
+ ...input.delegationPath ?? [],
285
+ ...input.agentName !== void 0 ? [
286
+ input.agentName
287
+ ] : []
288
+ ];
98
289
  const hooks = {
99
290
  runId: ctx.runId,
100
291
  // A child forwards into the top-level sink but must not end/fail it (the top-level run owns it).
101
292
  openSink: /* @__PURE__ */ __name(async () => input.sinkRunId !== void 0 ? childSinkWriter(await deps.sink.open(sinkRunId)) : deps.sink.open(ctx.runId), "openSink"),
102
293
  awaitApproval: /* @__PURE__ */ __name((call) => ctx.waitForSignal(`tool:${ctx.runId}:${call.id}`), "awaitApproval"),
294
+ // The same wait, on the same signal key, carrying a typed answer instead of a yes/no — so a
295
+ // question set and an approval reach a parked run through one path, and the HTTP surface that
296
+ // settles either one is the same `POST /agent/tool-call/*` family.
297
+ awaitAnswers: /* @__PURE__ */ __name((request) => ctx.waitForSignal(`tool:${ctx.runId}:${request.id}`), "awaitAnswers"),
103
298
  step: /* @__PURE__ */ __name((name, fn) => ctx.localStep(name, fn), "step"),
299
+ // Both durable step primitives take their checkpoint position on the CALL, before their first
300
+ // await, so launching a batch in one tick — what `settleAll` does — fixes the block of
301
+ // positions in call order however the tools then settle. `ctx.patched` keeps a run that
302
+ // recorded the one-call-at-a-time shape replaying against that shape.
303
+ parallel: import_nestjs_agent_core2.settleAll,
304
+ cancelled: /* @__PURE__ */ __name(() => this.isCancelled(ctx.runId), "cancelled"),
305
+ patched: /* @__PURE__ */ __name((id) => ctx.patched(id), "patched"),
104
306
  // Dispatched-step suspends must escape the loop's tool catch — control flow, not a tool
105
307
  // failure. Marker-based predicate, NOT instanceof: the signal's CLASS differs by runtime
106
308
  // (engine in-process throws durable-core's WorkflowSuspended/ContinueAsNew; the BullMQ thin
@@ -121,15 +323,54 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
121
323
  userText: task,
122
324
  day,
123
325
  delegationDepth: (input.delegationDepth ?? 0) + 1,
326
+ delegationPath: chainBelow,
327
+ parentRunId: ctx.runId,
124
328
  sinkRunId
125
329
  });
126
330
  }, "runAgent"),
331
+ // The same delegation, not awaited: `ctx.startChild` records a `spawn:<childRunId>` at this
332
+ // position and returns, so THIS turn ends while the child is still working. Two things the
333
+ // awaited form does are deliberately left off:
334
+ // - no `sinkRunId`. A detached run owns its own stream. Forwarding it into the turn that
335
+ // started it would write tokens, and a pending action-tool frame, into a stream whose
336
+ // reader has already seen `done` — and would put the child's approval card in whatever
337
+ // turn happened to be open. Its approval goes to the pending-approvals surface instead,
338
+ // which it reaches for free: the call is persisted `pending_approval` against the child's
339
+ // OWN runId, and that is what `runForToolCall` answers with.
340
+ // - `deliverTo` instead. The parent's tool result is a receipt, so the answer needs an
341
+ // address of its own, and by the time it exists nobody is holding one.
342
+ startAgent: /* @__PURE__ */ __name(async ({ agentName, task, toolCallId: toolCallId2 }) => {
343
+ const subThreadId = await ctx.localStep(`subthread:${agentName}`, async () => {
344
+ const thread = await this.store.createThread({
345
+ actor: input.actor,
346
+ transient: true
347
+ });
348
+ return thread.id;
349
+ });
350
+ const childRunId = await ctx.startChild(_AgentRunWorkflow, {
351
+ agentName,
352
+ threadId: subThreadId,
353
+ actor: input.actor,
354
+ userText: task,
355
+ day,
356
+ delegationDepth: (input.delegationDepth ?? 0) + 1,
357
+ delegationPath: chainBelow,
358
+ parentRunId: ctx.runId,
359
+ deliverTo: {
360
+ threadId: input.threadId,
361
+ toolCallId: toolCallId2
362
+ }
363
+ });
364
+ return {
365
+ runId: childRunId
366
+ };
367
+ }, "startAgent"),
127
368
  // Routes the two long steps through AgentRunSteps as engine-dispatched `ctx.step`s instead of
128
369
  // `ctx.localStep`s, so a turn isn't pinned to this workflow worker for the model call or a tool
129
370
  // execution. `sinkRunId`/`childSink` are sink routing this workflow already resolved above —
130
371
  // core's dispatchLlm signature stays sink-topology-agnostic, so we add them here, not in core.
131
- ...dispatchSteps !== void 0 ? {
132
- dispatchLlm: /* @__PURE__ */ __name((index, envelope) => ctx.step(dispatchSteps.llm, {
372
+ ...dispatchSteps ? {
373
+ dispatchLlm: /* @__PURE__ */ __name((index, envelope) => ctx.step(AgentRunSteps.prototype.llm, {
133
374
  ...envelope,
134
375
  runId: ctx.runId,
135
376
  step: index,
@@ -141,7 +382,7 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
141
382
  // ('agent'-kind delegations branch to runAgent earlier in the loop), so anything that
142
383
  // isn't 'action' is defensively 'read' — the same posture core takes for an
143
384
  // unresolvable `kind`.
144
- dispatchTool: /* @__PURE__ */ __name((call, envelope) => ctx.step(dispatchSteps.tool, {
385
+ dispatchTool: /* @__PURE__ */ __name((call, envelope) => ctx.step(AgentRunSteps.prototype.tool, {
145
386
  ...envelope,
146
387
  toolCallId: call.id,
147
388
  toolType: call.kind === "action" ? "action" : "read"
@@ -149,7 +390,7 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
149
390
  } : {}
150
391
  };
151
392
  try {
152
- const result = await (0, import_nestjs_agent_core.runAgentLoop)({
393
+ const result = await (0, import_nestjs_agent_core2.runAgentLoop)({
153
394
  ...deps,
154
395
  day
155
396
  }, input, hooks);
@@ -159,9 +400,28 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
159
400
  if ((0, import_nestjs_durable_core.isWorkflowControlFlowSignal)(error)) {
160
401
  throw error;
161
402
  }
403
+ if (error instanceof import_nestjs_agent_core2.RunCancelledError) {
404
+ await ctx.localStep("deactivate", () => this.store.setActiveStream(input.threadId, null));
405
+ await this.settleDetachedParent(ctx, input, {
406
+ status: "cancelled"
407
+ });
408
+ throw error;
409
+ }
410
+ if ((0, import_nestjs_agent_core2.isReplayIntegrityError)(error)) {
411
+ const failure = {
412
+ code: "run_failed",
413
+ message: error.message
414
+ };
415
+ (0, import_nestjs_agent_core2.publishAgentRunFailed)({
416
+ runId: ctx.runId,
417
+ ...failure
418
+ });
419
+ await (await hooks.openSink()).fail(failure);
420
+ throw error;
421
+ }
162
422
  const message = error instanceof Error ? error.message : String(error);
163
- const code = error instanceof import_nestjs_agent_core.QuotaExceededError ? "quota_exceeded" : "run_failed";
164
- (0, import_nestjs_agent_core.publishAgentRunFailed)({
423
+ const code = (0, import_nestjs_agent_core2.agentFailureCode)(error);
424
+ (0, import_nestjs_agent_core2.publishAgentRunFailed)({
165
425
  runId: ctx.runId,
166
426
  code,
167
427
  message
@@ -173,6 +433,10 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
173
433
  errorMessage: message
174
434
  }) ?? Promise.resolve());
175
435
  await ctx.localStep("deactivate", () => this.store.setActiveStream(input.threadId, null));
436
+ await this.settleDetachedParent(ctx, input, {
437
+ status: "failed",
438
+ error: message
439
+ });
176
440
  const writer = await hooks.openSink();
177
441
  await writer.fail({
178
442
  code,
@@ -182,143 +446,29 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
182
446
  }
183
447
  }
184
448
  };
185
- AgentRunWorkflow = _ts_decorate([
186
- (0, import_common.Injectable)(),
187
- (0, import_nestjs_durable.Workflow)({
449
+ AgentRunWorkflow = _ts_decorate2([
450
+ (0, import_common2.Injectable)(),
451
+ (0, import_nestjs_durable2.Workflow)({
188
452
  name: "agent.run",
189
453
  version: "1"
190
454
  }),
191
- _ts_param(0, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_DEPS_FACTORY)),
192
- _ts_param(1, (0, import_common.Inject)(import_nestjs_agent_core.AGENT_STORE)),
193
- _ts_param(2, (0, import_common.Optional)()),
194
- _ts_param(3, (0, import_common.Inject)(AGENT_DISPATCHED_STEPS)),
195
- _ts_metadata("design:type", Function),
196
- _ts_metadata("design:paramtypes", [
197
- typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
198
- typeof AgentStore === "undefined" ? Object : AgentStore,
199
- Object,
200
- Boolean
201
- ])
202
- ], AgentRunWorkflow);
203
-
204
- // src/durable/agent-run.steps.ts
205
- var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
206
- var import_nestjs_durable2 = require("@dudousxd/nestjs-durable");
207
- var import_common2 = require("@nestjs/common");
208
- function _ts_decorate2(decorators, target, key, desc) {
209
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
210
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
211
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
212
- return c > 3 && r && Object.defineProperty(target, key, r), r;
213
- }
214
- __name(_ts_decorate2, "_ts_decorate");
215
- function _ts_metadata2(k, v) {
216
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
217
- }
218
- __name(_ts_metadata2, "_ts_metadata");
219
- function _ts_param2(paramIndex, decorator) {
220
- return function(target, key) {
221
- decorator(target, key, paramIndex);
222
- };
223
- }
224
- __name(_ts_param2, "_ts_param");
225
- var AgentRunSteps = class {
226
- static {
227
- __name(this, "AgentRunSteps");
228
- }
229
- factory;
230
- constructor(factory) {
231
- this.factory = factory;
232
- }
233
- /**
234
- * Retryable: every side effect (persist/quota/stream markers) happens loop-side under
235
- * `hooks.step`, so a durable retry only re-runs the model call and re-streams its tokens — never
236
- * double-writes. NEVER call `writer.end()`/`fail()` here: the workflow owns the stream's lifecycle,
237
- * across however many turns/retries it takes.
238
- */
239
- async llm(input) {
240
- const deps = this.factory.forAgent(input.agentName);
241
- const tools = await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList);
242
- const opened = await deps.sink.open(input.sinkRunId);
243
- const writer = input.childSink ? childSinkWriter(opened) : opened;
244
- return (0, import_nestjs_agent_core2.traceLlmTurn)(input.runId, input.step, () => deps.model.runTurn({
245
- system: input.system,
246
- messages: input.messages,
247
- tools,
248
- sink: writer
249
- }));
250
- }
251
- /**
252
- * NO DURABLE retries — a tool may not be idempotent (a bare `@Step()` carries none, unlike `llm`
253
- * above). What it does retry, in place, is a CLASSIFIED-TRANSIENT error from the tool's own
254
- * invocation (a DB deadlock, a lock-wait timeout — see `isTransientToolError`): the server rolled
255
- * that work back, so re-invoking it is safe, and doing it here (inside this one step, never a new
256
- * checkpoint) is exactly how the non-dispatched loop path handles it too. The timeout is applied
257
- * HERE, handler-side, via `withToolTimeout` — never as a durable dispatch `timeoutMs`, which
258
- * bounds engine liveness (retryable) rather than the tool's own business outcome — and per
259
- * ATTEMPT, so a retried invocation gets its own fresh timeout window.
260
- */
261
- async tool(input) {
262
- const deps = this.factory.forAgent(input.ctx.agentName);
263
- const ctx = {
264
- ...input.ctx
265
- };
266
- const localClassify = deps.toolTransientRetry !== false ? deps.toolTransientRetry?.classify : void 0;
267
- const transientRetry = input.transientRetry === false ? false : {
268
- attempts: input.transientRetry.attempts,
269
- backoffMs: input.transientRetry.backoffMs,
270
- ...localClassify !== void 0 ? {
271
- classify: localClassify
272
- } : {}
273
- };
274
- return (0, import_nestjs_agent_core2.traceToolExecution)(input.ctx.runId, {
275
- toolCallId: input.toolCallId,
276
- toolName: input.toolName,
277
- toolType: input.toolType
278
- }, () => (0, import_nestjs_agent_core2.invokeWithTransientRetry)(() => {
279
- const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
280
- return input.timeoutMs !== void 0 ? (0, import_nestjs_agent_core2.withToolTimeout)(invocation, input.timeoutMs, input.toolName) : invocation;
281
- }, transientRetry, {
282
- onRetry: /* @__PURE__ */ __name((attempt, error) => {
283
- (0, import_nestjs_agent_core2.publishAgentToolRetry)({
284
- toolName: input.toolName,
285
- toolCallId: input.toolCallId,
286
- attempt,
287
- message: error instanceof Error ? error.message : String(error)
288
- });
289
- }, "onRetry")
290
- }));
291
- }
292
- };
293
- _ts_decorate2([
294
- (0, import_nestjs_durable2.Step)({
295
- retries: 3
296
- }),
297
- _ts_metadata2("design:type", Function),
298
- _ts_metadata2("design:paramtypes", [
299
- typeof DispatchedLlmInput === "undefined" ? Object : DispatchedLlmInput
300
- ]),
301
- _ts_metadata2("design:returntype", Promise)
302
- ], AgentRunSteps.prototype, "llm", null);
303
- _ts_decorate2([
304
- (0, import_nestjs_durable2.Step)(),
305
- _ts_metadata2("design:type", Function),
306
- _ts_metadata2("design:paramtypes", [
307
- typeof DispatchedToolInput === "undefined" ? Object : DispatchedToolInput
308
- ]),
309
- _ts_metadata2("design:returntype", Promise)
310
- ], AgentRunSteps.prototype, "tool", null);
311
- AgentRunSteps = _ts_decorate2([
312
- (0, import_common2.Injectable)(),
313
455
  _ts_param2(0, (0, import_common2.Inject)(import_nestjs_agent_core2.AGENT_DEPS_FACTORY)),
456
+ _ts_param2(1, (0, import_common2.Inject)(import_nestjs_agent_core2.AGENT_STORE)),
457
+ _ts_param2(2, (0, import_common2.Inject)(AGENT_DISPATCHED_STEPS)),
458
+ _ts_param2(3, (0, import_common2.Optional)()),
459
+ _ts_param2(3, (0, import_common2.Inject)(import_nestjs_durable2.RUN_GATEWAY)),
314
460
  _ts_metadata2("design:type", Function),
315
461
  _ts_metadata2("design:paramtypes", [
316
- typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
462
+ typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
463
+ typeof AgentStore === "undefined" ? Object : AgentStore,
464
+ Boolean,
465
+ typeof RunGateway === "undefined" ? Object : RunGateway
317
466
  ])
318
- ], AgentRunSteps);
467
+ ], AgentRunWorkflow);
319
468
 
320
469
  // src/durable/durable-agent-runner.ts
321
470
  var import_node_crypto = require("crypto");
471
+ var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
322
472
  var import_nestjs_durable3 = require("@dudousxd/nestjs-durable");
323
473
  var import_nestjs_durable_core2 = require("@dudousxd/nestjs-durable-core");
324
474
  var import_common3 = require("@nestjs/common");
@@ -333,13 +483,26 @@ function _ts_metadata3(k, v) {
333
483
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
334
484
  }
335
485
  __name(_ts_metadata3, "_ts_metadata");
336
- var DurableAgentRunner = class {
486
+ function _ts_param3(paramIndex, decorator) {
487
+ return function(target, key) {
488
+ decorator(target, key, paramIndex);
489
+ };
490
+ }
491
+ __name(_ts_param3, "_ts_param");
492
+ var DurableAgentRunner = class _DurableAgentRunner {
337
493
  static {
338
494
  __name(this, "DurableAgentRunner");
339
495
  }
340
496
  workflows;
341
- constructor(workflows) {
497
+ runs;
498
+ store;
499
+ sink;
500
+ logger = new import_common3.Logger(_DurableAgentRunner.name);
501
+ constructor(workflows, runs, store, sink) {
342
502
  this.workflows = workflows;
503
+ this.runs = runs;
504
+ this.store = store;
505
+ this.sink = sink;
343
506
  }
344
507
  async start(input) {
345
508
  const stamped = {
@@ -358,27 +521,62 @@ var DurableAgentRunner = class {
358
521
  runId
359
522
  };
360
523
  }
361
- async signal(runId, toolCallId, decision) {
362
- await this.workflows.signal(`tool:${runId}:${toolCallId}`, decision);
524
+ async signal(runId, toolCallId2, reply) {
525
+ await this.workflows.signal(`tool:${runId}:${toolCallId2}`, reply);
363
526
  }
364
- async cancel(_runId) {
365
- await Promise.resolve();
527
+ /**
528
+ * Stop a run, and settle what the durable runtime knows nothing about.
529
+ *
530
+ * `compensate: true` is the form that gives the BODY a chance: it moves the run to `cancelling`
531
+ * (which is what the workflow's own cancel observation reads) and then re-drives it, so a turn
532
+ * running in-process unwinds at its next safe point instead of finishing. It also guarantees the
533
+ * outcome for the turn that CANNOT observe anything — one parked on `waitForSignal`, suspended
534
+ * inside a position its journal already holds — because that re-drive re-suspends and the runtime
535
+ * settles the run `cancelled` regardless. The cascade to child runs comes with it.
536
+ *
537
+ * Neither of those settles the agent's own state, so this does: the run row gets its own terminal,
538
+ * and the subscriber gets a `cancelled` frame followed by a normal end. Both are keyed by runId
539
+ * alone, which is why they belong here rather than in the body — the body is the only place that
540
+ * knows which THREAD was streaming, so releasing that stays there (see `AgentRunWorkflow`).
541
+ *
542
+ * A tool already executing is not interrupted, here or anywhere: see `haltIfCancelled` in core.
543
+ */
544
+ async cancel(runId) {
545
+ this.logger.log(`cancelling agent run ${runId}`);
546
+ await this.runs.cancel(runId, {
547
+ compensate: true
548
+ });
549
+ const writer = await this.sink.open(runId);
550
+ await writer.write((0, import_nestjs_agent_core3.encodeStreamEvent)({
551
+ kind: "cancelled"
552
+ }));
553
+ await writer.end();
554
+ await this.store.recordRunEnd?.({
555
+ runId,
556
+ status: "cancelled"
557
+ });
366
558
  }
367
559
  };
368
560
  DurableAgentRunner = _ts_decorate3([
369
561
  (0, import_common3.Injectable)(),
562
+ _ts_param3(1, (0, import_common3.Inject)(import_nestjs_durable3.RUN_GATEWAY)),
563
+ _ts_param3(2, (0, import_common3.Inject)(import_nestjs_agent_core3.AGENT_STORE)),
564
+ _ts_param3(3, (0, import_common3.Inject)(import_nestjs_agent_core3.AGENT_SINK)),
370
565
  _ts_metadata3("design:type", Function),
371
566
  _ts_metadata3("design:paramtypes", [
372
- typeof import_nestjs_durable3.WorkflowService === "undefined" ? Object : import_nestjs_durable3.WorkflowService
567
+ typeof import_nestjs_durable3.WorkflowService === "undefined" ? Object : import_nestjs_durable3.WorkflowService,
568
+ typeof RunGateway === "undefined" ? Object : RunGateway,
569
+ typeof AgentStore === "undefined" ? Object : AgentStore,
570
+ typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink
373
571
  ])
374
572
  ], DurableAgentRunner);
375
573
 
376
574
  // src/durable/agent-durable.module.ts
377
- var import_nestjs_agent_core4 = require("@dudousxd/nestjs-agent-core");
575
+ var import_nestjs_agent_core5 = require("@dudousxd/nestjs-agent-core");
378
576
  var import_common4 = require("@nestjs/common");
379
577
 
380
578
  // src/in-process-sink.ts
381
- var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
579
+ var import_nestjs_agent_core4 = require("@dudousxd/nestjs-agent-core");
382
580
  var InProcessTokenStreamSink = class {
383
581
  static {
384
582
  __name(this, "InProcessTokenStreamSink");
@@ -433,7 +631,7 @@ var InProcessTokenStreamSink = class {
433
631
  }
434
632
  if (buf.ended) {
435
633
  if (buf.failure !== void 0) {
436
- throw new import_nestjs_agent_core3.AgentStreamError(buf.failure);
634
+ throw new import_nestjs_agent_core4.AgentStreamError(buf.failure);
437
635
  }
438
636
  return;
439
637
  }
@@ -458,7 +656,7 @@ function runnerProviders() {
458
656
  return [
459
657
  DurableAgentRunner,
460
658
  {
461
- provide: import_nestjs_agent_core4.AGENT_DURABLE_RUNNER,
659
+ provide: import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
462
660
  useExisting: DurableAgentRunner
463
661
  },
464
662
  {
@@ -471,8 +669,8 @@ function runnerProviders() {
471
669
  return enabled;
472
670
  }, "useFactory"),
473
671
  inject: [
474
- import_nestjs_agent_core4.AGENT_OPTIONS,
475
- import_nestjs_agent_core4.AGENT_SINK
672
+ import_nestjs_agent_core5.AGENT_OPTIONS,
673
+ import_nestjs_agent_core5.AGENT_SINK
476
674
  ]
477
675
  }
478
676
  ];
@@ -491,7 +689,7 @@ AgentDurableHttpModule = _ts_decorate4([
491
689
  ...runnerProviders()
492
690
  ],
493
691
  exports: [
494
- import_nestjs_agent_core4.AGENT_DURABLE_RUNNER,
692
+ import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
495
693
  AgentRunWorkflow,
496
694
  AGENT_DISPATCHED_STEPS
497
695
  ]
@@ -531,7 +729,7 @@ AgentDurableModule = _ts_decorate4([
531
729
  ...runnerProviders()
532
730
  ],
533
731
  exports: [
534
- import_nestjs_agent_core4.AGENT_DURABLE_RUNNER,
732
+ import_nestjs_agent_core5.AGENT_DURABLE_RUNNER,
535
733
  AgentRunWorkflow,
536
734
  AgentRunSteps,
537
735
  AGENT_DISPATCHED_STEPS
@@ -540,13 +738,13 @@ AgentDurableModule = _ts_decorate4([
540
738
  ], AgentDurableModule);
541
739
 
542
740
  // src/agent.module.ts
543
- var import_nestjs_agent_core17 = require("@dudousxd/nestjs-agent-core");
544
- var import_common17 = require("@nestjs/common");
545
- var import_core3 = require("@nestjs/core");
741
+ var import_nestjs_agent_core23 = require("@dudousxd/nestjs-agent-core");
742
+ var import_common20 = require("@nestjs/common");
743
+ var import_core4 = require("@nestjs/core");
546
744
 
547
745
  // src/agent-deps.factory.ts
548
- var import_nestjs_agent_core5 = require("@dudousxd/nestjs-agent-core");
549
746
  var import_nestjs_agent_core6 = require("@dudousxd/nestjs-agent-core");
747
+ var import_nestjs_agent_core7 = require("@dudousxd/nestjs-agent-core");
550
748
  var import_common5 = require("@nestjs/common");
551
749
  function _ts_decorate5(decorators, target, key, desc) {
552
750
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -559,14 +757,15 @@ function _ts_metadata4(k, v) {
559
757
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
560
758
  }
561
759
  __name(_ts_metadata4, "_ts_metadata");
562
- function _ts_param3(paramIndex, decorator) {
760
+ function _ts_param4(paramIndex, decorator) {
563
761
  return function(target, key) {
564
762
  decorator(target, key, paramIndex);
565
763
  };
566
764
  }
567
- __name(_ts_param3, "_ts_param");
568
- function delegateToolName(target) {
569
- return `ask_${target.replace(/[^a-zA-Z0-9]+/g, "_")}`;
765
+ __name(_ts_param4, "_ts_param");
766
+ function delegateToolName(args) {
767
+ const slug = args.target.replace(/[^a-zA-Z0-9]+/g, "_");
768
+ return args.detached === true ? `start_${slug}` : `ask_${slug}`;
570
769
  }
571
770
  __name(delegateToolName, "delegateToolName");
572
771
  var AgentDepsFactory2 = class {
@@ -583,7 +782,9 @@ var AgentDepsFactory2 = class {
583
782
  promptContributors;
584
783
  quota;
585
784
  pricingStore;
586
- constructor(options, model, store, sink, rolesPolicy, registry, agents, promptContributors, quota, pricingStore) {
785
+ skills;
786
+ memory;
787
+ constructor(options, model, store, sink, rolesPolicy, registry, agents, promptContributors, quota, pricingStore, skills, memory) {
587
788
  this.options = options;
588
789
  this.model = model;
589
790
  this.store = store;
@@ -594,6 +795,16 @@ var AgentDepsFactory2 = class {
594
795
  this.promptContributors = promptContributors;
595
796
  this.quota = quota;
596
797
  this.pricingStore = pricingStore;
798
+ this.skills = skills;
799
+ this.memory = memory;
800
+ }
801
+ /** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
802
+ memoryConfig() {
803
+ return this.memory;
804
+ }
805
+ /** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */
806
+ skillsConfig() {
807
+ return this.skills;
597
808
  }
598
809
  /**
599
810
  * The agent a turn uses when the caller names none: the explicit `defaultAgent` option, else the
@@ -610,7 +821,13 @@ var AgentDepsFactory2 = class {
610
821
  if (definition === void 0) {
611
822
  return void 0;
612
823
  }
613
- const delegated = (definition.delegatesTo ?? []).map(delegateToolName);
824
+ const delegated = (definition.delegatesTo ?? []).map((edge) => {
825
+ const { agent, detached } = (0, import_nestjs_agent_core6.normalizeDelegation)(edge);
826
+ return delegateToolName({
827
+ target: agent,
828
+ detached
829
+ });
830
+ });
614
831
  if (definition.tools === void 0 && delegated.length === 0) {
615
832
  return void 0;
616
833
  }
@@ -625,6 +842,8 @@ var AgentDepsFactory2 = class {
625
842
  const toolAllowList = this.effectiveTools(definition);
626
843
  const followUpsCount = this.followUpsCount();
627
844
  const retrieval = this.options.retrieval;
845
+ const historyPolicy = this.historyPolicy(definition);
846
+ const ask = definition?.ask ?? this.options.ask;
628
847
  return {
629
848
  model: this.model,
630
849
  store: this.store,
@@ -634,6 +853,12 @@ var AgentDepsFactory2 = class {
634
853
  promptContributors: this.promptContributors,
635
854
  systemPrompt: definition?.systemPrompt ?? "You are a helpful assistant.",
636
855
  maxSteps: definition?.maxSteps ?? 8,
856
+ ...definition?.maxDelegationDepth !== void 0 ? {
857
+ maxDelegationDepth: definition.maxDelegationDepth
858
+ } : {},
859
+ ...definition?.maxAgentAppearances !== void 0 ? {
860
+ maxAgentAppearances: definition.maxAgentAppearances
861
+ } : {},
637
862
  ...definition?.modelId !== void 0 ? {
638
863
  modelId: definition.modelId
639
864
  } : {},
@@ -643,6 +868,37 @@ var AgentDepsFactory2 = class {
643
868
  ...this.pricingStore !== void 0 ? {
644
869
  pricingStore: this.pricingStore
645
870
  } : {},
871
+ ...historyPolicy !== void 0 ? {
872
+ historyPolicy
873
+ } : {},
874
+ inputProcessors: this.options.inputProcessors ?? [],
875
+ outputProcessors: this.options.outputProcessors ?? [],
876
+ ...definition?.outputSchema !== void 0 ? {
877
+ outputSchema: definition.outputSchema
878
+ } : {},
879
+ ...definition?.outputRepairAttempts !== void 0 ? {
880
+ outputRepairAttempts: definition.outputRepairAttempts
881
+ } : {},
882
+ ...definition?.intake !== void 0 ? {
883
+ intake: definition.intake
884
+ } : {},
885
+ // Most specific wins, exactly as `historyPolicy` resolves: the agent's own `@Agent({ ask })`,
886
+ // else the module-wide flag. Both are module config, so every process of a deployment agrees.
887
+ ...ask === true ? {
888
+ ask: true
889
+ } : {},
890
+ // Module-wide, never per-agent: a skill is a procedure, not a persona, and an agent that could
891
+ // opt out of one would make the catalog depend on which agent a turn happened to select — a
892
+ // per-turn fact the worker re-deriving the tool list cannot see.
893
+ ...this.skills !== void 0 ? {
894
+ skills: this.skills
895
+ } : {},
896
+ // Module-wide, never per-agent, for the same reason skills are: which memories a turn carries
897
+ // cannot depend on which persona answered it, or the worker re-deriving a dispatched turn's
898
+ // tool list would disagree with the loop about whether `remember` was offered.
899
+ ...this.memory !== void 0 ? {
900
+ memory: this.memory
901
+ } : {},
646
902
  ...toolAllowList !== void 0 ? {
647
903
  toolAllowList
648
904
  } : {},
@@ -663,6 +919,36 @@ var AgentDepsFactory2 = class {
663
919
  } : {}
664
920
  };
665
921
  }
922
+ /**
923
+ * The ceiling on how much of a thread this agent's turns carry, most specific wins: the agent's
924
+ * own `@Agent({ history })`, else a module-wide custom `historyPolicy`, else the module-wide
925
+ * `history` window. Undefined → unbounded, the behaviour of a module that configures none.
926
+ */
927
+ historyPolicy(definition) {
928
+ if (definition?.history !== void 0) {
929
+ return this.window(definition.history);
930
+ }
931
+ if (this.options.historyPolicy !== void 0) {
932
+ return this.options.historyPolicy;
933
+ }
934
+ return this.options.history === void 0 ? void 0 : this.window(this.options.history);
935
+ }
936
+ /** Build the built-in window policy from the declarative `{ maxMessages, maxTokens, summarize }`. */
937
+ window(config) {
938
+ return (0, import_nestjs_agent_core6.windowHistory)({
939
+ ...config.maxMessages !== void 0 ? {
940
+ maxMessages: config.maxMessages
941
+ } : {},
942
+ ...config.maxTokens !== void 0 ? {
943
+ maxTokens: config.maxTokens
944
+ } : {},
945
+ // The shared module model, not a per-agent one: an agent's `modelId` is an accounting label,
946
+ // and only one provider is ever bound.
947
+ ...config.summarize === true ? {
948
+ summarize: (0, import_nestjs_agent_core6.summarizeWithModel)(this.model)
949
+ } : {}
950
+ });
951
+ }
666
952
  /** Normalize the `followUps` option (`true` → 3, `{ count }` → count) to a number, or undefined. */
667
953
  followUpsCount() {
668
954
  const followUps = this.options.followUps;
@@ -677,17 +963,21 @@ var AgentDepsFactory2 = class {
677
963
  };
678
964
  AgentDepsFactory2 = _ts_decorate5([
679
965
  (0, import_common5.Injectable)(),
680
- _ts_param3(0, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_OPTIONS)),
681
- _ts_param3(1, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_MODEL)),
682
- _ts_param3(2, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_STORE)),
683
- _ts_param3(3, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_SINK)),
684
- _ts_param3(4, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_ROLES_POLICY)),
685
- _ts_param3(5, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_TOOL_REGISTRY)),
686
- _ts_param3(6, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_REGISTRY)),
687
- _ts_param3(7, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_PROMPT_CONTRIBUTORS)),
688
- _ts_param3(8, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_QUOTA_STORE)),
689
- _ts_param3(9, (0, import_common5.Optional)()),
690
- _ts_param3(9, (0, import_common5.Inject)(import_nestjs_agent_core5.AGENT_PRICING_STORE)),
966
+ _ts_param4(0, (0, import_common5.Inject)(import_nestjs_agent_core7.AGENT_OPTIONS)),
967
+ _ts_param4(1, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_MODEL)),
968
+ _ts_param4(2, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_STORE)),
969
+ _ts_param4(3, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_SINK)),
970
+ _ts_param4(4, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_ROLES_POLICY)),
971
+ _ts_param4(5, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_TOOL_REGISTRY)),
972
+ _ts_param4(6, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_REGISTRY)),
973
+ _ts_param4(7, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_PROMPT_CONTRIBUTORS)),
974
+ _ts_param4(8, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_QUOTA_STORE)),
975
+ _ts_param4(9, (0, import_common5.Optional)()),
976
+ _ts_param4(9, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_PRICING_STORE)),
977
+ _ts_param4(10, (0, import_common5.Optional)()),
978
+ _ts_param4(10, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_SKILLS)),
979
+ _ts_param4(11, (0, import_common5.Optional)()),
980
+ _ts_param4(11, (0, import_common5.Inject)(import_nestjs_agent_core6.AGENT_MEMORY)),
691
981
  _ts_metadata4("design:type", Function),
692
982
  _ts_metadata4("design:paramtypes", [
693
983
  typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
@@ -695,16 +985,18 @@ AgentDepsFactory2 = _ts_decorate5([
695
985
  typeof AgentStore === "undefined" ? Object : AgentStore,
696
986
  typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
697
987
  typeof RolesPolicy === "undefined" ? Object : RolesPolicy,
698
- typeof import_nestjs_agent_core5.ToolRegistry === "undefined" ? Object : import_nestjs_agent_core5.ToolRegistry,
699
- typeof import_nestjs_agent_core5.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core5.AgentRegistry,
988
+ typeof import_nestjs_agent_core6.ToolRegistry === "undefined" ? Object : import_nestjs_agent_core6.ToolRegistry,
989
+ typeof import_nestjs_agent_core6.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core6.AgentRegistry,
700
990
  Array,
701
991
  Object,
992
+ Object,
993
+ Object,
702
994
  Object
703
995
  ])
704
996
  ], AgentDepsFactory2);
705
997
 
706
998
  // src/agent.service.ts
707
- var import_nestjs_agent_core7 = require("@dudousxd/nestjs-agent-core");
999
+ var import_nestjs_agent_core8 = require("@dudousxd/nestjs-agent-core");
708
1000
  var import_common6 = require("@nestjs/common");
709
1001
  function _ts_decorate6(decorators, target, key, desc) {
710
1002
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -717,12 +1009,12 @@ function _ts_metadata5(k, v) {
717
1009
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
718
1010
  }
719
1011
  __name(_ts_metadata5, "_ts_metadata");
720
- function _ts_param4(paramIndex, decorator) {
1012
+ function _ts_param5(paramIndex, decorator) {
721
1013
  return function(target, key) {
722
1014
  decorator(target, key, paramIndex);
723
1015
  };
724
1016
  }
725
- __name(_ts_param4, "_ts_param");
1017
+ __name(_ts_param5, "_ts_param");
726
1018
  var AgentService = class {
727
1019
  static {
728
1020
  __name(this, "AgentService");
@@ -731,14 +1023,17 @@ var AgentService = class {
731
1023
  store;
732
1024
  deps;
733
1025
  quota;
734
- constructor(runner, store, deps, quota) {
1026
+ staging;
1027
+ constructor(runner, store, deps, quota, staging) {
735
1028
  this.runner = runner;
736
1029
  this.store = store;
737
1030
  this.deps = deps;
738
1031
  this.quota = quota;
1032
+ this.staging = staging;
739
1033
  }
740
1034
  async chat(params) {
741
1035
  const agentName = await this.resolveAgentName(params.agentName, params.threadId);
1036
+ const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
742
1037
  let threadId = params.threadId;
743
1038
  if (threadId === void 0) {
744
1039
  if (params.regenerate === true) {
@@ -763,8 +1058,8 @@ var AgentService = class {
763
1058
  ...params.regenerate === true ? {
764
1059
  regenerate: true
765
1060
  } : {},
766
- ...params.attachments !== void 0 ? {
767
- attachments: params.attachments
1061
+ ...attachments.length > 0 ? {
1062
+ attachments
768
1063
  } : {},
769
1064
  ...params.pageContext !== void 0 ? {
770
1065
  pageContext: params.pageContext
@@ -777,18 +1072,66 @@ var AgentService = class {
777
1072
  threadId
778
1073
  };
779
1074
  }
1075
+ /**
1076
+ * Rebuild this turn's attachments from the staging store, keyed by the ids the caller claimed.
1077
+ * The model provider fetches {@link MessageAttachment.url} verbatim, so that url is only ever
1078
+ * allowed to come from the host's own store — a caller that could name it could point the server
1079
+ * at anything it can reach (cloud metadata, internal services) and read the response back out of
1080
+ * the model's answer.
1081
+ *
1082
+ * No store bound means no way to tell an id the actor owns from one they don't, so a turn simply
1083
+ * cannot carry attachments: 501 rather than trusting the request.
1084
+ */
1085
+ async resolveAttachments(actor, refs) {
1086
+ if (refs.length === 0) {
1087
+ return [];
1088
+ }
1089
+ const staging = this.staging;
1090
+ if (staging === void 0 || typeof staging.resolve !== "function") {
1091
+ throw new import_common6.NotImplementedException("Message attachments require an AGENT_ATTACHMENT_STAGING provider implementing resolve(); attachment urls are never taken from the request.");
1092
+ }
1093
+ const resolved = [];
1094
+ for (const ref of refs) {
1095
+ const attachment = await staging.resolve({
1096
+ mediaId: ref.mediaId,
1097
+ actor
1098
+ });
1099
+ if (attachment === null) {
1100
+ throw new import_common6.ForbiddenException(`attachment ${ref.mediaId} is not available to this actor`);
1101
+ }
1102
+ resolved.push(attachment);
1103
+ }
1104
+ return resolved;
1105
+ }
1106
+ /**
1107
+ * The run's live token stream, WITHOUT an ownership check — for in-process callers that are
1108
+ * already authorized (the MCP bridge, a host's own job code), the same split as
1109
+ * {@link signalToolCall} vs {@link approve}. Anything reachable from a request must go through
1110
+ * {@link subscribeAs} instead: a runId is the only thing standing between a caller and another
1111
+ * actor's answer, tool arguments and tool results.
1112
+ */
780
1113
  subscribe(runId) {
781
1114
  return this.deps.forAgent().sink.subscribe(runId);
782
1115
  }
783
- async approve(actor, toolCallId) {
784
- await this.assertOwnsToolCall(actor, toolCallId);
785
- return this.signalToolCall(toolCallId, {
1116
+ /**
1117
+ * {@link subscribe}, gated the way {@link cancel} is: only the actor whose thread is currently
1118
+ * streaming this run may read it. A run that has already finished is reported missing rather than
1119
+ * replayed — the runner clears the thread's active stream as the run ends, and that field is what
1120
+ * ownership is derived from.
1121
+ */
1122
+ async subscribeAs(actor, runId) {
1123
+ await this.assertOwnsActiveStream(actor, runId);
1124
+ return this.subscribe(runId);
1125
+ }
1126
+ async approve(actor, toolCallId2) {
1127
+ await this.assertOwnsToolCall(actor, toolCallId2);
1128
+ return this.signalToolCall(toolCallId2, {
786
1129
  approved: true
787
1130
  });
788
1131
  }
789
- async reject(actor, toolCallId, reason) {
790
- await this.assertOwnsToolCall(actor, toolCallId);
791
- return this.signalToolCall(toolCallId, {
1132
+ async reject(actor, toolCallId2, reason) {
1133
+ await this.assertOwnsToolCall(actor, toolCallId2);
1134
+ return this.signalToolCall(toolCallId2, {
792
1135
  approved: false,
793
1136
  ...reason !== void 0 ? {
794
1137
  reason
@@ -796,6 +1139,34 @@ var AgentService = class {
796
1139
  });
797
1140
  }
798
1141
  /**
1142
+ * Answer a parked question set. An omitted question takes the request's own pre-picked default —
1143
+ * resolved by the LOOP against the request it already holds, so "the user just submitted" and
1144
+ * "the user picked exactly the defaults" persist as the same answers, and no client has to
1145
+ * re-send what it was shown.
1146
+ */
1147
+ async answer(actor, toolCallId2, answers2 = {}) {
1148
+ await this.assertOwnsToolCall(actor, toolCallId2);
1149
+ const reply = {
1150
+ answers: answers2,
1151
+ answeredByRef: actor.id
1152
+ };
1153
+ return this.signalToolCall(toolCallId2, reply);
1154
+ }
1155
+ /**
1156
+ * Decline to answer and let the agent proceed on its own assumptions. NOT the same as confirming
1157
+ * them: the run records this as a rejection, so a reader auditing what the agent was told can
1158
+ * tell a choice the user made from one they refused to make.
1159
+ */
1160
+ async skip(actor, toolCallId2) {
1161
+ await this.assertOwnsToolCall(actor, toolCallId2);
1162
+ const reply = {
1163
+ answers: {},
1164
+ skipped: true,
1165
+ answeredByRef: actor.id
1166
+ };
1167
+ return this.signalToolCall(toolCallId2, reply);
1168
+ }
1169
+ /**
799
1170
  * The decision core behind approve/reject, WITHOUT an ownership check: resolves the run
800
1171
  * currently awaiting `toolCallId` and signals it. `approve`/`reject` above call this after their
801
1172
  * own `assertOwnsToolCall` gate; the console `AgentApprovalPort` adapter (bound by `AgentModule`)
@@ -803,9 +1174,9 @@ var AgentService = class {
803
1174
  * re-deriving thread ownership here would reject a legitimate operator decision (an operator is
804
1175
  * not the thread's own actor).
805
1176
  */
806
- async signalToolCall(toolCallId, decision) {
807
- const runId = await this.resolveRunForToolCall(toolCallId);
808
- return this.runner.signal(runId, toolCallId, decision);
1177
+ async signalToolCall(toolCallId2, reply) {
1178
+ const runId = await this.resolveRunForToolCall(toolCallId2);
1179
+ return this.runner.signal(runId, toolCallId2, reply);
809
1180
  }
810
1181
  async cancel(actor, runId) {
811
1182
  await this.assertOwnsActiveStream(actor, runId);
@@ -872,20 +1243,33 @@ var AgentService = class {
872
1243
  /**
873
1244
  * Agent-selection precedence for a `chat()` call with no explicit `agentName`: the thread's own
874
1245
  * `defaultAgent` (if the thread exists and one is set) wins over the module's configured default.
875
- * Skips the thread lookup entirely when the caller already named an agent or there's no thread yet.
1246
+ * Skips the store entirely when the caller already named an agent or there's no thread yet.
1247
+ *
1248
+ * What this needs is one nullable scalar, so it asks for one. `getThread` returns the entire
1249
+ * transcript — every message, every persisted tool output — and this discards all of it; on a
1250
+ * long thread with large tool results that is hundreds of kilobytes read per turn, outside the
1251
+ * workflow, for a string. A store predating {@link ThreadDefaultAgentReader} still answers, via
1252
+ * the full read.
876
1253
  */
877
1254
  async resolveAgentName(agentName, threadId) {
878
1255
  if (agentName !== void 0) {
879
1256
  return agentName;
880
1257
  }
881
1258
  if (threadId !== void 0) {
882
- const thread = await this.store.getThread(threadId);
883
- if (thread?.defaultAgent !== void 0 && thread.defaultAgent !== null) {
884
- return thread.defaultAgent;
1259
+ const threadDefault = await this.threadDefaultAgent(threadId);
1260
+ if (threadDefault !== null) {
1261
+ return threadDefault;
885
1262
  }
886
1263
  }
887
1264
  return this.deps.defaultAgentName();
888
1265
  }
1266
+ async threadDefaultAgent(threadId) {
1267
+ const projecting = this.store;
1268
+ if (typeof projecting.defaultAgentForThread === "function") {
1269
+ return projecting.defaultAgentForThread(threadId);
1270
+ }
1271
+ return (await this.store.getThread(threadId))?.defaultAgent ?? null;
1272
+ }
889
1273
  async toSummaryView(thread) {
890
1274
  return {
891
1275
  ...thread,
@@ -908,13 +1292,74 @@ var AgentService = class {
908
1292
  return this.store.promoteThread(threadId);
909
1293
  }
910
1294
  /**
911
- * Drop a message and everything after it — the "edit and resend" / "delete from here" primitive.
912
- * The client then sends a fresh turn on the truncated thread. Ownership-gated like the other
913
- * thread-scoped mutations.
1295
+ * Drop a message and everything after it — the "edit and resend" / "delete from here" primitive.
1296
+ * The client then sends a fresh turn on the truncated thread. Ownership-gated like the other
1297
+ * thread-scoped mutations.
1298
+ */
1299
+ async truncateThreadFrom(actor, threadId, messageId) {
1300
+ await this.assertOwnsThread(actor, threadId);
1301
+ return this.store.truncateFrom(threadId, messageId);
1302
+ }
1303
+ /**
1304
+ * Every file this actor has staged, newest first — across threads, including uploads that were
1305
+ * never sent, which nothing else on this surface can see.
1306
+ *
1307
+ * Metadata only. A url is minted per turn by `resolve` so it can be short-lived, and handing one
1308
+ * back per entry would undo that for the price of rendering a list.
1309
+ */
1310
+ async listAttachments(actor, options = {}) {
1311
+ const list = this.attachmentInventory();
1312
+ return list({
1313
+ actor,
1314
+ ...options.limit !== void 0 ? {
1315
+ limit: options.limit
1316
+ } : {}
1317
+ });
1318
+ }
1319
+ /**
1320
+ * This actor's staged media that no live message references and that is old enough not to be an
1321
+ * upload in flight — the candidate set for a sweep. Returns them; never deletes them. The bytes
1322
+ * are the host's, and so is the decision.
1323
+ *
1324
+ * `olderThan` is required and has no default. How long a composer may sit open with a file
1325
+ * attached is the host's knowledge, and a library-chosen grace period would eventually delete a
1326
+ * file someone was about to send. The staging store is asked to apply it, and the result is
1327
+ * filtered again here: a store that ignores the hint would otherwise turn this into exactly that
1328
+ * bug, silently.
1329
+ *
1330
+ * Both halves must be answerable or this refuses. An unanswerable reference query means "cannot
1331
+ * tell", and treating it as "nothing is referenced" would hand back every attachment the actor
1332
+ * ever sent, marked safe to delete.
1333
+ */
1334
+ async collectableAttachments(actor, options) {
1335
+ const list = this.attachmentInventory();
1336
+ const referencedMediaIds = this.store.referencedMediaIds?.bind(this.store);
1337
+ if (referencedMediaIds === void 0) {
1338
+ throw new import_common6.NotImplementedException("Collecting attachments requires an AgentStore that implements referencedMediaIds(); the bound store cannot say which media a message still references, and guessing would delete files that are in use.");
1339
+ }
1340
+ const stagedBefore = options.olderThan.toISOString();
1341
+ const inventory = await list({
1342
+ actor,
1343
+ stagedBefore,
1344
+ ...options.limit !== void 0 ? {
1345
+ limit: options.limit
1346
+ } : {}
1347
+ });
1348
+ const aged = inventory.filter((entry) => entry.createdAt < stagedBefore);
1349
+ const referenced = new Set(await referencedMediaIds(actor.id, aged.map((entry) => entry.mediaId)));
1350
+ return aged.filter((entry) => !referenced.has(entry.mediaId));
1351
+ }
1352
+ /**
1353
+ * The bound staging store's `list`, or a refusal. Absence is never answered with an empty list:
1354
+ * "this host keeps no inventory" and "this actor has no files" are opposite facts that would
1355
+ * otherwise render identically — as a clean file list, and as a sweep that collects nothing.
914
1356
  */
915
- async truncateThreadFrom(actor, threadId, messageId) {
916
- await this.assertOwnsThread(actor, threadId);
917
- return this.store.truncateFrom(threadId, messageId);
1357
+ attachmentInventory() {
1358
+ const list = this.staging?.list?.bind(this.staging);
1359
+ if (list === void 0) {
1360
+ throw new import_common6.NotImplementedException("Listing attachments requires an AGENT_ATTACHMENT_STAGING provider implementing list(); the host owns the staged bytes, so only it can enumerate them.");
1361
+ }
1362
+ return list;
918
1363
  }
919
1364
  /**
920
1365
  * The day's usage for the badge: tokens + summed USD cost from the store, and the configured
@@ -958,24 +1403,26 @@ var AgentService = class {
958
1403
  * out from run resolution (see {@link resolveRunForToolCall}) so the console `AgentApprovalPort`
959
1404
  * adapter can resolve+signal a decision WITHOUT this check — it is authorized upstream instead.
960
1405
  */
961
- async assertOwnsToolCall(actor, toolCallId) {
962
- const owner = await this.store.ownerOfToolCall(toolCallId);
1406
+ async assertOwnsToolCall(actor, toolCallId2) {
1407
+ const owner = await this.store.ownerOfToolCall(toolCallId2);
963
1408
  if (owner === null) {
964
- throw new import_common6.NotFoundException(`tool call ${toolCallId} not found`);
1409
+ throw new import_common6.NotFoundException(`tool call ${toolCallId2} not found`);
965
1410
  }
966
1411
  if (owner !== actor.id) {
967
1412
  throw new import_common6.ForbiddenException("tool call belongs to another actor");
968
1413
  }
969
1414
  }
970
1415
  /**
971
- * Resolve the run currently awaiting `toolCallId` (its thread's active stream). That run is the
972
- * sub-agent's own child run when the pending call belongs to a delegated agent — the client never
973
- * knows or supplies a runId; it is derived here from the tool call alone.
1416
+ * Resolve the run awaiting `toolCallId`. Derived server-side from the tool call alone — the client
1417
+ * never knows or supplies a runId, and that run is the sub-agent's own child run when the pending
1418
+ * call belongs to a delegated agent. The store answers from the CALL'S OWN `runId` where it has
1419
+ * one; see `AgentStore.runForToolCall` for why that matters once a thread can hold more than one
1420
+ * live run.
974
1421
  */
975
- async resolveRunForToolCall(toolCallId) {
976
- const runId = await this.store.runForToolCall(toolCallId);
1422
+ async resolveRunForToolCall(toolCallId2) {
1423
+ const runId = await this.store.runForToolCall(toolCallId2);
977
1424
  if (runId === null) {
978
- throw new import_common6.NotFoundException(`tool call ${toolCallId} has no active run to signal`);
1425
+ throw new import_common6.NotFoundException(`tool call ${toolCallId2} has no active run to signal`);
979
1426
  }
980
1427
  return runId;
981
1428
  }
@@ -992,16 +1439,19 @@ var AgentService = class {
992
1439
  };
993
1440
  AgentService = _ts_decorate6([
994
1441
  (0, import_common6.Injectable)(),
995
- _ts_param4(0, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_RUNNER)),
996
- _ts_param4(1, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_STORE)),
997
- _ts_param4(2, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_DEPS_FACTORY)),
998
- _ts_param4(3, (0, import_common6.Inject)(import_nestjs_agent_core7.AGENT_QUOTA_STORE)),
1442
+ _ts_param5(0, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_RUNNER)),
1443
+ _ts_param5(1, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_STORE)),
1444
+ _ts_param5(2, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_DEPS_FACTORY)),
1445
+ _ts_param5(3, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_QUOTA_STORE)),
1446
+ _ts_param5(4, (0, import_common6.Optional)()),
1447
+ _ts_param5(4, (0, import_common6.Inject)(import_nestjs_agent_core8.AGENT_ATTACHMENT_STAGING)),
999
1448
  _ts_metadata5("design:type", Function),
1000
1449
  _ts_metadata5("design:paramtypes", [
1001
1450
  typeof AgentRunner === "undefined" ? Object : AgentRunner,
1002
1451
  typeof AgentStore === "undefined" ? Object : AgentStore,
1003
1452
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
1004
- Object
1453
+ Object,
1454
+ typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
1005
1455
  ])
1006
1456
  ], AgentService);
1007
1457
 
@@ -1026,16 +1476,16 @@ var AgentApprovalPortAdapter = class {
1026
1476
  constructor(agent) {
1027
1477
  this.agent = agent;
1028
1478
  }
1029
- async approve(toolCallId, opts) {
1030
- await this.agent.signalToolCall(toolCallId, {
1479
+ async approve(toolCallId2, opts) {
1480
+ await this.agent.signalToolCall(toolCallId2, {
1031
1481
  approved: true,
1032
1482
  ...opts?.executedByRef !== void 0 ? {
1033
1483
  executedByRef: opts.executedByRef
1034
1484
  } : {}
1035
1485
  });
1036
1486
  }
1037
- async reject(toolCallId, opts) {
1038
- await this.agent.signalToolCall(toolCallId, {
1487
+ async reject(toolCallId2, opts) {
1488
+ await this.agent.signalToolCall(toolCallId2, {
1039
1489
  approved: false,
1040
1490
  ...opts?.executedByRef !== void 0 ? {
1041
1491
  executedByRef: opts.executedByRef
@@ -1055,7 +1505,7 @@ AgentApprovalPortAdapter = _ts_decorate7([
1055
1505
  ], AgentApprovalPortAdapter);
1056
1506
 
1057
1507
  // src/controller/agents.controller.ts
1058
- var import_nestjs_agent_core8 = require("@dudousxd/nestjs-agent-core");
1508
+ var import_nestjs_agent_core9 = require("@dudousxd/nestjs-agent-core");
1059
1509
  var import_common8 = require("@nestjs/common");
1060
1510
  function _ts_decorate8(decorators, target, key, desc) {
1061
1511
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1068,12 +1518,12 @@ function _ts_metadata7(k, v) {
1068
1518
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1069
1519
  }
1070
1520
  __name(_ts_metadata7, "_ts_metadata");
1071
- function _ts_param5(paramIndex, decorator) {
1521
+ function _ts_param6(paramIndex, decorator) {
1072
1522
  return function(target, key) {
1073
1523
  decorator(target, key, paramIndex);
1074
1524
  };
1075
1525
  }
1076
- __name(_ts_param5, "_ts_param");
1526
+ __name(_ts_param6, "_ts_param");
1077
1527
  var AgentsController = class {
1078
1528
  static {
1079
1529
  __name(this, "AgentsController");
@@ -1103,17 +1553,17 @@ _ts_decorate8([
1103
1553
  ], AgentsController.prototype, "list", null);
1104
1554
  AgentsController = _ts_decorate8([
1105
1555
  (0, import_common8.Controller)("agents"),
1106
- _ts_param5(0, (0, import_common8.Inject)(import_nestjs_agent_core8.AGENT_REGISTRY)),
1107
- _ts_param5(1, (0, import_common8.Inject)(import_nestjs_agent_core8.AGENT_DEPS_FACTORY)),
1556
+ _ts_param6(0, (0, import_common8.Inject)(import_nestjs_agent_core9.AGENT_REGISTRY)),
1557
+ _ts_param6(1, (0, import_common8.Inject)(import_nestjs_agent_core9.AGENT_DEPS_FACTORY)),
1108
1558
  _ts_metadata7("design:type", Function),
1109
1559
  _ts_metadata7("design:paramtypes", [
1110
- typeof import_nestjs_agent_core8.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core8.AgentRegistry,
1560
+ typeof import_nestjs_agent_core9.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core9.AgentRegistry,
1111
1561
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
1112
1562
  ])
1113
1563
  ], AgentsController);
1114
1564
 
1115
1565
  // src/controller/attachments.controller.ts
1116
- var import_nestjs_agent_core9 = require("@dudousxd/nestjs-agent-core");
1566
+ var import_nestjs_agent_core10 = require("@dudousxd/nestjs-agent-core");
1117
1567
  var import_common9 = require("@nestjs/common");
1118
1568
  var import_platform_express = require("@nestjs/platform-express");
1119
1569
  function _ts_decorate9(decorators, target, key, desc) {
@@ -1127,13 +1577,15 @@ function _ts_metadata8(k, v) {
1127
1577
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1128
1578
  }
1129
1579
  __name(_ts_metadata8, "_ts_metadata");
1130
- function _ts_param6(paramIndex, decorator) {
1580
+ function _ts_param7(paramIndex, decorator) {
1131
1581
  return function(target, key) {
1132
1582
  decorator(target, key, paramIndex);
1133
1583
  };
1134
1584
  }
1135
- __name(_ts_param6, "_ts_param");
1585
+ __name(_ts_param7, "_ts_param");
1136
1586
  var DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
1587
+ var HARD_MAX_ATTACHMENT_BYTES = 32 * 1024 * 1024;
1588
+ var ATTACHMENT_PAGE_SIZE = 50;
1137
1589
  var DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES = [
1138
1590
  "image/png",
1139
1591
  "image/jpeg",
@@ -1149,10 +1601,12 @@ var AttachmentsController = class {
1149
1601
  }
1150
1602
  options;
1151
1603
  actorResolver;
1604
+ agents;
1152
1605
  staging;
1153
- constructor(options, actorResolver, staging) {
1606
+ constructor(options, actorResolver, agents, staging) {
1154
1607
  this.options = options;
1155
1608
  this.actorResolver = actorResolver;
1609
+ this.agents = agents;
1156
1610
  this.staging = staging;
1157
1611
  }
1158
1612
  /**
@@ -1166,6 +1620,21 @@ var AttachmentsController = class {
1166
1620
  throw new Error("AgentModule: attachments.upload is true but no AGENT_ATTACHMENT_STAGING provider is bound. Bind one (e.g. `{ provide: AGENT_ATTACHMENT_STAGING, useClass: MyStagingStore }`) in a module imported alongside AgentModule, or set attachments.upload to false.");
1167
1621
  }
1168
1622
  }
1623
+ /**
1624
+ * The caller's own staged files, newest first — the one question `GET /agent/threads/:id` cannot
1625
+ * answer, since an upload that was never sent belongs to no thread.
1626
+ *
1627
+ * Scoped by the RESOLVED actor and nothing else. There is deliberately no `threadId` filter: a
1628
+ * thread's attachments already ride on its messages in the thread payload, and re-serving them
1629
+ * from here would add a second ownership path to get wrong for information the client already
1630
+ * holds. Metadata only — see {@link StagedAttachment}.
1631
+ */
1632
+ async list(req) {
1633
+ const actor = await this.actorResolver.resolve(req);
1634
+ return this.agents.listAttachments(actor, {
1635
+ limit: ATTACHMENT_PAGE_SIZE
1636
+ });
1637
+ }
1169
1638
  async upload(req, file) {
1170
1639
  if (this.staging === void 0) {
1171
1640
  throw new import_common9.NotImplementedException("Attachment upload is not configured on this server.");
@@ -1191,11 +1660,24 @@ var AttachmentsController = class {
1191
1660
  });
1192
1661
  }
1193
1662
  };
1663
+ _ts_decorate9([
1664
+ (0, import_common9.Get)(),
1665
+ _ts_param7(0, (0, import_common9.Req)()),
1666
+ _ts_metadata8("design:type", Function),
1667
+ _ts_metadata8("design:paramtypes", [
1668
+ typeof Request === "undefined" ? Object : Request
1669
+ ]),
1670
+ _ts_metadata8("design:returntype", Promise)
1671
+ ], AttachmentsController.prototype, "list", null);
1194
1672
  _ts_decorate9([
1195
1673
  (0, import_common9.Post)(),
1196
- (0, import_common9.UseInterceptors)((0, import_platform_express.FileInterceptor)("file")),
1197
- _ts_param6(0, (0, import_common9.Req)()),
1198
- _ts_param6(1, (0, import_common9.UploadedFile)()),
1674
+ (0, import_common9.UseInterceptors)((0, import_platform_express.FileInterceptor)("file", {
1675
+ limits: {
1676
+ fileSize: HARD_MAX_ATTACHMENT_BYTES
1677
+ }
1678
+ })),
1679
+ _ts_param7(0, (0, import_common9.Req)()),
1680
+ _ts_param7(1, (0, import_common9.UploadedFile)()),
1199
1681
  _ts_metadata8("design:type", Function),
1200
1682
  _ts_metadata8("design:paramtypes", [
1201
1683
  typeof Request === "undefined" ? Object : Request,
@@ -1205,20 +1687,21 @@ _ts_decorate9([
1205
1687
  ], AttachmentsController.prototype, "upload", null);
1206
1688
  AttachmentsController = _ts_decorate9([
1207
1689
  (0, import_common9.Controller)("attachments"),
1208
- _ts_param6(0, (0, import_common9.Inject)(import_nestjs_agent_core9.AGENT_OPTIONS)),
1209
- _ts_param6(1, (0, import_common9.Inject)(import_nestjs_agent_core9.AGENT_ACTOR_RESOLVER)),
1210
- _ts_param6(2, (0, import_common9.Optional)()),
1211
- _ts_param6(2, (0, import_common9.Inject)(import_nestjs_agent_core9.AGENT_ATTACHMENT_STAGING)),
1690
+ _ts_param7(0, (0, import_common9.Inject)(import_nestjs_agent_core10.AGENT_OPTIONS)),
1691
+ _ts_param7(1, (0, import_common9.Inject)(import_nestjs_agent_core10.AGENT_ACTOR_RESOLVER)),
1692
+ _ts_param7(3, (0, import_common9.Optional)()),
1693
+ _ts_param7(3, (0, import_common9.Inject)(import_nestjs_agent_core10.AGENT_ATTACHMENT_STAGING)),
1212
1694
  _ts_metadata8("design:type", Function),
1213
1695
  _ts_metadata8("design:paramtypes", [
1214
1696
  typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
1215
1697
  typeof ActorResolver === "undefined" ? Object : ActorResolver,
1698
+ typeof AgentService === "undefined" ? Object : AgentService,
1216
1699
  Object
1217
1700
  ])
1218
1701
  ], AttachmentsController);
1219
1702
 
1220
1703
  // src/controller/chat.controller.ts
1221
- var import_nestjs_agent_core10 = require("@dudousxd/nestjs-agent-core");
1704
+ var import_nestjs_agent_core11 = require("@dudousxd/nestjs-agent-core");
1222
1705
  var import_common10 = require("@nestjs/common");
1223
1706
  function _ts_decorate10(decorators, target, key, desc) {
1224
1707
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1231,12 +1714,37 @@ function _ts_metadata9(k, v) {
1231
1714
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1232
1715
  }
1233
1716
  __name(_ts_metadata9, "_ts_metadata");
1234
- function _ts_param7(paramIndex, decorator) {
1717
+ function _ts_param8(paramIndex, decorator) {
1235
1718
  return function(target, key) {
1236
1719
  decorator(target, key, paramIndex);
1237
1720
  };
1238
1721
  }
1239
- __name(_ts_param7, "_ts_param");
1722
+ __name(_ts_param8, "_ts_param");
1723
+ var MAX_ATTACHMENTS_PER_MESSAGE = 10;
1724
+ function attachmentRefs(claimed) {
1725
+ if (claimed === void 0) {
1726
+ return [];
1727
+ }
1728
+ if (!Array.isArray(claimed)) {
1729
+ throw new import_common10.BadRequestException("attachments must be an array of { mediaId }");
1730
+ }
1731
+ if (claimed.length > MAX_ATTACHMENTS_PER_MESSAGE) {
1732
+ throw new import_common10.BadRequestException(`a message may carry at most ${MAX_ATTACHMENTS_PER_MESSAGE} attachments`);
1733
+ }
1734
+ return claimed.map((entry) => {
1735
+ if (typeof entry !== "object" || entry === null || !("mediaId" in entry)) {
1736
+ throw new import_common10.BadRequestException("each attachment must be an object with a mediaId");
1737
+ }
1738
+ const { mediaId } = entry;
1739
+ if (typeof mediaId !== "string" || mediaId.length === 0) {
1740
+ throw new import_common10.BadRequestException("each attachment must carry a non-empty string mediaId");
1741
+ }
1742
+ return {
1743
+ mediaId
1744
+ };
1745
+ });
1746
+ }
1747
+ __name(attachmentRefs, "attachmentRefs");
1240
1748
  var ChatController = class {
1241
1749
  static {
1242
1750
  __name(this, "ChatController");
@@ -1249,6 +1757,7 @@ var ChatController = class {
1249
1757
  }
1250
1758
  async chat(req, res, body) {
1251
1759
  const actor = await this.actorResolver.resolve(req);
1760
+ const attachments = attachmentRefs(body.attachments);
1252
1761
  const { runId, threadId } = await this.agent.chat({
1253
1762
  actor,
1254
1763
  message: body.message,
@@ -1258,8 +1767,8 @@ var ChatController = class {
1258
1767
  ...body.agent !== void 0 ? {
1259
1768
  agentName: body.agent
1260
1769
  } : {},
1261
- ...body.attachments !== void 0 ? {
1262
- attachments: body.attachments
1770
+ ...attachments.length > 0 ? {
1771
+ attachments
1263
1772
  } : {},
1264
1773
  ...body.pageContext !== void 0 ? {
1265
1774
  pageContext: body.pageContext
@@ -1271,10 +1780,11 @@ var ChatController = class {
1271
1780
  transient: true
1272
1781
  } : {}
1273
1782
  });
1274
- await this.pipe(res, runId, threadId);
1783
+ await this.pipe(res, runId, this.agent.subscribe(runId), threadId);
1275
1784
  }
1276
- async stream(runId, res) {
1277
- await this.pipe(res, runId);
1785
+ async stream(req, runId, res) {
1786
+ const actor = await this.actorResolver.resolve(req);
1787
+ await this.pipe(res, runId, await this.agent.subscribeAs(actor, runId));
1278
1788
  }
1279
1789
  async cancel(req, runId) {
1280
1790
  const actor = await this.actorResolver.resolve(req);
@@ -1283,7 +1793,7 @@ var ChatController = class {
1283
1793
  aborted: true
1284
1794
  };
1285
1795
  }
1286
- async pipe(res, runId, threadId) {
1796
+ async pipe(res, runId, events, threadId) {
1287
1797
  res.setHeader("Content-Type", "text/event-stream");
1288
1798
  res.setHeader("Cache-Control", "no-cache");
1289
1799
  res.setHeader("Connection", "keep-alive");
@@ -1301,7 +1811,7 @@ data: ${JSON.stringify({
1301
1811
  const decoder = new TextDecoder();
1302
1812
  let buffer = "";
1303
1813
  try {
1304
- for await (const chunk of this.agent.subscribe(runId)) {
1814
+ for await (const chunk of events) {
1305
1815
  buffer += decoder.decode(chunk, {
1306
1816
  stream: true
1307
1817
  });
@@ -1324,7 +1834,7 @@ data: ${JSON.stringify({
1324
1834
  }
1325
1835
  res.write("event: done\ndata: {}\n\n");
1326
1836
  } catch (error) {
1327
- const payload = error instanceof import_nestjs_agent_core10.AgentStreamError ? {
1837
+ const payload = error instanceof import_nestjs_agent_core11.AgentStreamError ? {
1328
1838
  code: error.code,
1329
1839
  message: error.message
1330
1840
  } : {
@@ -1341,9 +1851,9 @@ data: ${JSON.stringify(payload)}
1341
1851
  };
1342
1852
  _ts_decorate10([
1343
1853
  (0, import_common10.Post)("chat"),
1344
- _ts_param7(0, (0, import_common10.Req)()),
1345
- _ts_param7(1, (0, import_common10.Res)()),
1346
- _ts_param7(2, (0, import_common10.Body)()),
1854
+ _ts_param8(0, (0, import_common10.Req)()),
1855
+ _ts_param8(1, (0, import_common10.Res)()),
1856
+ _ts_param8(2, (0, import_common10.Body)()),
1347
1857
  _ts_metadata9("design:type", Function),
1348
1858
  _ts_metadata9("design:paramtypes", [
1349
1859
  typeof Request === "undefined" ? Object : Request,
@@ -1354,10 +1864,12 @@ _ts_decorate10([
1354
1864
  ], ChatController.prototype, "chat", null);
1355
1865
  _ts_decorate10([
1356
1866
  (0, import_common10.Get)("chat/:runId/stream"),
1357
- _ts_param7(0, (0, import_common10.Param)("runId")),
1358
- _ts_param7(1, (0, import_common10.Res)()),
1867
+ _ts_param8(0, (0, import_common10.Req)()),
1868
+ _ts_param8(1, (0, import_common10.Param)("runId")),
1869
+ _ts_param8(2, (0, import_common10.Res)()),
1359
1870
  _ts_metadata9("design:type", Function),
1360
1871
  _ts_metadata9("design:paramtypes", [
1872
+ typeof Request === "undefined" ? Object : Request,
1361
1873
  String,
1362
1874
  typeof Response === "undefined" ? Object : Response
1363
1875
  ]),
@@ -1365,8 +1877,8 @@ _ts_decorate10([
1365
1877
  ], ChatController.prototype, "stream", null);
1366
1878
  _ts_decorate10([
1367
1879
  (0, import_common10.Post)("chat/:runId/cancel"),
1368
- _ts_param7(0, (0, import_common10.Req)()),
1369
- _ts_param7(1, (0, import_common10.Param)("runId")),
1880
+ _ts_param8(0, (0, import_common10.Req)()),
1881
+ _ts_param8(1, (0, import_common10.Param)("runId")),
1370
1882
  _ts_metadata9("design:type", Function),
1371
1883
  _ts_metadata9("design:paramtypes", [
1372
1884
  typeof Request === "undefined" ? Object : Request,
@@ -1376,7 +1888,7 @@ _ts_decorate10([
1376
1888
  ], ChatController.prototype, "cancel", null);
1377
1889
  ChatController = _ts_decorate10([
1378
1890
  (0, import_common10.Controller)(),
1379
- _ts_param7(1, (0, import_common10.Inject)(import_nestjs_agent_core10.AGENT_ACTOR_RESOLVER)),
1891
+ _ts_param8(1, (0, import_common10.Inject)(import_nestjs_agent_core11.AGENT_ACTOR_RESOLVER)),
1380
1892
  _ts_metadata9("design:type", Function),
1381
1893
  _ts_metadata9("design:paramtypes", [
1382
1894
  typeof AgentService === "undefined" ? Object : AgentService,
@@ -1384,8 +1896,8 @@ ChatController = _ts_decorate10([
1384
1896
  ])
1385
1897
  ], ChatController);
1386
1898
 
1387
- // src/controller/quota.controller.ts
1388
- var import_nestjs_agent_core11 = require("@dudousxd/nestjs-agent-core");
1899
+ // src/controller/memories.controller.ts
1900
+ var import_nestjs_agent_core12 = require("@dudousxd/nestjs-agent-core");
1389
1901
  var import_common11 = require("@nestjs/common");
1390
1902
  function _ts_decorate11(decorators, target, key, desc) {
1391
1903
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -1398,12 +1910,138 @@ function _ts_metadata10(k, v) {
1398
1910
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1399
1911
  }
1400
1912
  __name(_ts_metadata10, "_ts_metadata");
1401
- function _ts_param8(paramIndex, decorator) {
1913
+ function _ts_param9(paramIndex, decorator) {
1402
1914
  return function(target, key) {
1403
1915
  decorator(target, key, paramIndex);
1404
1916
  };
1405
1917
  }
1406
- __name(_ts_param8, "_ts_param");
1918
+ __name(_ts_param9, "_ts_param");
1919
+ var MemoriesController = class {
1920
+ static {
1921
+ __name(this, "MemoriesController");
1922
+ }
1923
+ actorResolver;
1924
+ memory;
1925
+ constructor(actorResolver, memory) {
1926
+ this.actorResolver = actorResolver;
1927
+ this.memory = memory;
1928
+ }
1929
+ /**
1930
+ * Every memory this actor can reach, most specific first, each carrying its origin and whatever
1931
+ * wider value it outranks.
1932
+ *
1933
+ * DELIBERATELY IGNORES `maxMemories`. That ceiling is a budget on what one TURN carries; applying
1934
+ * it here would mean a person could not see — and so could not delete — a belief the assistant is
1935
+ * one write away from acting on again. Showing someone more than the model sees is harmless;
1936
+ * showing them less is the failure this endpoint exists to prevent.
1937
+ */
1938
+ async list(req, threadId) {
1939
+ if (this.memory === void 0) {
1940
+ return [];
1941
+ }
1942
+ const actor = await this.actorResolver.resolve(req);
1943
+ return (await this.unbounded(threadId ?? "", actor)).entries;
1944
+ }
1945
+ /**
1946
+ * Forget one. Authorized against the actor's OWN resolved list, the same way a `skill` load is
1947
+ * authorized against the turn's catalog: an id this actor cannot see is answered as missing rather
1948
+ * than refused, so the endpoint cannot be used to find out which memories exist about other people.
1949
+ */
1950
+ async forget(req, id) {
1951
+ if (this.memory === void 0) {
1952
+ throw new import_common11.NotFoundException("No memory is configured in this deployment.");
1953
+ }
1954
+ const actor = await this.actorResolver.resolve(req);
1955
+ const digest = await this.unbounded("", actor);
1956
+ const entry = digest.entries.find((candidate) => candidate.id === id);
1957
+ if (entry === void 0) {
1958
+ throw new import_common11.NotFoundException(`No memory with id "${id}".`);
1959
+ }
1960
+ const verdict = (0, import_nestjs_agent_core12.memoryForgetVerdict)({
1961
+ record: entry,
1962
+ actor
1963
+ });
1964
+ if (!verdict.allowed) {
1965
+ throw new import_common11.ForbiddenException(verdict.reason);
1966
+ }
1967
+ return {
1968
+ forgotten: await this.memory.provider.forget({
1969
+ id: entry.id,
1970
+ ctx: {
1971
+ actor,
1972
+ threadId: ""
1973
+ }
1974
+ })
1975
+ };
1976
+ }
1977
+ async unbounded(threadId, actor) {
1978
+ const config = this.memory;
1979
+ return await (0, import_nestjs_agent_core12.offerMemories)({
1980
+ config: {
1981
+ ...config,
1982
+ maxMemories: Number.POSITIVE_INFINITY
1983
+ },
1984
+ ctx: {
1985
+ actor,
1986
+ threadId
1987
+ }
1988
+ });
1989
+ }
1990
+ };
1991
+ _ts_decorate11([
1992
+ (0, import_common11.Get)(),
1993
+ _ts_param9(0, (0, import_common11.Req)()),
1994
+ _ts_param9(1, (0, import_common11.Query)("threadId")),
1995
+ _ts_metadata10("design:type", Function),
1996
+ _ts_metadata10("design:paramtypes", [
1997
+ typeof Request === "undefined" ? Object : Request,
1998
+ String
1999
+ ]),
2000
+ _ts_metadata10("design:returntype", Promise)
2001
+ ], MemoriesController.prototype, "list", null);
2002
+ _ts_decorate11([
2003
+ (0, import_common11.Delete)(":id"),
2004
+ _ts_param9(0, (0, import_common11.Req)()),
2005
+ _ts_param9(1, (0, import_common11.Param)("id")),
2006
+ _ts_metadata10("design:type", Function),
2007
+ _ts_metadata10("design:paramtypes", [
2008
+ typeof Request === "undefined" ? Object : Request,
2009
+ String
2010
+ ]),
2011
+ _ts_metadata10("design:returntype", Promise)
2012
+ ], MemoriesController.prototype, "forget", null);
2013
+ MemoriesController = _ts_decorate11([
2014
+ (0, import_common11.Controller)("memories"),
2015
+ _ts_param9(0, (0, import_common11.Inject)(import_nestjs_agent_core12.AGENT_ACTOR_RESOLVER)),
2016
+ _ts_param9(1, (0, import_common11.Optional)()),
2017
+ _ts_param9(1, (0, import_common11.Inject)(import_nestjs_agent_core12.AGENT_MEMORY)),
2018
+ _ts_metadata10("design:type", Function),
2019
+ _ts_metadata10("design:paramtypes", [
2020
+ typeof ActorResolver === "undefined" ? Object : ActorResolver,
2021
+ Object
2022
+ ])
2023
+ ], MemoriesController);
2024
+
2025
+ // src/controller/quota.controller.ts
2026
+ var import_nestjs_agent_core13 = require("@dudousxd/nestjs-agent-core");
2027
+ var import_common12 = require("@nestjs/common");
2028
+ function _ts_decorate12(decorators, target, key, desc) {
2029
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2030
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2031
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2032
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2033
+ }
2034
+ __name(_ts_decorate12, "_ts_decorate");
2035
+ function _ts_metadata11(k, v) {
2036
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2037
+ }
2038
+ __name(_ts_metadata11, "_ts_metadata");
2039
+ function _ts_param10(paramIndex, decorator) {
2040
+ return function(target, key) {
2041
+ decorator(target, key, paramIndex);
2042
+ };
2043
+ }
2044
+ __name(_ts_param10, "_ts_param");
1407
2045
  var QuotaController = class {
1408
2046
  static {
1409
2047
  __name(this, "QuotaController");
@@ -1419,45 +2057,110 @@ var QuotaController = class {
1419
2057
  return this.agent.quotaToday(actor.id);
1420
2058
  }
1421
2059
  };
1422
- _ts_decorate11([
1423
- (0, import_common11.Get)("today"),
1424
- _ts_param8(0, (0, import_common11.Req)()),
1425
- _ts_metadata10("design:type", Function),
1426
- _ts_metadata10("design:paramtypes", [
2060
+ _ts_decorate12([
2061
+ (0, import_common12.Get)("today"),
2062
+ _ts_param10(0, (0, import_common12.Req)()),
2063
+ _ts_metadata11("design:type", Function),
2064
+ _ts_metadata11("design:paramtypes", [
1427
2065
  typeof Request === "undefined" ? Object : Request
1428
2066
  ]),
1429
- _ts_metadata10("design:returntype", Promise)
2067
+ _ts_metadata11("design:returntype", Promise)
1430
2068
  ], QuotaController.prototype, "today", null);
1431
- QuotaController = _ts_decorate11([
1432
- (0, import_common11.Controller)("quota"),
1433
- _ts_param8(1, (0, import_common11.Inject)(import_nestjs_agent_core11.AGENT_ACTOR_RESOLVER)),
1434
- _ts_metadata10("design:type", Function),
1435
- _ts_metadata10("design:paramtypes", [
2069
+ QuotaController = _ts_decorate12([
2070
+ (0, import_common12.Controller)("quota"),
2071
+ _ts_param10(1, (0, import_common12.Inject)(import_nestjs_agent_core13.AGENT_ACTOR_RESOLVER)),
2072
+ _ts_metadata11("design:type", Function),
2073
+ _ts_metadata11("design:paramtypes", [
1436
2074
  typeof AgentService === "undefined" ? Object : AgentService,
1437
2075
  typeof ActorResolver === "undefined" ? Object : ActorResolver
1438
2076
  ])
1439
2077
  ], QuotaController);
1440
2078
 
2079
+ // src/controller/skills.controller.ts
2080
+ var import_nestjs_agent_core14 = require("@dudousxd/nestjs-agent-core");
2081
+ var import_common13 = require("@nestjs/common");
2082
+ function _ts_decorate13(decorators, target, key, desc) {
2083
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2084
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2085
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2086
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2087
+ }
2088
+ __name(_ts_decorate13, "_ts_decorate");
2089
+ function _ts_metadata12(k, v) {
2090
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2091
+ }
2092
+ __name(_ts_metadata12, "_ts_metadata");
2093
+ function _ts_param11(paramIndex, decorator) {
2094
+ return function(target, key) {
2095
+ decorator(target, key, paramIndex);
2096
+ };
2097
+ }
2098
+ __name(_ts_param11, "_ts_param");
2099
+ var SkillsController = class {
2100
+ static {
2101
+ __name(this, "SkillsController");
2102
+ }
2103
+ actorResolver;
2104
+ skills;
2105
+ constructor(actorResolver, skills) {
2106
+ this.actorResolver = actorResolver;
2107
+ this.skills = skills;
2108
+ }
2109
+ async list(req, threadId) {
2110
+ if (this.skills === void 0) {
2111
+ return [];
2112
+ }
2113
+ const actor = await this.actorResolver.resolve(req);
2114
+ const offer = await (0, import_nestjs_agent_core14.offerSkills)(this.skills, {
2115
+ actor,
2116
+ threadId: threadId ?? ""
2117
+ });
2118
+ return offer.entries;
2119
+ }
2120
+ };
2121
+ _ts_decorate13([
2122
+ (0, import_common13.Get)(),
2123
+ _ts_param11(0, (0, import_common13.Req)()),
2124
+ _ts_param11(1, (0, import_common13.Query)("threadId")),
2125
+ _ts_metadata12("design:type", Function),
2126
+ _ts_metadata12("design:paramtypes", [
2127
+ typeof Request === "undefined" ? Object : Request,
2128
+ String
2129
+ ]),
2130
+ _ts_metadata12("design:returntype", Promise)
2131
+ ], SkillsController.prototype, "list", null);
2132
+ SkillsController = _ts_decorate13([
2133
+ (0, import_common13.Controller)("skills"),
2134
+ _ts_param11(0, (0, import_common13.Inject)(import_nestjs_agent_core14.AGENT_ACTOR_RESOLVER)),
2135
+ _ts_param11(1, (0, import_common13.Optional)()),
2136
+ _ts_param11(1, (0, import_common13.Inject)(import_nestjs_agent_core14.AGENT_SKILLS)),
2137
+ _ts_metadata12("design:type", Function),
2138
+ _ts_metadata12("design:paramtypes", [
2139
+ typeof ActorResolver === "undefined" ? Object : ActorResolver,
2140
+ Object
2141
+ ])
2142
+ ], SkillsController);
2143
+
1441
2144
  // src/controller/threads.controller.ts
1442
- var import_nestjs_agent_core12 = require("@dudousxd/nestjs-agent-core");
1443
- var import_common12 = require("@nestjs/common");
1444
- function _ts_decorate12(decorators, target, key, desc) {
2145
+ var import_nestjs_agent_core15 = require("@dudousxd/nestjs-agent-core");
2146
+ var import_common14 = require("@nestjs/common");
2147
+ function _ts_decorate14(decorators, target, key, desc) {
1445
2148
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1446
2149
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1447
2150
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1448
2151
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1449
2152
  }
1450
- __name(_ts_decorate12, "_ts_decorate");
1451
- function _ts_metadata11(k, v) {
2153
+ __name(_ts_decorate14, "_ts_decorate");
2154
+ function _ts_metadata13(k, v) {
1452
2155
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1453
2156
  }
1454
- __name(_ts_metadata11, "_ts_metadata");
1455
- function _ts_param9(paramIndex, decorator) {
2157
+ __name(_ts_metadata13, "_ts_metadata");
2158
+ function _ts_param12(paramIndex, decorator) {
1456
2159
  return function(target, key) {
1457
2160
  decorator(target, key, paramIndex);
1458
2161
  };
1459
2162
  }
1460
- __name(_ts_param9, "_ts_param");
2163
+ __name(_ts_param12, "_ts_param");
1461
2164
  var ThreadsController = class {
1462
2165
  static {
1463
2166
  __name(this, "ThreadsController");
@@ -1521,117 +2224,173 @@ var ThreadsController = class {
1521
2224
  };
1522
2225
  }
1523
2226
  };
1524
- _ts_decorate12([
1525
- (0, import_common12.Get)(),
1526
- _ts_param9(0, (0, import_common12.Req)()),
1527
- _ts_metadata11("design:type", Function),
1528
- _ts_metadata11("design:paramtypes", [
2227
+ _ts_decorate14([
2228
+ (0, import_common14.Get)(),
2229
+ _ts_param12(0, (0, import_common14.Req)()),
2230
+ _ts_metadata13("design:type", Function),
2231
+ _ts_metadata13("design:paramtypes", [
1529
2232
  typeof Request === "undefined" ? Object : Request
1530
2233
  ]),
1531
- _ts_metadata11("design:returntype", Promise)
2234
+ _ts_metadata13("design:returntype", Promise)
1532
2235
  ], ThreadsController.prototype, "list", null);
1533
- _ts_decorate12([
1534
- (0, import_common12.Get)(":id"),
1535
- _ts_param9(0, (0, import_common12.Req)()),
1536
- _ts_param9(1, (0, import_common12.Param)("id")),
1537
- _ts_metadata11("design:type", Function),
1538
- _ts_metadata11("design:paramtypes", [
2236
+ _ts_decorate14([
2237
+ (0, import_common14.Get)(":id"),
2238
+ _ts_param12(0, (0, import_common14.Req)()),
2239
+ _ts_param12(1, (0, import_common14.Param)("id")),
2240
+ _ts_metadata13("design:type", Function),
2241
+ _ts_metadata13("design:paramtypes", [
1539
2242
  typeof Request === "undefined" ? Object : Request,
1540
2243
  String
1541
2244
  ]),
1542
- _ts_metadata11("design:returntype", Promise)
2245
+ _ts_metadata13("design:returntype", Promise)
1543
2246
  ], ThreadsController.prototype, "detail", null);
1544
- _ts_decorate12([
1545
- (0, import_common12.Delete)(":id"),
1546
- _ts_param9(0, (0, import_common12.Req)()),
1547
- _ts_param9(1, (0, import_common12.Param)("id")),
1548
- _ts_metadata11("design:type", Function),
1549
- _ts_metadata11("design:paramtypes", [
2247
+ _ts_decorate14([
2248
+ (0, import_common14.Delete)(":id"),
2249
+ _ts_param12(0, (0, import_common14.Req)()),
2250
+ _ts_param12(1, (0, import_common14.Param)("id")),
2251
+ _ts_metadata13("design:type", Function),
2252
+ _ts_metadata13("design:paramtypes", [
1550
2253
  typeof Request === "undefined" ? Object : Request,
1551
2254
  String
1552
2255
  ]),
1553
- _ts_metadata11("design:returntype", Promise)
2256
+ _ts_metadata13("design:returntype", Promise)
1554
2257
  ], ThreadsController.prototype, "remove", null);
1555
- _ts_decorate12([
1556
- (0, import_common12.Post)(":id/fork-from/:messageId"),
1557
- _ts_param9(0, (0, import_common12.Req)()),
1558
- _ts_param9(1, (0, import_common12.Param)("id")),
1559
- _ts_param9(2, (0, import_common12.Param)("messageId")),
1560
- _ts_metadata11("design:type", Function),
1561
- _ts_metadata11("design:paramtypes", [
2258
+ _ts_decorate14([
2259
+ (0, import_common14.Post)(":id/fork-from/:messageId"),
2260
+ _ts_param12(0, (0, import_common14.Req)()),
2261
+ _ts_param12(1, (0, import_common14.Param)("id")),
2262
+ _ts_param12(2, (0, import_common14.Param)("messageId")),
2263
+ _ts_metadata13("design:type", Function),
2264
+ _ts_metadata13("design:paramtypes", [
1562
2265
  typeof Request === "undefined" ? Object : Request,
1563
2266
  String,
1564
2267
  String
1565
2268
  ]),
1566
- _ts_metadata11("design:returntype", Promise)
2269
+ _ts_metadata13("design:returntype", Promise)
1567
2270
  ], ThreadsController.prototype, "fork", null);
1568
- _ts_decorate12([
1569
- (0, import_common12.Patch)(":id"),
1570
- _ts_param9(0, (0, import_common12.Req)()),
1571
- _ts_param9(1, (0, import_common12.Param)("id")),
1572
- _ts_param9(2, (0, import_common12.Body)()),
1573
- _ts_metadata11("design:type", Function),
1574
- _ts_metadata11("design:paramtypes", [
2271
+ _ts_decorate14([
2272
+ (0, import_common14.Patch)(":id"),
2273
+ _ts_param12(0, (0, import_common14.Req)()),
2274
+ _ts_param12(1, (0, import_common14.Param)("id")),
2275
+ _ts_param12(2, (0, import_common14.Body)()),
2276
+ _ts_metadata13("design:type", Function),
2277
+ _ts_metadata13("design:paramtypes", [
1575
2278
  typeof Request === "undefined" ? Object : Request,
1576
2279
  String,
1577
2280
  typeof UpdateThreadBody === "undefined" ? Object : UpdateThreadBody
1578
2281
  ]),
1579
- _ts_metadata11("design:returntype", Promise)
2282
+ _ts_metadata13("design:returntype", Promise)
1580
2283
  ], ThreadsController.prototype, "update", null);
1581
- _ts_decorate12([
1582
- (0, import_common12.Post)(":id/promote"),
1583
- _ts_param9(0, (0, import_common12.Req)()),
1584
- _ts_param9(1, (0, import_common12.Param)("id")),
1585
- _ts_metadata11("design:type", Function),
1586
- _ts_metadata11("design:paramtypes", [
2284
+ _ts_decorate14([
2285
+ (0, import_common14.Post)(":id/promote"),
2286
+ _ts_param12(0, (0, import_common14.Req)()),
2287
+ _ts_param12(1, (0, import_common14.Param)("id")),
2288
+ _ts_metadata13("design:type", Function),
2289
+ _ts_metadata13("design:paramtypes", [
1587
2290
  typeof Request === "undefined" ? Object : Request,
1588
2291
  String
1589
2292
  ]),
1590
- _ts_metadata11("design:returntype", Promise)
2293
+ _ts_metadata13("design:returntype", Promise)
1591
2294
  ], ThreadsController.prototype, "promote", null);
1592
- _ts_decorate12([
1593
- (0, import_common12.Delete)(":id/from/:messageId"),
1594
- _ts_param9(0, (0, import_common12.Req)()),
1595
- _ts_param9(1, (0, import_common12.Param)("id")),
1596
- _ts_param9(2, (0, import_common12.Param)("messageId")),
1597
- _ts_metadata11("design:type", Function),
1598
- _ts_metadata11("design:paramtypes", [
2295
+ _ts_decorate14([
2296
+ (0, import_common14.Delete)(":id/from/:messageId"),
2297
+ _ts_param12(0, (0, import_common14.Req)()),
2298
+ _ts_param12(1, (0, import_common14.Param)("id")),
2299
+ _ts_param12(2, (0, import_common14.Param)("messageId")),
2300
+ _ts_metadata13("design:type", Function),
2301
+ _ts_metadata13("design:paramtypes", [
1599
2302
  typeof Request === "undefined" ? Object : Request,
1600
2303
  String,
1601
2304
  String
1602
2305
  ]),
1603
- _ts_metadata11("design:returntype", Promise)
2306
+ _ts_metadata13("design:returntype", Promise)
1604
2307
  ], ThreadsController.prototype, "truncateFrom", null);
1605
- ThreadsController = _ts_decorate12([
1606
- (0, import_common12.Controller)("threads"),
1607
- _ts_param9(1, (0, import_common12.Inject)(import_nestjs_agent_core12.AGENT_ACTOR_RESOLVER)),
1608
- _ts_metadata11("design:type", Function),
1609
- _ts_metadata11("design:paramtypes", [
2308
+ ThreadsController = _ts_decorate14([
2309
+ (0, import_common14.Controller)("threads"),
2310
+ _ts_param12(1, (0, import_common14.Inject)(import_nestjs_agent_core15.AGENT_ACTOR_RESOLVER)),
2311
+ _ts_metadata13("design:type", Function),
2312
+ _ts_metadata13("design:paramtypes", [
1610
2313
  typeof AgentService === "undefined" ? Object : AgentService,
1611
2314
  typeof ActorResolver === "undefined" ? Object : ActorResolver
1612
2315
  ])
1613
2316
  ], ThreadsController);
1614
2317
 
1615
2318
  // src/controller/tool-call.controller.ts
1616
- var import_nestjs_agent_core13 = require("@dudousxd/nestjs-agent-core");
1617
- var import_common13 = require("@nestjs/common");
1618
- function _ts_decorate13(decorators, target, key, desc) {
2319
+ var import_nestjs_agent_core16 = require("@dudousxd/nestjs-agent-core");
2320
+ var import_common15 = require("@nestjs/common");
2321
+ function _ts_decorate15(decorators, target, key, desc) {
1619
2322
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1620
2323
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1621
2324
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1622
2325
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1623
2326
  }
1624
- __name(_ts_decorate13, "_ts_decorate");
1625
- function _ts_metadata12(k, v) {
2327
+ __name(_ts_decorate15, "_ts_decorate");
2328
+ function _ts_metadata14(k, v) {
1626
2329
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1627
2330
  }
1628
- __name(_ts_metadata12, "_ts_metadata");
1629
- function _ts_param10(paramIndex, decorator) {
2331
+ __name(_ts_metadata14, "_ts_metadata");
2332
+ function _ts_param13(paramIndex, decorator) {
1630
2333
  return function(target, key) {
1631
2334
  decorator(target, key, paramIndex);
1632
2335
  };
1633
2336
  }
1634
- __name(_ts_param10, "_ts_param");
2337
+ __name(_ts_param13, "_ts_param");
2338
+ var MAX_ANSWERED_QUESTIONS = 100;
2339
+ var MAX_VALUES_PER_QUESTION = 100;
2340
+ var MAX_ANSWER_VALUE_LENGTH = 4096;
2341
+ var MAX_REJECT_REASON_LENGTH = 4096;
2342
+ function toolCallId(claimed) {
2343
+ if (typeof claimed !== "string" || claimed.length === 0) {
2344
+ throw new import_common15.BadRequestException("toolCallId must be a non-empty string");
2345
+ }
2346
+ return claimed;
2347
+ }
2348
+ __name(toolCallId, "toolCallId");
2349
+ function rejectReason(claimed) {
2350
+ if (claimed === void 0) {
2351
+ return void 0;
2352
+ }
2353
+ if (typeof claimed !== "string") {
2354
+ throw new import_common15.BadRequestException("reason must be a string");
2355
+ }
2356
+ if (claimed.length > MAX_REJECT_REASON_LENGTH) {
2357
+ throw new import_common15.BadRequestException(`reason must be at most ${MAX_REJECT_REASON_LENGTH} characters`);
2358
+ }
2359
+ return claimed;
2360
+ }
2361
+ __name(rejectReason, "rejectReason");
2362
+ function answers(claimed) {
2363
+ if (claimed === void 0) {
2364
+ return void 0;
2365
+ }
2366
+ if (typeof claimed !== "object" || claimed === null || Array.isArray(claimed)) {
2367
+ throw new import_common15.BadRequestException("answers must be an object of questionId \u2192 chosen values");
2368
+ }
2369
+ const entries = Object.entries(claimed);
2370
+ if (entries.length > MAX_ANSWERED_QUESTIONS) {
2371
+ throw new import_common15.BadRequestException(`answers may cover at most ${MAX_ANSWERED_QUESTIONS} questions`);
2372
+ }
2373
+ const validated = /* @__PURE__ */ Object.create(null);
2374
+ for (const [questionId, values] of entries) {
2375
+ if (!Array.isArray(values)) {
2376
+ throw new import_common15.BadRequestException(`answers["${questionId}"] must be an array of chosen values`);
2377
+ }
2378
+ if (values.length > MAX_VALUES_PER_QUESTION) {
2379
+ throw new import_common15.BadRequestException(`answers["${questionId}"] may carry at most ${MAX_VALUES_PER_QUESTION} values`);
2380
+ }
2381
+ for (const value of values) {
2382
+ if (typeof value !== "string") {
2383
+ throw new import_common15.BadRequestException(`answers["${questionId}"] must contain only strings`);
2384
+ }
2385
+ if (value.length > MAX_ANSWER_VALUE_LENGTH) {
2386
+ throw new import_common15.BadRequestException(`answers["${questionId}"] values must be at most ${MAX_ANSWER_VALUE_LENGTH} characters`);
2387
+ }
2388
+ }
2389
+ validated[questionId] = values;
2390
+ }
2391
+ return validated;
2392
+ }
2393
+ __name(answers, "answers");
1635
2394
  var ToolCallController = class {
1636
2395
  static {
1637
2396
  __name(this, "ToolCallController");
@@ -1644,54 +2403,96 @@ var ToolCallController = class {
1644
2403
  }
1645
2404
  async approve(req, body) {
1646
2405
  const actor = await this.actorResolver.resolve(req);
1647
- await this.agent.approve(actor, body.toolCallId);
2406
+ await this.agent.approve(actor, toolCallId(body.toolCallId));
1648
2407
  return {
1649
2408
  ok: true
1650
2409
  };
1651
2410
  }
1652
2411
  async reject(req, body) {
1653
2412
  const actor = await this.actorResolver.resolve(req);
1654
- await this.agent.reject(actor, body.toolCallId, body.reason);
2413
+ await this.agent.reject(actor, toolCallId(body.toolCallId), rejectReason(body.reason));
2414
+ return {
2415
+ ok: true
2416
+ };
2417
+ }
2418
+ /**
2419
+ * Settle a parked question set. Alongside `approve`/`reject` rather than under a surface of its
2420
+ * own: an elicitation IS a parked tool call, gated by the same ownership check and delivered
2421
+ * through the same signal.
2422
+ */
2423
+ async answer(req, body) {
2424
+ const actor = await this.actorResolver.resolve(req);
2425
+ await this.agent.answer(actor, toolCallId(body.toolCallId), answers(body.answers));
2426
+ return {
2427
+ ok: true
2428
+ };
2429
+ }
2430
+ /** Decline to answer and let the agent proceed on the answers it pre-picked. */
2431
+ async skip(req, body) {
2432
+ const actor = await this.actorResolver.resolve(req);
2433
+ await this.agent.skip(actor, toolCallId(body.toolCallId));
1655
2434
  return {
1656
2435
  ok: true
1657
2436
  };
1658
2437
  }
1659
2438
  };
1660
- _ts_decorate13([
1661
- (0, import_common13.Post)("approve"),
1662
- _ts_param10(0, (0, import_common13.Req)()),
1663
- _ts_param10(1, (0, import_common13.Body)()),
1664
- _ts_metadata12("design:type", Function),
1665
- _ts_metadata12("design:paramtypes", [
2439
+ _ts_decorate15([
2440
+ (0, import_common15.Post)("approve"),
2441
+ _ts_param13(0, (0, import_common15.Req)()),
2442
+ _ts_param13(1, (0, import_common15.Body)()),
2443
+ _ts_metadata14("design:type", Function),
2444
+ _ts_metadata14("design:paramtypes", [
1666
2445
  typeof Request === "undefined" ? Object : Request,
1667
2446
  typeof ApproveBody === "undefined" ? Object : ApproveBody
1668
2447
  ]),
1669
- _ts_metadata12("design:returntype", Promise)
2448
+ _ts_metadata14("design:returntype", Promise)
1670
2449
  ], ToolCallController.prototype, "approve", null);
1671
- _ts_decorate13([
1672
- (0, import_common13.Post)("reject"),
1673
- _ts_param10(0, (0, import_common13.Req)()),
1674
- _ts_param10(1, (0, import_common13.Body)()),
1675
- _ts_metadata12("design:type", Function),
1676
- _ts_metadata12("design:paramtypes", [
2450
+ _ts_decorate15([
2451
+ (0, import_common15.Post)("reject"),
2452
+ _ts_param13(0, (0, import_common15.Req)()),
2453
+ _ts_param13(1, (0, import_common15.Body)()),
2454
+ _ts_metadata14("design:type", Function),
2455
+ _ts_metadata14("design:paramtypes", [
1677
2456
  typeof Request === "undefined" ? Object : Request,
1678
2457
  typeof RejectBody === "undefined" ? Object : RejectBody
1679
2458
  ]),
1680
- _ts_metadata12("design:returntype", Promise)
2459
+ _ts_metadata14("design:returntype", Promise)
1681
2460
  ], ToolCallController.prototype, "reject", null);
1682
- ToolCallController = _ts_decorate13([
1683
- (0, import_common13.Controller)("tool-call"),
1684
- _ts_param10(1, (0, import_common13.Inject)(import_nestjs_agent_core13.AGENT_ACTOR_RESOLVER)),
1685
- _ts_metadata12("design:type", Function),
1686
- _ts_metadata12("design:paramtypes", [
2461
+ _ts_decorate15([
2462
+ (0, import_common15.Post)("answer"),
2463
+ _ts_param13(0, (0, import_common15.Req)()),
2464
+ _ts_param13(1, (0, import_common15.Body)()),
2465
+ _ts_metadata14("design:type", Function),
2466
+ _ts_metadata14("design:paramtypes", [
2467
+ typeof Request === "undefined" ? Object : Request,
2468
+ typeof AnswerBody === "undefined" ? Object : AnswerBody
2469
+ ]),
2470
+ _ts_metadata14("design:returntype", Promise)
2471
+ ], ToolCallController.prototype, "answer", null);
2472
+ _ts_decorate15([
2473
+ (0, import_common15.Post)("skip"),
2474
+ _ts_param13(0, (0, import_common15.Req)()),
2475
+ _ts_param13(1, (0, import_common15.Body)()),
2476
+ _ts_metadata14("design:type", Function),
2477
+ _ts_metadata14("design:paramtypes", [
2478
+ typeof Request === "undefined" ? Object : Request,
2479
+ typeof ApproveBody === "undefined" ? Object : ApproveBody
2480
+ ]),
2481
+ _ts_metadata14("design:returntype", Promise)
2482
+ ], ToolCallController.prototype, "skip", null);
2483
+ ToolCallController = _ts_decorate15([
2484
+ (0, import_common15.Controller)("tool-call"),
2485
+ _ts_param13(1, (0, import_common15.Inject)(import_nestjs_agent_core16.AGENT_ACTOR_RESOLVER)),
2486
+ _ts_metadata14("design:type", Function),
2487
+ _ts_metadata14("design:paramtypes", [
1687
2488
  typeof AgentService === "undefined" ? Object : AgentService,
1688
2489
  typeof ActorResolver === "undefined" ? Object : ActorResolver
1689
2490
  ])
1690
2491
  ], ToolCallController);
1691
2492
 
1692
2493
  // src/discovery/agent-discovery.service.ts
1693
- var import_nestjs_agent_core14 = require("@dudousxd/nestjs-agent-core");
1694
- var import_common14 = require("@nestjs/common");
2494
+ var import_nestjs_agent_core17 = require("@dudousxd/nestjs-agent-core");
2495
+ var import_common16 = require("@nestjs/common");
1695
2496
  var import_core = require("@nestjs/core");
1696
2497
 
1697
2498
  // src/decorator/agent.decorator.ts
@@ -1708,23 +2509,23 @@ var SYSTEM_PROMPT_METADATA = Symbol.for("@dudousxd/nestjs-agent:system-prompt");
1708
2509
  var SYSTEM_PROMPT_CONTRIBUTOR_METADATA = Symbol.for("@dudousxd/nestjs-agent:system-prompt-contributor");
1709
2510
 
1710
2511
  // src/discovery/agent-discovery.service.ts
1711
- function _ts_decorate14(decorators, target, key, desc) {
2512
+ function _ts_decorate16(decorators, target, key, desc) {
1712
2513
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1713
2514
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1714
2515
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1715
2516
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1716
2517
  }
1717
- __name(_ts_decorate14, "_ts_decorate");
1718
- function _ts_metadata13(k, v) {
2518
+ __name(_ts_decorate16, "_ts_decorate");
2519
+ function _ts_metadata15(k, v) {
1719
2520
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1720
2521
  }
1721
- __name(_ts_metadata13, "_ts_metadata");
1722
- function _ts_param11(paramIndex, decorator) {
2522
+ __name(_ts_metadata15, "_ts_metadata");
2523
+ function _ts_param14(paramIndex, decorator) {
1723
2524
  return function(target, key) {
1724
2525
  decorator(target, key, paramIndex);
1725
2526
  };
1726
2527
  }
1727
- __name(_ts_param11, "_ts_param");
2528
+ __name(_ts_param14, "_ts_param");
1728
2529
  var AgentDiscoveryService = class _AgentDiscoveryService {
1729
2530
  static {
1730
2531
  __name(this, "AgentDiscoveryService");
@@ -1733,7 +2534,7 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
1733
2534
  scanner;
1734
2535
  registry;
1735
2536
  contributors;
1736
- logger = new import_common14.Logger(_AgentDiscoveryService.name);
2537
+ logger = new import_common16.Logger(_AgentDiscoveryService.name);
1737
2538
  constructor(discovery, scanner, registry, contributors) {
1738
2539
  this.discovery = discovery;
1739
2540
  this.scanner = scanner;
@@ -1772,23 +2573,53 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
1772
2573
  ...meta.maxSteps !== void 0 ? {
1773
2574
  maxSteps: meta.maxSteps
1774
2575
  } : {},
2576
+ ...meta.maxDelegationDepth !== void 0 ? {
2577
+ maxDelegationDepth: meta.maxDelegationDepth
2578
+ } : {},
2579
+ ...meta.maxAgentAppearances !== void 0 ? {
2580
+ maxAgentAppearances: meta.maxAgentAppearances
2581
+ } : {},
2582
+ ...meta.history !== void 0 ? {
2583
+ history: meta.history
2584
+ } : {},
2585
+ ...meta.outputSchema !== void 0 ? {
2586
+ outputSchema: meta.outputSchema
2587
+ } : {},
2588
+ ...meta.intake !== void 0 ? {
2589
+ intake: meta.intake
2590
+ } : {},
2591
+ ...meta.ask !== void 0 ? {
2592
+ ask: meta.ask
2593
+ } : {},
2594
+ ...meta.outputRepairAttempts !== void 0 ? {
2595
+ outputRepairAttempts: meta.outputRepairAttempts
2596
+ } : {},
1775
2597
  ...meta.handoff !== void 0 ? {
1776
- delegatesTo: this.handoffNames(meta)
2598
+ delegatesTo: this.handoffEdges(meta)
1777
2599
  } : {}
1778
2600
  };
1779
2601
  }
1780
- /** Resolve each handoff `@Agent` class to its registered name (skipping non-agent classes). */
1781
- handoffNames(meta) {
1782
- const names = [];
1783
- for (const target of meta.handoff ?? []) {
2602
+ /**
2603
+ * Resolve each handoff entry to an {@link AgentDelegation} — its target's registered name, plus
2604
+ * whether that edge detaches (skipping non-agent classes). A bare name is kept for a plain edge
2605
+ * rather than an always-object form, so a definition an older host built by hand still reads.
2606
+ */
2607
+ handoffEdges(meta) {
2608
+ const edges = [];
2609
+ for (const entry of meta.handoff ?? []) {
2610
+ const target = typeof entry === "function" ? entry : entry.agent;
2611
+ const detached = typeof entry === "function" ? false : entry.detached === true;
1784
2612
  const targetMeta = readAgentMetadata(target);
1785
2613
  if (targetMeta === void 0) {
1786
2614
  this.logger.warn(`Agent "${meta.name}" hands off to ${target.name}, which is not an @Agent \u2014 skipped.`);
1787
2615
  continue;
1788
2616
  }
1789
- names.push(targetMeta.name);
2617
+ edges.push(detached ? {
2618
+ agent: targetMeta.name,
2619
+ detached: true
2620
+ } : targetMeta.name);
1790
2621
  }
1791
- return names;
2622
+ return edges;
1792
2623
  }
1793
2624
  /** Push every `@SystemPromptContributor()` method on `instance` (bound) into the contributor list. */
1794
2625
  collectContributors(instance) {
@@ -1821,22 +2652,22 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
1821
2652
  return (ctx) => candidate.call(instance, ctx);
1822
2653
  }
1823
2654
  };
1824
- AgentDiscoveryService = _ts_decorate14([
1825
- (0, import_common14.Injectable)(),
1826
- _ts_param11(2, (0, import_common14.Inject)(import_nestjs_agent_core14.AGENT_REGISTRY)),
1827
- _ts_param11(3, (0, import_common14.Inject)(import_nestjs_agent_core14.AGENT_PROMPT_CONTRIBUTORS)),
1828
- _ts_metadata13("design:type", Function),
1829
- _ts_metadata13("design:paramtypes", [
2655
+ AgentDiscoveryService = _ts_decorate16([
2656
+ (0, import_common16.Injectable)(),
2657
+ _ts_param14(2, (0, import_common16.Inject)(import_nestjs_agent_core17.AGENT_REGISTRY)),
2658
+ _ts_param14(3, (0, import_common16.Inject)(import_nestjs_agent_core17.AGENT_PROMPT_CONTRIBUTORS)),
2659
+ _ts_metadata15("design:type", Function),
2660
+ _ts_metadata15("design:paramtypes", [
1830
2661
  typeof import_core.DiscoveryService === "undefined" ? Object : import_core.DiscoveryService,
1831
2662
  typeof import_core.MetadataScanner === "undefined" ? Object : import_core.MetadataScanner,
1832
- typeof import_nestjs_agent_core14.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core14.AgentRegistry,
2663
+ typeof import_nestjs_agent_core17.AgentRegistry === "undefined" ? Object : import_nestjs_agent_core17.AgentRegistry,
1833
2664
  Array
1834
2665
  ])
1835
2666
  ], AgentDiscoveryService);
1836
2667
 
1837
2668
  // src/discovery/ai-tool-discovery.service.ts
1838
- var import_nestjs_agent_core15 = require("@dudousxd/nestjs-agent-core");
1839
- var import_common15 = require("@nestjs/common");
2669
+ var import_nestjs_agent_core18 = require("@dudousxd/nestjs-agent-core");
2670
+ var import_common17 = require("@nestjs/common");
1840
2671
  var import_core2 = require("@nestjs/core");
1841
2672
  var import_zod = require("zod");
1842
2673
 
@@ -1856,23 +2687,23 @@ function isBrandedFunctionalTool(value) {
1856
2687
  __name(isBrandedFunctionalTool, "isBrandedFunctionalTool");
1857
2688
 
1858
2689
  // src/discovery/ai-tool-discovery.service.ts
1859
- function _ts_decorate15(decorators, target, key, desc) {
2690
+ function _ts_decorate17(decorators, target, key, desc) {
1860
2691
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1861
2692
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1862
2693
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1863
2694
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1864
2695
  }
1865
- __name(_ts_decorate15, "_ts_decorate");
1866
- function _ts_metadata14(k, v) {
2696
+ __name(_ts_decorate17, "_ts_decorate");
2697
+ function _ts_metadata16(k, v) {
1867
2698
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1868
2699
  }
1869
- __name(_ts_metadata14, "_ts_metadata");
1870
- function _ts_param12(paramIndex, decorator) {
2700
+ __name(_ts_metadata16, "_ts_metadata");
2701
+ function _ts_param15(paramIndex, decorator) {
1871
2702
  return function(target, key) {
1872
2703
  decorator(target, key, paramIndex);
1873
2704
  };
1874
2705
  }
1875
- __name(_ts_param12, "_ts_param");
2706
+ __name(_ts_param15, "_ts_param");
1876
2707
  var AiToolDiscoveryService = class _AiToolDiscoveryService {
1877
2708
  static {
1878
2709
  __name(this, "AiToolDiscoveryService");
@@ -1881,7 +2712,7 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
1881
2712
  registry;
1882
2713
  agents;
1883
2714
  options;
1884
- logger = new import_common15.Logger(_AiToolDiscoveryService.name);
2715
+ logger = new import_common17.Logger(_AiToolDiscoveryService.name);
1885
2716
  constructor(discovery, registry, agents, options) {
1886
2717
  this.discovery = discovery;
1887
2718
  this.registry = registry;
@@ -1948,22 +2779,30 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
1948
2779
  }
1949
2780
  let delegates = 0;
1950
2781
  for (const definition of this.agents.list()) {
1951
- for (const target of definition.delegatesTo ?? []) {
2782
+ for (const edge of definition.delegatesTo ?? []) {
2783
+ const { agent: target, detached } = (0, import_nestjs_agent_core18.normalizeDelegation)(edge);
1952
2784
  const targetDefinition = this.agents.get(target);
1953
2785
  if (targetDefinition === void 0) {
1954
2786
  throw new Error(`Agent "${definition.name}" hands off to "${target}", which is not a registered @Agent. Declare it as an @Agent provider or fix the reference.`);
1955
2787
  }
1956
- const name = delegateToolName(target);
2788
+ const name = delegateToolName({
2789
+ target,
2790
+ detached
2791
+ });
1957
2792
  if (this.registry.has(name)) {
1958
2793
  continue;
1959
2794
  }
1960
2795
  const targetBlurb = typeof targetDefinition.systemPrompt === "string" ? ` It is: ${targetDefinition.systemPrompt}` : "";
2796
+ const description = detached ? `Start the "${target}" agent working on a task in the BACKGROUND. Returns immediately with a receipt, NOT an answer \u2014 the answer is delivered to this conversation as a separate message later. Use it for work the user does not need to sit and wait for.${targetBlurb}` : `Delegate a task to the "${target}" agent and get its answer.${targetBlurb}`;
1961
2797
  this.registry.register(
1962
2798
  {
1963
2799
  name,
1964
2800
  kind: "agent",
1965
2801
  targetAgent: target,
1966
- description: `Delegate a task to the "${target}" agent and get its answer.${targetBlurb}`,
2802
+ ...detached ? {
2803
+ detached: true
2804
+ } : {},
2805
+ description,
1967
2806
  inputSchema: import_zod.z.object({
1968
2807
  task: import_zod.z.string()
1969
2808
  })
@@ -1991,13 +2830,13 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
1991
2830
  return true;
1992
2831
  }
1993
2832
  };
1994
- AiToolDiscoveryService = _ts_decorate15([
1995
- (0, import_common15.Injectable)(),
1996
- _ts_param12(1, (0, import_common15.Inject)(import_nestjs_agent_core15.AGENT_TOOL_REGISTRY)),
1997
- _ts_param12(2, (0, import_common15.Inject)(import_nestjs_agent_core15.AGENT_REGISTRY)),
1998
- _ts_param12(3, (0, import_common15.Inject)(import_nestjs_agent_core15.AGENT_OPTIONS)),
1999
- _ts_metadata14("design:type", Function),
2000
- _ts_metadata14("design:paramtypes", [
2833
+ AiToolDiscoveryService = _ts_decorate17([
2834
+ (0, import_common17.Injectable)(),
2835
+ _ts_param15(1, (0, import_common17.Inject)(import_nestjs_agent_core18.AGENT_TOOL_REGISTRY)),
2836
+ _ts_param15(2, (0, import_common17.Inject)(import_nestjs_agent_core18.AGENT_REGISTRY)),
2837
+ _ts_param15(3, (0, import_common17.Inject)(import_nestjs_agent_core18.AGENT_OPTIONS)),
2838
+ _ts_metadata16("design:type", Function),
2839
+ _ts_metadata16("design:paramtypes", [
2001
2840
  typeof import_core2.DiscoveryService === "undefined" ? Object : import_core2.DiscoveryService,
2002
2841
  typeof ToolRegistry === "undefined" ? Object : ToolRegistry,
2003
2842
  typeof AgentRegistry === "undefined" ? Object : AgentRegistry,
@@ -2005,6 +2844,95 @@ AiToolDiscoveryService = _ts_decorate15([
2005
2844
  ])
2006
2845
  ], AiToolDiscoveryService);
2007
2846
 
2847
+ // src/discovery/skill-discovery.service.ts
2848
+ var import_nestjs_agent_core20 = require("@dudousxd/nestjs-agent-core");
2849
+ var import_common18 = require("@nestjs/common");
2850
+ var import_core3 = require("@nestjs/core");
2851
+
2852
+ // src/decorator/skill.decorator.ts
2853
+ var import_reflect_metadata4 = require("reflect-metadata");
2854
+ var import_nestjs_agent_core19 = require("@dudousxd/nestjs-agent-core");
2855
+ var SKILL_METADATA = Symbol.for("@dudousxd/nestjs-agent:skill-metadata");
2856
+ function readSkillMetadata(target) {
2857
+ return Reflect.getMetadata(SKILL_METADATA, target);
2858
+ }
2859
+ __name(readSkillMetadata, "readSkillMetadata");
2860
+ function skillScope(options) {
2861
+ return options.scope ?? import_nestjs_agent_core19.GLOBAL_SCOPE;
2862
+ }
2863
+ __name(skillScope, "skillScope");
2864
+
2865
+ // src/discovery/skill-discovery.service.ts
2866
+ function _ts_decorate18(decorators, target, key, desc) {
2867
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2868
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2869
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2870
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2871
+ }
2872
+ __name(_ts_decorate18, "_ts_decorate");
2873
+ function _ts_metadata17(k, v) {
2874
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2875
+ }
2876
+ __name(_ts_metadata17, "_ts_metadata");
2877
+ function _ts_param16(paramIndex, decorator) {
2878
+ return function(target, key) {
2879
+ decorator(target, key, paramIndex);
2880
+ };
2881
+ }
2882
+ __name(_ts_param16, "_ts_param");
2883
+ var SkillDiscoveryService = class _SkillDiscoveryService {
2884
+ static {
2885
+ __name(this, "SkillDiscoveryService");
2886
+ }
2887
+ discovery;
2888
+ declared;
2889
+ logger = new import_common18.Logger(_SkillDiscoveryService.name);
2890
+ constructor(discovery, declared) {
2891
+ this.discovery = discovery;
2892
+ this.declared = declared;
2893
+ }
2894
+ onModuleInit() {
2895
+ for (const wrapper of this.discovery.getProviders()) {
2896
+ const instance = wrapper.instance;
2897
+ if (instance === null || typeof instance !== "object") {
2898
+ continue;
2899
+ }
2900
+ const meta = readSkillMetadata(instance.constructor);
2901
+ if (meta === void 0) {
2902
+ continue;
2903
+ }
2904
+ const body = this.bodyOf(instance, meta.body);
2905
+ if (body === void 0) {
2906
+ this.logger.warn(`Skill "${meta.name}" declares no body \u2014 add a \`body()\` method or \`@Skill({ body })\`. Skipped.`);
2907
+ continue;
2908
+ }
2909
+ this.declared.push({
2910
+ name: meta.name,
2911
+ description: meta.description,
2912
+ scope: skillScope(meta),
2913
+ body
2914
+ });
2915
+ }
2916
+ }
2917
+ /** The instance's `body()` method (bound), else the flat string, else nothing to offer. */
2918
+ bodyOf(instance, flat) {
2919
+ const candidate = instance.body;
2920
+ if (typeof candidate === "function") {
2921
+ return (ctx) => candidate.call(instance, ctx);
2922
+ }
2923
+ return flat === void 0 ? void 0 : () => flat;
2924
+ }
2925
+ };
2926
+ SkillDiscoveryService = _ts_decorate18([
2927
+ (0, import_common18.Injectable)(),
2928
+ _ts_param16(1, (0, import_common18.Inject)(import_nestjs_agent_core20.AGENT_SKILL_SOURCES)),
2929
+ _ts_metadata17("design:type", Function),
2930
+ _ts_metadata17("design:paramtypes", [
2931
+ typeof import_core3.DiscoveryService === "undefined" ? Object : import_core3.DiscoveryService,
2932
+ Array
2933
+ ])
2934
+ ], SkillDiscoveryService);
2935
+
2008
2936
  // src/ledger-quota-store.ts
2009
2937
  var LedgerQuotaStore = class {
2010
2938
  static {
@@ -2024,38 +2952,44 @@ var LedgerQuotaStore = class {
2024
2952
  withinLimit: usedTokens < this.limitTokens
2025
2953
  };
2026
2954
  }
2027
- async bump() {
2955
+ async bump(_actorRef, _day, _tokens) {
2028
2956
  }
2029
2957
  };
2030
2958
 
2031
2959
  // src/runner/inline-agent-runner.ts
2032
- var import_nestjs_agent_core16 = require("@dudousxd/nestjs-agent-core");
2033
- var import_common16 = require("@nestjs/common");
2034
- function _ts_decorate16(decorators, target, key, desc) {
2960
+ var import_nestjs_agent_core21 = require("@dudousxd/nestjs-agent-core");
2961
+ var import_common19 = require("@nestjs/common");
2962
+ function _ts_decorate19(decorators, target, key, desc) {
2035
2963
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2036
2964
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2037
2965
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2038
2966
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2039
2967
  }
2040
- __name(_ts_decorate16, "_ts_decorate");
2041
- function _ts_metadata15(k, v) {
2968
+ __name(_ts_decorate19, "_ts_decorate");
2969
+ function _ts_metadata18(k, v) {
2042
2970
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2043
2971
  }
2044
- __name(_ts_metadata15, "_ts_metadata");
2045
- function _ts_param13(paramIndex, decorator) {
2972
+ __name(_ts_metadata18, "_ts_metadata");
2973
+ function _ts_param17(paramIndex, decorator) {
2046
2974
  return function(target, key) {
2047
2975
  decorator(target, key, paramIndex);
2048
2976
  };
2049
2977
  }
2050
- __name(_ts_param13, "_ts_param");
2978
+ __name(_ts_param17, "_ts_param");
2051
2979
  var InlineAgentRunner = class _InlineAgentRunner {
2052
2980
  static {
2053
2981
  __name(this, "InlineAgentRunner");
2054
2982
  }
2055
2983
  factory;
2056
2984
  store;
2057
- logger = new import_common16.Logger(_InlineAgentRunner.name);
2985
+ logger = new import_common19.Logger(_InlineAgentRunner.name);
2058
2986
  pending = /* @__PURE__ */ new Map();
2987
+ /**
2988
+ * Runs someone has asked to stop. In-process, like `pending`, and for the same reason: this runner
2989
+ * is single-replica by construction, so the request is readable by the only loop that could be
2990
+ * running it. A cancelled id is dropped once the run settles, so the set tracks live runs only.
2991
+ */
2992
+ cancelled = /* @__PURE__ */ new Set();
2059
2993
  constructor(factory, store) {
2060
2994
  this.factory = factory;
2061
2995
  this.store = store;
@@ -2064,15 +2998,31 @@ var InlineAgentRunner = class _InlineAgentRunner {
2064
2998
  const runId = crypto.randomUUID();
2065
2999
  const day = input.day ?? utcDay();
2066
3000
  const deps = this.factory.forAgent(input.agentName);
2067
- const hooks = this.topLevelHooks(runId, deps, input.actor, day);
2068
- void (0, import_nestjs_agent_core16.runAgentLoop)({
3001
+ const hooks = this.topLevelHooks({
3002
+ runId,
3003
+ deps,
3004
+ actor: input.actor,
3005
+ day,
3006
+ threadId: input.threadId,
3007
+ chainBelow: [
3008
+ ...input.delegationPath ?? [],
3009
+ ...input.agentName !== void 0 ? [
3010
+ input.agentName
3011
+ ] : []
3012
+ ]
3013
+ });
3014
+ void (0, import_nestjs_agent_core21.runAgentLoop)({
2069
3015
  ...deps,
2070
3016
  day
2071
3017
  }, input, hooks).then(() => this.store.setActiveStream(input.threadId, null)).catch(async (error) => {
3018
+ if (error instanceof import_nestjs_agent_core21.RunCancelledError) {
3019
+ await this.settleCancelled(runId, input.threadId, deps);
3020
+ return;
3021
+ }
2072
3022
  const message = error instanceof Error ? error.message : String(error);
2073
- const code = error instanceof import_nestjs_agent_core16.QuotaExceededError ? "quota_exceeded" : "run_failed";
3023
+ const code = (0, import_nestjs_agent_core21.agentFailureCode)(error);
2074
3024
  this.logger.error(`agent run ${runId} failed (${code}): ${message}`);
2075
- (0, import_nestjs_agent_core16.publishAgentRunFailed)({
3025
+ (0, import_nestjs_agent_core21.publishAgentRunFailed)({
2076
3026
  runId,
2077
3027
  code,
2078
3028
  message
@@ -2089,33 +3039,216 @@ var InlineAgentRunner = class _InlineAgentRunner {
2089
3039
  code,
2090
3040
  message
2091
3041
  });
2092
- });
3042
+ }).finally(() => this.cancelled.delete(runId));
2093
3043
  return {
2094
3044
  runId
2095
3045
  };
2096
3046
  }
2097
- async signal(runId, toolCallId, decision) {
2098
- const key = `${runId}:${toolCallId}`;
2099
- const resolve = this.pending.get(key);
2100
- if (resolve !== void 0) {
3047
+ async signal(runId, toolCallId2, reply) {
3048
+ const key = `${runId}:${toolCallId2}`;
3049
+ const waiter = this.pending.get(key);
3050
+ if (waiter !== void 0) {
2101
3051
  this.pending.delete(key);
2102
- resolve(decision);
3052
+ waiter.resolve(reply);
2103
3053
  }
2104
3054
  }
3055
+ /**
3056
+ * Ask a run to stop, and settle whatever it was parked on.
3057
+ *
3058
+ * The loop observes the request at its next safe point (between steps, before the turn's tools) and
3059
+ * unwinds from there — so a tool already executing is left to finish, and its result is recorded
3060
+ * exactly as it would have been. What this cannot wait for is a turn parked on a human: that wait
3061
+ * is a promise nobody is going to resolve, so it is REJECTED here with the same
3062
+ * {@link RunCancelledError} the loop would have thrown, and the run unwinds through the identical
3063
+ * path.
3064
+ *
3065
+ * Settlement — the run row, the thread's active stream, the stream's terminal — belongs to the
3066
+ * `RunCancelledError` catch in `start`, so a cancel and an ordinary failure settle in one place
3067
+ * each and can never both write.
3068
+ */
2105
3069
  async cancel(runId) {
2106
- const deps = this.factory.forAgent();
3070
+ this.cancelled.add(runId);
3071
+ for (const [key, waiter] of this.pending) {
3072
+ if (key.startsWith(`${runId}:`)) {
3073
+ this.pending.delete(key);
3074
+ waiter.reject(new import_nestjs_agent_core21.RunCancelledError());
3075
+ }
3076
+ }
3077
+ await Promise.resolve();
3078
+ }
3079
+ /**
3080
+ * The single place a cancelled run's state is settled: recorded as its own terminal (never
3081
+ * `failed` — a user pressing Stop must not land in someone's error rate), the thread released, and
3082
+ * the stream ENDED after a `cancelled` frame rather than failed, so a client that retries failed
3083
+ * streams does not retry this one.
3084
+ */
3085
+ async settleCancelled(runId, threadId, deps) {
3086
+ this.logger.log(`agent run ${runId} cancelled`);
3087
+ await this.store.setActiveStream(threadId, null);
2107
3088
  const writer = await deps.sink.open(runId);
3089
+ await writer.write((0, import_nestjs_agent_core21.encodeStreamEvent)({
3090
+ kind: "cancelled"
3091
+ }));
2108
3092
  await writer.end();
3093
+ await this.store.recordRunEnd?.({
3094
+ runId,
3095
+ status: "cancelled"
3096
+ });
3097
+ }
3098
+ /**
3099
+ * Park a run on a human, keyed by run + tool call. One map for approvals and for question-set
3100
+ * answers alike: both wait on the same key, and `signal` cannot tell (or need to tell) which
3101
+ * shape it is delivering — the loop asked for one and only ever gets what the caller sent. A
3102
+ * cancel settles the wait too, by rejecting it.
3103
+ */
3104
+ park(runId, toolCallId2) {
3105
+ return new Promise((resolve, reject) => {
3106
+ this.pending.set(`${runId}:${toolCallId2}`, {
3107
+ resolve,
3108
+ reject
3109
+ });
3110
+ });
2109
3111
  }
2110
- topLevelHooks(runId, deps, actor, day) {
3112
+ topLevelHooks(args) {
3113
+ const { runId, deps, actor, day, threadId, chainBelow } = args;
2111
3114
  return {
2112
3115
  runId,
2113
3116
  openSink: /* @__PURE__ */ __name(() => deps.sink.open(runId), "openSink"),
2114
- awaitApproval: /* @__PURE__ */ __name((call) => new Promise((resolve) => {
2115
- this.pending.set(`${runId}:${call.id}`, resolve);
2116
- }), "awaitApproval"),
3117
+ awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
3118
+ awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
3119
+ step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
3120
+ parallel: import_nestjs_agent_core21.settleAll,
3121
+ cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
3122
+ runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested({
3123
+ agentName,
3124
+ task,
3125
+ actor,
3126
+ day,
3127
+ depth: 1,
3128
+ path: chainBelow,
3129
+ sinkRunId: runId,
3130
+ parentRunId: runId
3131
+ }), "runAgent"),
3132
+ startAgent: /* @__PURE__ */ __name(({ agentName, task, toolCallId: toolCallId2 }) => this.startDetached({
3133
+ agentName,
3134
+ task,
3135
+ actor,
3136
+ day,
3137
+ depth: 1,
3138
+ path: chainBelow,
3139
+ parentRunId: runId,
3140
+ deliverTo: {
3141
+ threadId,
3142
+ toolCallId: toolCallId2
3143
+ }
3144
+ }), "startAgent")
3145
+ };
3146
+ }
3147
+ /**
3148
+ * Delegate WITHOUT waiting: a nested loop nobody awaits, on its own thread and its own sink, which
3149
+ * posts its answer back into the delegating thread when it lands (`deliverTo`, settled by the
3150
+ * loop). The calling turn gets the run id straight back and finishes.
3151
+ *
3152
+ * No `sinkRunId`, unlike {@link runNested}: forwarding into the stream the human is watching would
3153
+ * write into a turn that has already ended. Its own approvals resolve through the shared pending
3154
+ * map keyed by its own runId — which is what the pending-approvals surface routes to.
3155
+ */
3156
+ async startDetached(args) {
3157
+ const { agentName, task, actor, day, depth, path, parentRunId, deliverTo } = args;
3158
+ const subThread = await this.store.createThread({
3159
+ actor,
3160
+ transient: true
3161
+ });
3162
+ const runId = crypto.randomUUID();
3163
+ await this.store.setActiveStream(subThread.id, runId);
3164
+ const deps = this.factory.forAgent(agentName);
3165
+ const hooks = {
3166
+ runId,
3167
+ openSink: /* @__PURE__ */ __name(() => deps.sink.open(runId), "openSink"),
3168
+ awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
3169
+ awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
2117
3170
  step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
2118
- runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested(agentName, task, actor, day, 1, runId), "runAgent")
3171
+ parallel: import_nestjs_agent_core21.settleAll,
3172
+ cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
3173
+ runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
3174
+ agentName: childName,
3175
+ task: childTask,
3176
+ actor,
3177
+ day,
3178
+ depth: depth + 1,
3179
+ path: [
3180
+ ...path,
3181
+ agentName
3182
+ ],
3183
+ // A detached run owns a stream of its own, so ITS sub-agents forward into that one.
3184
+ sinkRunId: runId,
3185
+ parentRunId: runId
3186
+ }), "runAgent"),
3187
+ startAgent: /* @__PURE__ */ __name(({ agentName: childName, task: childTask, toolCallId: toolCallId2 }) => this.startDetached({
3188
+ agentName: childName,
3189
+ task: childTask,
3190
+ actor,
3191
+ day,
3192
+ depth: depth + 1,
3193
+ path: [
3194
+ ...path,
3195
+ agentName
3196
+ ],
3197
+ parentRunId: runId,
3198
+ deliverTo: {
3199
+ threadId: subThread.id,
3200
+ toolCallId: toolCallId2
3201
+ }
3202
+ }), "startAgent")
3203
+ };
3204
+ void (0, import_nestjs_agent_core21.runAgentLoop)({
3205
+ ...deps,
3206
+ day
3207
+ }, {
3208
+ threadId: subThread.id,
3209
+ actor,
3210
+ userText: task,
3211
+ agentName,
3212
+ day,
3213
+ delegationDepth: depth,
3214
+ delegationPath: path,
3215
+ parentRunId,
3216
+ deliverTo
3217
+ }, hooks).catch(async (error) => {
3218
+ const cancelled = error instanceof import_nestjs_agent_core21.RunCancelledError;
3219
+ const message = error instanceof Error ? error.message : String(error);
3220
+ if (!cancelled) {
3221
+ this.logger.error(`detached agent run ${runId} failed: ${message}`);
3222
+ (0, import_nestjs_agent_core21.publishAgentRunFailed)({
3223
+ runId,
3224
+ code: (0, import_nestjs_agent_core21.agentFailureCode)(error),
3225
+ message
3226
+ });
3227
+ }
3228
+ await this.store.recordRunEnd?.({
3229
+ runId,
3230
+ status: cancelled ? "cancelled" : "failed",
3231
+ ...cancelled ? {} : {
3232
+ errorCode: (0, import_nestjs_agent_core21.agentFailureCode)(error),
3233
+ errorMessage: message
3234
+ }
3235
+ });
3236
+ await (0, import_nestjs_agent_core21.settleUnsettledDelegation)({
3237
+ store: this.store,
3238
+ delivery: deliverTo,
3239
+ agent: agentName,
3240
+ runId,
3241
+ status: cancelled ? "cancelled" : "failed",
3242
+ ...cancelled ? {} : {
3243
+ error: message
3244
+ }
3245
+ });
3246
+ }).finally(async () => {
3247
+ this.cancelled.delete(runId);
3248
+ await this.store.setActiveStream(subThread.id, null);
3249
+ });
3250
+ return {
3251
+ runId
2119
3252
  };
2120
3253
  }
2121
3254
  /**
@@ -2123,7 +3256,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
2123
3256
  * (the top-level run the human is watching) so its output and any pending action tool are visible,
2124
3257
  * and its own approvals resolve through the shared pending map keyed by its own runId.
2125
3258
  */
2126
- async runNested(agentName, task, actor, day, depth, sinkRunId) {
3259
+ async runNested(args) {
3260
+ const { agentName, task, actor, day, depth, path, sinkRunId, parentRunId } = args;
2127
3261
  const subThread = await this.store.createThread({
2128
3262
  actor,
2129
3263
  transient: true
@@ -2135,14 +3269,45 @@ var InlineAgentRunner = class _InlineAgentRunner {
2135
3269
  runId,
2136
3270
  // Forward into the top-level stream; the top-level run owns end/fail on that shared sink.
2137
3271
  openSink: /* @__PURE__ */ __name(async () => childSinkWriter(await deps.sink.open(sinkRunId)), "openSink"),
2138
- awaitApproval: /* @__PURE__ */ __name((call) => new Promise((resolve) => {
2139
- this.pending.set(`${runId}:${call.id}`, resolve);
2140
- }), "awaitApproval"),
3272
+ awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
3273
+ awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
2141
3274
  step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
2142
- runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested(childName, childTask, actor, day, depth + 1, sinkRunId), "runAgent")
3275
+ parallel: import_nestjs_agent_core21.settleAll,
3276
+ // A child stops when it is cancelled OR when the run a human is actually watching is: the
3277
+ // canceller names the top-level run, which is the only id that ever left the server.
3278
+ cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId) || this.cancelled.has(sinkRunId), "cancelled"),
3279
+ runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
3280
+ agentName: childName,
3281
+ task: childTask,
3282
+ actor,
3283
+ day,
3284
+ depth: depth + 1,
3285
+ path: [
3286
+ ...path,
3287
+ agentName
3288
+ ],
3289
+ sinkRunId,
3290
+ parentRunId: runId
3291
+ }), "runAgent"),
3292
+ startAgent: /* @__PURE__ */ __name(({ agentName: childName, task: childTask, toolCallId: toolCallId2 }) => this.startDetached({
3293
+ agentName: childName,
3294
+ task: childTask,
3295
+ actor,
3296
+ day,
3297
+ depth: depth + 1,
3298
+ path: [
3299
+ ...path,
3300
+ agentName
3301
+ ],
3302
+ parentRunId: runId,
3303
+ deliverTo: {
3304
+ threadId: subThread.id,
3305
+ toolCallId: toolCallId2
3306
+ }
3307
+ }), "startAgent")
2143
3308
  };
2144
3309
  try {
2145
- return await (0, import_nestjs_agent_core16.runAgentLoop)({
3310
+ return await (0, import_nestjs_agent_core21.runAgentLoop)({
2146
3311
  ...deps,
2147
3312
  day
2148
3313
  }, {
@@ -2152,6 +3317,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
2152
3317
  agentName,
2153
3318
  day,
2154
3319
  delegationDepth: depth,
3320
+ delegationPath: path,
3321
+ parentRunId,
2155
3322
  sinkRunId
2156
3323
  }, hooks);
2157
3324
  } finally {
@@ -2159,112 +3326,177 @@ var InlineAgentRunner = class _InlineAgentRunner {
2159
3326
  }
2160
3327
  }
2161
3328
  };
2162
- InlineAgentRunner = _ts_decorate16([
2163
- (0, import_common16.Injectable)(),
2164
- _ts_param13(0, (0, import_common16.Inject)(import_nestjs_agent_core16.AGENT_DEPS_FACTORY)),
2165
- _ts_param13(1, (0, import_common16.Inject)(import_nestjs_agent_core16.AGENT_STORE)),
2166
- _ts_metadata15("design:type", Function),
2167
- _ts_metadata15("design:paramtypes", [
3329
+ InlineAgentRunner = _ts_decorate19([
3330
+ (0, import_common19.Injectable)(),
3331
+ _ts_param17(0, (0, import_common19.Inject)(import_nestjs_agent_core21.AGENT_DEPS_FACTORY)),
3332
+ _ts_param17(1, (0, import_common19.Inject)(import_nestjs_agent_core21.AGENT_STORE)),
3333
+ _ts_metadata18("design:type", Function),
3334
+ _ts_metadata18("design:paramtypes", [
2168
3335
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
2169
3336
  typeof AgentStore === "undefined" ? Object : AgentStore
2170
3337
  ])
2171
3338
  ], InlineAgentRunner);
2172
3339
 
3340
+ // src/skills-config.ts
3341
+ var import_nestjs_agent_core22 = require("@dudousxd/nestjs-agent-core");
3342
+ function declaredSkillProvider(declared) {
3343
+ return {
3344
+ list: /* @__PURE__ */ __name(({ scopes }) => declared.filter((skill) => scopes.includes(skill.scope)).map(({ name, description, scope }) => ({
3345
+ name,
3346
+ description,
3347
+ scope
3348
+ })), "list"),
3349
+ load: /* @__PURE__ */ __name(async ({ name, scope, ctx }) => {
3350
+ const match = declared.find((skill) => skill.name === name && skill.scope === scope);
3351
+ return match === void 0 ? null : await match.body(ctx);
3352
+ }, "load")
3353
+ };
3354
+ }
3355
+ __name(declaredSkillProvider, "declaredSkillProvider");
3356
+ function resolveSkillsConfig(options, declared) {
3357
+ if (options === void 0) {
3358
+ return void 0;
3359
+ }
3360
+ const providers = options.provider === void 0 ? [
3361
+ declaredSkillProvider(declared)
3362
+ ] : [
3363
+ options.provider,
3364
+ declaredSkillProvider(declared)
3365
+ ];
3366
+ return {
3367
+ provider: providers.length === 1 ? providers[0] : (0, import_nestjs_agent_core22.compositeSkillProvider)(providers),
3368
+ ...options.scopes !== void 0 ? {
3369
+ scopes: options.scopes
3370
+ } : {},
3371
+ ...options.maxSkills !== void 0 ? {
3372
+ maxSkills: options.maxSkills
3373
+ } : {}
3374
+ };
3375
+ }
3376
+ __name(resolveSkillsConfig, "resolveSkillsConfig");
3377
+
2173
3378
  // src/agent.module.ts
2174
- function _ts_decorate17(decorators, target, key, desc) {
3379
+ function _ts_decorate20(decorators, target, key, desc) {
2175
3380
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2176
3381
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2177
3382
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2178
3383
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2179
3384
  }
2180
- __name(_ts_decorate17, "_ts_decorate");
3385
+ __name(_ts_decorate20, "_ts_decorate");
2181
3386
  var DEFAULT_PATH = "agent";
2182
3387
  function sharedProviders(durable, includeStore) {
2183
3388
  const providers = [
2184
3389
  {
2185
- provide: import_nestjs_agent_core17.AGENT_TOOL_REGISTRY,
2186
- useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core17.ToolRegistry(), "useFactory")
3390
+ provide: import_nestjs_agent_core23.AGENT_TOOL_REGISTRY,
3391
+ useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core23.ToolRegistry(), "useFactory")
2187
3392
  },
2188
3393
  // Starts empty; AgentDiscoveryService populates it from `@Agent`-decorated providers at boot.
2189
3394
  {
2190
- provide: import_nestjs_agent_core17.AGENT_REGISTRY,
2191
- useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core17.AgentRegistry(), "useFactory")
3395
+ provide: import_nestjs_agent_core23.AGENT_REGISTRY,
3396
+ useFactory: /* @__PURE__ */ __name(() => new import_nestjs_agent_core23.AgentRegistry(), "useFactory")
2192
3397
  },
2193
3398
  // A shared, mutable list AgentDiscoveryService fills with `@SystemPromptContributor()` methods.
2194
3399
  {
2195
- provide: import_nestjs_agent_core17.AGENT_PROMPT_CONTRIBUTORS,
3400
+ provide: import_nestjs_agent_core23.AGENT_PROMPT_CONTRIBUTORS,
3401
+ useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
3402
+ },
3403
+ // Likewise for `@Skill`-decorated providers — filled by SkillDiscoveryService at onModuleInit,
3404
+ // read lazily by the AGENT_SKILLS provider below (which DI builds before discovery has run).
3405
+ {
3406
+ provide: import_nestjs_agent_core23.AGENT_SKILL_SOURCES,
2196
3407
  useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
2197
3408
  },
2198
3409
  {
2199
- provide: import_nestjs_agent_core17.AGENT_SINK,
3410
+ // One resolution, shared by the loop's deps and the listing endpoint: a second one would
3411
+ // drift, and a user would be offered a skill the agent cannot reach. `undefined` when the
3412
+ // host configured none — which is what keeps the turn's checkpoint sequence unchanged.
3413
+ provide: import_nestjs_agent_core23.AGENT_SKILLS,
3414
+ useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
3415
+ inject: [
3416
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3417
+ import_nestjs_agent_core23.AGENT_SKILL_SOURCES
3418
+ ]
3419
+ },
3420
+ {
3421
+ // One resolution, shared by the loop's deps and the read-back endpoint: a person has to be
3422
+ // shown what the model was shown, and two resolutions would eventually disagree about that.
3423
+ provide: import_nestjs_agent_core23.AGENT_MEMORY,
3424
+ useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
3425
+ inject: [
3426
+ import_nestjs_agent_core23.AGENT_OPTIONS
3427
+ ]
3428
+ },
3429
+ {
3430
+ provide: import_nestjs_agent_core23.AGENT_SINK,
2200
3431
  useFactory: /* @__PURE__ */ __name((options) => options.sink ?? new InProcessTokenStreamSink(), "useFactory"),
2201
3432
  inject: [
2202
- import_nestjs_agent_core17.AGENT_OPTIONS
3433
+ import_nestjs_agent_core23.AGENT_OPTIONS
2203
3434
  ]
2204
3435
  },
2205
3436
  {
2206
- provide: import_nestjs_agent_core17.AGENT_ROLES_POLICY,
2207
- useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new import_nestjs_agent_core17.DefaultRolesPolicy(options.defaultRoles), "useFactory"),
3437
+ provide: import_nestjs_agent_core23.AGENT_ROLES_POLICY,
3438
+ useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new import_nestjs_agent_core23.DefaultRolesPolicy(options.defaultRoles), "useFactory"),
2208
3439
  inject: [
2209
- import_nestjs_agent_core17.AGENT_OPTIONS
3440
+ import_nestjs_agent_core23.AGENT_OPTIONS
2210
3441
  ]
2211
3442
  },
2212
3443
  {
2213
- provide: import_nestjs_agent_core17.AGENT_ACTOR_RESOLVER,
3444
+ provide: import_nestjs_agent_core23.AGENT_ACTOR_RESOLVER,
2214
3445
  useFactory: /* @__PURE__ */ __name((options) => options.actorResolver, "useFactory"),
2215
3446
  inject: [
2216
- import_nestjs_agent_core17.AGENT_OPTIONS
3447
+ import_nestjs_agent_core23.AGENT_OPTIONS
2217
3448
  ]
2218
3449
  },
2219
3450
  {
2220
- provide: import_nestjs_agent_core17.AGENT_MODEL,
3451
+ provide: import_nestjs_agent_core23.AGENT_MODEL,
2221
3452
  useFactory: /* @__PURE__ */ __name((o) => o.model, "useFactory"),
2222
3453
  inject: [
2223
- import_nestjs_agent_core17.AGENT_OPTIONS
3454
+ import_nestjs_agent_core23.AGENT_OPTIONS
2224
3455
  ]
2225
3456
  },
2226
3457
  {
2227
3458
  // An explicit `quota` wins; otherwise `quotaLimitTokens` binds the built-in ledger-backed
2228
3459
  // store; otherwise quotas are off (undefined). The ledger store reads the same usage rows
2229
3460
  // the loop already writes, so enforcement needs no extra shared state across replicas.
2230
- provide: import_nestjs_agent_core17.AGENT_QUOTA_STORE,
3461
+ provide: import_nestjs_agent_core23.AGENT_QUOTA_STORE,
2231
3462
  useFactory: /* @__PURE__ */ __name((o, store) => o.quota ?? (o.quotaLimitTokens !== void 0 ? new LedgerQuotaStore(store, o.quotaLimitTokens) : void 0), "useFactory"),
2232
3463
  inject: [
2233
- import_nestjs_agent_core17.AGENT_OPTIONS,
2234
- import_nestjs_agent_core17.AGENT_STORE
3464
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3465
+ import_nestjs_agent_core23.AGENT_STORE
2235
3466
  ]
2236
3467
  },
2237
3468
  AgentDepsFactory2,
2238
3469
  {
2239
- provide: import_nestjs_agent_core17.AGENT_DEPS_FACTORY,
3470
+ provide: import_nestjs_agent_core23.AGENT_DEPS_FACTORY,
2240
3471
  useExisting: AgentDepsFactory2
2241
3472
  },
2242
3473
  // Populates the registry + contributors (onModuleInit) BEFORE AiToolDiscoveryService synthesizes
2243
3474
  // handoff tools (onApplicationBootstrap) reads the registry.
2244
3475
  AgentDiscoveryService,
2245
3476
  AiToolDiscoveryService,
3477
+ SkillDiscoveryService,
2246
3478
  InlineAgentRunner,
2247
3479
  AgentService,
2248
3480
  // Bound ALWAYS (durable or inline) — the console's cross-thread approvals inbox routes decisions
2249
3481
  // through AgentService.signalToolCall, which reaches whichever AGENT_RUNNER is bound above.
2250
3482
  AgentApprovalPortAdapter,
2251
3483
  {
2252
- provide: import_nestjs_agent_core17.AGENT_APPROVAL_PORT,
3484
+ provide: import_nestjs_agent_core23.AGENT_APPROVAL_PORT,
2253
3485
  useExisting: AgentApprovalPortAdapter
2254
3486
  }
2255
3487
  ];
2256
3488
  if (includeStore) {
2257
3489
  providers.push({
2258
- provide: import_nestjs_agent_core17.AGENT_STORE,
3490
+ provide: import_nestjs_agent_core23.AGENT_STORE,
2259
3491
  useFactory: /* @__PURE__ */ __name((o) => o.store, "useFactory"),
2260
3492
  inject: [
2261
- import_nestjs_agent_core17.AGENT_OPTIONS
3493
+ import_nestjs_agent_core23.AGENT_OPTIONS
2262
3494
  ]
2263
3495
  });
2264
3496
  }
2265
3497
  if (durable) {
2266
3498
  providers.push({
2267
- provide: import_nestjs_agent_core17.AGENT_RUNNER,
3499
+ provide: import_nestjs_agent_core23.AGENT_RUNNER,
2268
3500
  useFactory: /* @__PURE__ */ __name((durableRunner) => {
2269
3501
  if (durableRunner === void 0) {
2270
3502
  throw new Error("AgentModule.forRoot({ durable: true }) requires importing AgentDurableModule from '@dudousxd/nestjs-agent/durable' (alongside a configured DurableModule). It was not found.");
@@ -2273,14 +3505,14 @@ function sharedProviders(durable, includeStore) {
2273
3505
  }, "useFactory"),
2274
3506
  inject: [
2275
3507
  {
2276
- token: import_nestjs_agent_core17.AGENT_DURABLE_RUNNER,
3508
+ token: import_nestjs_agent_core23.AGENT_DURABLE_RUNNER,
2277
3509
  optional: true
2278
3510
  }
2279
3511
  ]
2280
3512
  });
2281
3513
  } else {
2282
3514
  providers.push({
2283
- provide: import_nestjs_agent_core17.AGENT_RUNNER,
3515
+ provide: import_nestjs_agent_core23.AGENT_RUNNER,
2284
3516
  useExisting: InlineAgentRunner
2285
3517
  });
2286
3518
  }
@@ -2289,23 +3521,25 @@ function sharedProviders(durable, includeStore) {
2289
3521
  __name(sharedProviders, "sharedProviders");
2290
3522
  function exportsFor(includeStore) {
2291
3523
  return [
2292
- import_nestjs_agent_core17.AGENT_OPTIONS,
2293
- import_nestjs_agent_core17.AGENT_TOOL_REGISTRY,
2294
- import_nestjs_agent_core17.AGENT_REGISTRY,
2295
- import_nestjs_agent_core17.AGENT_SINK,
2296
- import_nestjs_agent_core17.AGENT_ROLES_POLICY,
2297
- import_nestjs_agent_core17.AGENT_ACTOR_RESOLVER,
2298
- import_nestjs_agent_core17.AGENT_MODEL,
3524
+ import_nestjs_agent_core23.AGENT_OPTIONS,
3525
+ import_nestjs_agent_core23.AGENT_TOOL_REGISTRY,
3526
+ import_nestjs_agent_core23.AGENT_REGISTRY,
3527
+ import_nestjs_agent_core23.AGENT_SINK,
3528
+ import_nestjs_agent_core23.AGENT_ROLES_POLICY,
3529
+ import_nestjs_agent_core23.AGENT_ACTOR_RESOLVER,
3530
+ import_nestjs_agent_core23.AGENT_MODEL,
2299
3531
  ...includeStore ? [
2300
- import_nestjs_agent_core17.AGENT_STORE
3532
+ import_nestjs_agent_core23.AGENT_STORE
2301
3533
  ] : [],
2302
- import_nestjs_agent_core17.AGENT_QUOTA_STORE,
2303
- import_nestjs_agent_core17.AGENT_PROMPT_CONTRIBUTORS,
2304
- import_nestjs_agent_core17.AGENT_DEPS_FACTORY,
3534
+ import_nestjs_agent_core23.AGENT_QUOTA_STORE,
3535
+ import_nestjs_agent_core23.AGENT_PROMPT_CONTRIBUTORS,
3536
+ import_nestjs_agent_core23.AGENT_SKILLS,
3537
+ import_nestjs_agent_core23.AGENT_MEMORY,
3538
+ import_nestjs_agent_core23.AGENT_DEPS_FACTORY,
2305
3539
  AgentDepsFactory2,
2306
3540
  AgentService,
2307
3541
  InlineAgentRunner,
2308
- import_nestjs_agent_core17.AGENT_APPROVAL_PORT
3542
+ import_nestjs_agent_core23.AGENT_APPROVAL_PORT
2309
3543
  ];
2310
3544
  }
2311
3545
  __name(exportsFor, "exportsFor");
@@ -2314,7 +3548,9 @@ var BASE_CONTROLLERS = [
2314
3548
  ThreadsController,
2315
3549
  ToolCallController,
2316
3550
  QuotaController,
2317
- AgentsController
3551
+ AgentsController,
3552
+ SkillsController,
3553
+ MemoriesController
2318
3554
  ];
2319
3555
  var GUARDABLE_CONTROLLERS = [
2320
3556
  ...BASE_CONTROLLERS,
@@ -2346,7 +3582,7 @@ function guardProviders(guards) {
2346
3582
  }
2347
3583
  __name(guardProviders, "guardProviders");
2348
3584
  function routerFor(path) {
2349
- return import_core3.RouterModule.register([
3585
+ return import_core4.RouterModule.register([
2350
3586
  {
2351
3587
  path,
2352
3588
  module: AgentModule
@@ -2373,13 +3609,13 @@ var AgentModule = class _AgentModule {
2373
3609
  module: _AgentModule,
2374
3610
  global: true,
2375
3611
  imports: [
2376
- import_core3.DiscoveryModule,
3612
+ import_core4.DiscoveryModule,
2377
3613
  routerFor(path)
2378
3614
  ],
2379
3615
  controllers: controllersForSurface(options.surface, options.attachments?.upload === true),
2380
3616
  providers: [
2381
3617
  {
2382
- provide: import_nestjs_agent_core17.AGENT_OPTIONS,
3618
+ provide: import_nestjs_agent_core23.AGENT_OPTIONS,
2383
3619
  useValue: options
2384
3620
  },
2385
3621
  ...sharedProviders(options.durable ?? false, includeStore),
@@ -2397,14 +3633,14 @@ var AgentModule = class _AgentModule {
2397
3633
  module: _AgentModule,
2398
3634
  global: true,
2399
3635
  imports: [
2400
- import_core3.DiscoveryModule,
3636
+ import_core4.DiscoveryModule,
2401
3637
  routerFor(path),
2402
3638
  ...options.imports ?? []
2403
3639
  ],
2404
3640
  controllers: controllersForSurface(options.surface, options.attachmentsUpload === true),
2405
3641
  providers: [
2406
3642
  {
2407
- provide: import_nestjs_agent_core17.AGENT_OPTIONS,
3643
+ provide: import_nestjs_agent_core23.AGENT_OPTIONS,
2408
3644
  // Stamp the STATIC wiring flags onto the factory result: `durable`/`dispatchedSteps`/
2409
3645
  // `surface` are authoritative on the async config object (they decided the actual wiring
2410
3646
  // above), and `AgentDurableModule` derives the effective dispatched-steps value from
@@ -2429,9 +3665,9 @@ var AgentModule = class _AgentModule {
2429
3665
  };
2430
3666
  }
2431
3667
  };
2432
- AgentModule = _ts_decorate17([
2433
- (0, import_common17.Global)(),
2434
- (0, import_common17.Module)({})
3668
+ AgentModule = _ts_decorate20([
3669
+ (0, import_common20.Global)(),
3670
+ (0, import_common20.Module)({})
2435
3671
  ], AgentModule);
2436
3672
 
2437
3673
  // src/durable/agent-durable.ts