@dudousxd/nestjs-agent 1.33.0 → 1.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, BufferedModelTurnResult, ToolStepEnvelope, AgentRunner, TokenStreamSink, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
2
2
  import { WorkflowService } from '@dudousxd/nestjs-durable';
3
3
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
4
- import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-QIuTS-5c.cjs';
4
+ import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-CF2fcJDx.cjs';
5
5
  import { DynamicModule } from '@nestjs/common';
6
6
  import '@dudousxd/nestjs-agent-core/genui';
7
7
  import '@standard-schema/spec';
@@ -1,7 +1,7 @@
1
1
  import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, BufferedModelTurnResult, ToolStepEnvelope, AgentRunner, TokenStreamSink, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
2
2
  import { WorkflowService } from '@dudousxd/nestjs-durable';
3
3
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
4
- import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-wNWaoUN8.js';
4
+ import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-CzXsKVb1.js';
5
5
  import { DynamicModule } from '@nestjs/common';
6
6
  import '@dudousxd/nestjs-agent-core/genui';
7
7
  import '@standard-schema/spec';
@@ -102,7 +102,7 @@ var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-q
102
102
  // src/durable/agent-run.steps.ts
103
103
  import { createNegotiatedUiCollector } from "@dudousxd/nestjs-agent-core";
104
104
  import { prepareActionProposal, resolveActionProposalApproval } from "@dudousxd/nestjs-agent-core";
105
- import { AGENT_DEPS_FACTORY, createFrameBuffer, createNoopEmitUi, encodeStreamEvent, intersectAllowLists, invokeWithTransientRetry, isControlFlowSignal, isReplayIntegrityError, observeTurnFrames, previewToolInputs, publishAgentToolRetry, registryInputPreviews, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withChannelDelivery, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolPreflightDenied, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
105
+ import { AGENT_DEPS_FACTORY, announcedToolCalls, createFrameBuffer, createNoopEmitUi, encodeStreamEvent, intersectAllowLists, invokeWithTransientRetry, isControlFlowSignal, isReplayIntegrityError, observeTurnFrames, previewToolInputs, publishAgentToolRetry, registryInputPreviews, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withChannelDelivery, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolPreflightDenied, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
106
106
  import { turnChannel } from "@dudousxd/nestjs-agent-core/genui";
107
107
  import { Step } from "@dudousxd/nestjs-durable";
108
108
  import { Inject, Injectable } from "@nestjs/common";
@@ -188,9 +188,9 @@ var AgentRunSteps = class {
188
188
  ),
189
189
  ask: deps.ask
190
190
  }),
191
- enabled: deps.skills !== void 0
191
+ enabled: deps.skills !== void 0 && input.builtins?.skills !== false
192
192
  }),
193
- enabled: deps.memory?.provider.write !== void 0
193
+ enabled: deps.memory?.provider.write !== void 0 && input.builtins?.memory !== false
194
194
  });
195
195
  const buffer = input.bufferOutput === true ? createFrameBuffer() : void 0;
196
196
  let writer;
@@ -200,7 +200,8 @@ var AgentRunSteps = class {
200
200
  const opened = await deps.sink.open(input.sinkRunId);
201
201
  writer = input.childSink ? childSinkWriter(opened) : opened;
202
202
  }
203
- const previews = previewToolInputs(writer, registryInputPreviews(deps.registry, tools, {
203
+ const announced = announcedToolCalls(writer);
204
+ const previews = previewToolInputs(announced.writer, registryInputPreviews(deps.registry, tools, {
204
205
  actor: input.actor,
205
206
  ...input.threadId !== void 0 ? {
206
207
  threadId: input.threadId
@@ -224,6 +225,7 @@ var AgentRunSteps = class {
224
225
  } : {}
225
226
  })), frames.summary());
226
227
  const stamped = stampToolKinds(turn, deps);
228
+ await announced.announceRest(stamped.toolCalls, tools);
227
229
  const allowedTools = intersectAllowLists(deps.toolAllowList, input.personaAllowedTools);
228
230
  for (const call of stamped.toolCalls) {
229
231
  if (call.kind !== "action") continue;
@@ -1259,7 +1261,7 @@ AgentDurableModule = _ts_decorate4([
1259
1261
  ], AgentDurableModule);
1260
1262
 
1261
1263
  // src/agent.module.ts
1262
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER14, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY9, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL3, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS10, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK4, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE9, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
1264
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER14, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY9, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL3, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS10, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK4, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE9, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3, personalAgentGate, personalAgentScopes } from "@dudousxd/nestjs-agent-core";
1263
1265
  import { Global as Global2, Logger as Logger10, Module as Module3 } from "@nestjs/common";
1264
1266
  import { DiscoveryModule, ModulesContainer, RouterModule } from "@nestjs/core";
1265
1267
 
@@ -6027,9 +6029,19 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
6027
6029
  this.logger.warn(`Agent "${meta.name}" hands off to ${target.name}, which is not an @Agent \u2014 skipped.`);
6028
6030
  continue;
6029
6031
  }
6030
- edges.push(detached ? {
6032
+ const roles = typeof entry === "function" ? void 0 : entry.roles;
6033
+ const ability = typeof entry === "function" ? void 0 : entry.ability;
6034
+ edges.push(detached || roles !== void 0 || ability !== void 0 ? {
6031
6035
  agent: targetMeta.name,
6032
- detached: true
6036
+ ...detached ? {
6037
+ detached: true
6038
+ } : {},
6039
+ ...roles !== void 0 ? {
6040
+ roles
6041
+ } : {},
6042
+ ...ability !== void 0 ? {
6043
+ ability
6044
+ } : {}
6033
6045
  } : targetMeta.name);
6034
6046
  }
6035
6047
  return edges;
@@ -6221,7 +6233,7 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
6221
6233
  let delegates = 0;
6222
6234
  for (const definition of this.agents.list()) {
6223
6235
  for (const edge of definition.delegatesTo ?? []) {
6224
- const { agent: target, detached } = normalizeDelegation2(edge);
6236
+ const { agent: target, detached, roles, ability } = normalizeDelegation2(edge);
6225
6237
  const targetDefinition = this.agents.get(target);
6226
6238
  if (targetDefinition === void 0) {
6227
6239
  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.`);
@@ -6243,6 +6255,12 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
6243
6255
  ...detached ? {
6244
6256
  detached: true
6245
6257
  } : {},
6258
+ ...roles !== void 0 ? {
6259
+ roles
6260
+ } : {},
6261
+ ...ability !== void 0 ? {
6262
+ ability
6263
+ } : {},
6246
6264
  description,
6247
6265
  inputSchema: z.object({
6248
6266
  task: z.string()
@@ -6581,6 +6599,35 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
6581
6599
  worker;
6582
6600
  logger = new Logger8(_ActionProposalWorkerService.name);
6583
6601
  settledListeners = /* @__PURE__ */ new Set();
6602
+ admittedListeners = /* @__PURE__ */ new Set();
6603
+ /**
6604
+ * Run `listener` once a settled proposal's outcome is written to its thread by this process's
6605
+ * worker (the thread was free) — what a module uses to CONTINUE a conversation once an action it
6606
+ * proposed ran (a Poppy connect: the next turn goes on with what was asked). Next to
6607
+ * `actionProposalWorker.onAdmitted`; a listener that throws is logged and does not stop the
6608
+ * others. Returns the unsubscribe.
6609
+ */
6610
+ onAdmitted(listener) {
6611
+ this.admittedListeners.add(listener);
6612
+ return () => {
6613
+ this.admittedListeners.delete(listener);
6614
+ };
6615
+ }
6616
+ async admitted(outcome) {
6617
+ const configured = this.options.actionProposalWorker?.onAdmitted;
6618
+ for (const listener of [
6619
+ ...configured ? [
6620
+ configured
6621
+ ] : [],
6622
+ ...this.admittedListeners
6623
+ ]) {
6624
+ try {
6625
+ await listener(outcome);
6626
+ } catch (error) {
6627
+ this.logger.error(error);
6628
+ }
6629
+ }
6630
+ }
6584
6631
  /**
6585
6632
  * Run `listener` after every proposal this process's worker settles — how a module relays an
6586
6633
  * outcome somewhere the turn's stream no longer reaches (a text channel's conversation). Next to
@@ -6624,6 +6671,7 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
6624
6671
  workerId: randomUUID2(),
6625
6672
  ...this.options.actionProposalWorker,
6626
6673
  onSettled: /* @__PURE__ */ __name((proposal) => this.settled(proposal), "onSettled"),
6674
+ onAdmitted: /* @__PURE__ */ __name((outcome) => this.admitted(outcome), "onAdmitted"),
6627
6675
  executor: new ActionProposalExecutor({
6628
6676
  resolver,
6629
6677
  resolveExecution: /* @__PURE__ */ __name(async (proposal, actor) => {
@@ -7439,6 +7487,13 @@ function forwardingPolicy(wrapper) {
7439
7487
  throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
7440
7488
  }
7441
7489
  return policy.can(actor, tool);
7490
+ },
7491
+ canOffer(actor, tool) {
7492
+ const policy = wrapper.instance;
7493
+ if (policy === void 0 || policy === null) {
7494
+ throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
7495
+ }
7496
+ return policy.canOffer ? policy.canOffer(actor, tool) : policy.can(actor, tool);
7442
7497
  }
7443
7498
  };
7444
7499
  }
@@ -7480,7 +7535,14 @@ function sharedProviders(durable, engine) {
7480
7535
  // drift, and a user would be offered a skill the agent cannot reach. `undefined` when the
7481
7536
  // host configured none — which is what keeps the turn's checkpoint sequence unchanged.
7482
7537
  provide: AGENT_SKILLS3,
7483
- useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
7538
+ // Personal agents resolve no skill scope (`personalAgentScopes`): nothing of the app's to load.
7539
+ useFactory: /* @__PURE__ */ __name((options, declared) => {
7540
+ const skills = resolveSkillsConfig(options.skills, declared);
7541
+ return skills === void 0 ? void 0 : {
7542
+ ...skills,
7543
+ scopes: personalAgentScopes(skills.scopes)
7544
+ };
7545
+ }, "useFactory"),
7484
7546
  inject: [
7485
7547
  AGENT_OPTIONS10,
7486
7548
  AGENT_SKILL_SOURCES2
@@ -7490,7 +7552,12 @@ function sharedProviders(durable, engine) {
7490
7552
  // One resolution, shared by the loop's deps and the read-back endpoint: a person has to be
7491
7553
  // shown what the model was shown, and two resolutions would eventually disagree about that.
7492
7554
  provide: AGENT_MEMORY3,
7493
- useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
7555
+ // Personal agents resolve no memory scope (`personalAgentScopes`): under a signed-in Poppy
7556
+ // conversation the actor is the account, and it must neither read nor write its memories.
7557
+ useFactory: /* @__PURE__ */ __name((options) => options.memory === void 0 ? void 0 : {
7558
+ ...options.memory,
7559
+ scopes: personalAgentScopes(options.memory.scopes)
7560
+ }, "useFactory"),
7494
7561
  inject: [
7495
7562
  AGENT_OPTIONS10
7496
7563
  ]
@@ -7504,7 +7571,10 @@ function sharedProviders(durable, engine) {
7504
7571
  },
7505
7572
  {
7506
7573
  provide: AGENT_ROLES_POLICY2,
7507
- useFactory: /* @__PURE__ */ __name((options, modules) => resolveRolesPolicy(options, modules), "useFactory"),
7574
+ // Personal agents (a Poppy conversation, a Poppy session's MCP token) reach only the tools
7575
+ // written for them, and run only those of the scopes their user granted. A no-op for every
7576
+ // other actor.
7577
+ useFactory: /* @__PURE__ */ __name((options, modules) => personalAgentGate(resolveRolesPolicy(options, modules)), "useFactory"),
7508
7578
  inject: [
7509
7579
  AGENT_OPTIONS10,
7510
7580
  ModulesContainer