@dudousxd/nestjs-agent 1.17.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  AGENT_TOOL_BRAND: () => AGENT_TOOL_BRAND,
28
28
  AI_TOOL_METADATA: () => AI_TOOL_METADATA,
29
29
  ATTACHMENT_PAGE_SIZE: () => ATTACHMENT_PAGE_SIZE,
30
+ AgUiRunHandler: () => AgUiRunHandler,
30
31
  Agent: () => Agent,
31
32
  AgentApprovalPortAdapter: () => AgentApprovalPortAdapter,
32
33
  AgentDepsFactory: () => AgentDepsFactory2,
@@ -60,6 +61,7 @@ __export(index_exports, {
60
61
  SystemPrompt: () => SystemPrompt,
61
62
  SystemPromptContributor: () => SystemPromptContributor,
62
63
  ToolsController: () => ToolsController,
64
+ agUiAdapter: () => agUiAdapter,
63
65
  attachmentLimits: () => attachmentLimits,
64
66
  declaredSkillProvider: () => declaredSkillProvider,
65
67
  defaultRequestUserMapper: () => defaultRequestUserMapper,
@@ -1026,6 +1028,9 @@ var AgentService = class {
1026
1028
  actor: params.actor,
1027
1029
  ...params.transient === true ? {
1028
1030
  transient: true
1031
+ } : {},
1032
+ ...params.newThreadId !== void 0 ? {
1033
+ id: params.newThreadId
1029
1034
  } : {}
1030
1035
  });
1031
1036
  threadId = created.id;
@@ -1450,6 +1455,38 @@ var AgentService = class {
1450
1455
  });
1451
1456
  throw new RunNotActiveException(runId);
1452
1457
  }
1458
+ /** Who owns the thread, or `null` when there is no such (live) thread. */
1459
+ async threadOwner(threadId) {
1460
+ return this.store.ownerOfThread(threadId);
1461
+ }
1462
+ /**
1463
+ * May `actor` continue the run whose stream is `runId` — the AG-UI resume? Only the actor whose
1464
+ * thread is streaming it (`403` otherwise), and only while it still is: a run that is over is
1465
+ * waiting on no one (`409 run_not_active`), whatever an old interrupt id says.
1466
+ */
1467
+ async assertResumable(actor, runId) {
1468
+ const owner = await this.store.ownerOfActiveStream(runId);
1469
+ if (owner === null) {
1470
+ throw new RunNotActiveException(runId);
1471
+ }
1472
+ if (owner !== actor.id) {
1473
+ throw new import_common4.ForbiddenException("run belongs to another actor");
1474
+ }
1475
+ }
1476
+ /**
1477
+ * Everything {@link approve} / {@link reject} check before they signal — who may decide, and
1478
+ * that the request has not lapsed — without signalling. For a caller that settles several
1479
+ * decisions at once and must refuse all of them if one is refused (an AG-UI resume).
1480
+ */
1481
+ async checkDecision(actor, toolCallId2) {
1482
+ await this.assertMayDecide(actor, toolCallId2);
1483
+ await this.assertNotExpired(toolCallId2);
1484
+ }
1485
+ /** Everything {@link answer} checks before it signals, without signalling — see {@link checkDecision}. */
1486
+ async checkAnswer(actor, toolCallId2, answers2) {
1487
+ await this.assertOwnsToolCall(actor, toolCallId2);
1488
+ await this.assertAnswersFit(toolCallId2, answers2);
1489
+ }
1453
1490
  async cancel(actor, runId) {
1454
1491
  await this.assertOwnsActiveStream(actor, runId);
1455
1492
  return this.runner.cancel(runId);
@@ -4996,7 +5033,7 @@ function sharedProviders(durable) {
4996
5033
  },
4997
5034
  {
4998
5035
  provide: import_nestjs_agent_core27.AGENT_ROLES_POLICY,
4999
- useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? new import_nestjs_agent_core27.DefaultRolesPolicy(options.defaultRoles), "useFactory"),
5036
+ useFactory: /* @__PURE__ */ __name((options) => options.rolesPolicy ?? (options.emptyRoles === "deny" ? new import_nestjs_agent_core27.ClosedRolesPolicy(options.defaultRoles) : new import_nestjs_agent_core27.DefaultRolesPolicy(options.defaultRoles)), "useFactory"),
5000
5037
  inject: [
5001
5038
  import_nestjs_agent_core27.AGENT_OPTIONS
5002
5039
  ]
@@ -5138,15 +5175,28 @@ var BASE_CONTROLLERS = [
5138
5175
  ConfigController,
5139
5176
  AttachmentsController
5140
5177
  ];
5141
- var GUARDABLE_CONTROLLERS = BASE_CONTROLLERS;
5142
- function controllersForSurface(surface) {
5143
- return surface === "engine" ? [] : BASE_CONTROLLERS;
5178
+ function adapterControllers(adapters) {
5179
+ return (adapters ?? []).flatMap((adapter) => adapter.controllers);
5180
+ }
5181
+ __name(adapterControllers, "adapterControllers");
5182
+ function adapterProviders(adapters) {
5183
+ return (adapters ?? []).flatMap((adapter) => adapter.providers ?? []);
5184
+ }
5185
+ __name(adapterProviders, "adapterProviders");
5186
+ function controllersForSurface(surface, adapters) {
5187
+ return surface === "engine" ? [] : [
5188
+ ...BASE_CONTROLLERS,
5189
+ ...adapterControllers(adapters)
5190
+ ];
5144
5191
  }
5145
5192
  __name(controllersForSurface, "controllersForSurface");
5146
5193
  var GUARDS_METADATA = "__guards__";
5147
- function applyGuards(guards) {
5194
+ function applyGuards(guards, adapters) {
5148
5195
  const resolved = guards ?? [];
5149
- for (const controller of GUARDABLE_CONTROLLERS) {
5196
+ for (const controller of [
5197
+ ...BASE_CONTROLLERS,
5198
+ ...adapterControllers(adapters)
5199
+ ]) {
5150
5200
  Reflect.defineMetadata(GUARDS_METADATA, resolved, controller);
5151
5201
  }
5152
5202
  }
@@ -5172,7 +5222,7 @@ var AgentModule = class _AgentModule {
5172
5222
  }
5173
5223
  static forRoot(options) {
5174
5224
  const path = options.path ?? DEFAULT_PATH;
5175
- applyGuards(options.guards);
5225
+ applyGuards(options.guards, options.adapters);
5176
5226
  return {
5177
5227
  module: _AgentModule,
5178
5228
  global: true,
@@ -5180,21 +5230,22 @@ var AgentModule = class _AgentModule {
5180
5230
  import_core4.DiscoveryModule,
5181
5231
  routerFor(path)
5182
5232
  ],
5183
- controllers: controllersForSurface(options.surface),
5233
+ controllers: controllersForSurface(options.surface, options.adapters),
5184
5234
  providers: [
5185
5235
  {
5186
5236
  provide: import_nestjs_agent_core27.AGENT_OPTIONS,
5187
5237
  useValue: options
5188
5238
  },
5189
5239
  ...sharedProviders(options.durable ?? false),
5190
- ...guardProviders(options.guards)
5240
+ ...guardProviders(options.guards),
5241
+ ...adapterProviders(options.adapters)
5191
5242
  ],
5192
5243
  exports: exportsFor()
5193
5244
  };
5194
5245
  }
5195
5246
  static forRootAsync(options) {
5196
5247
  const path = options.path ?? DEFAULT_PATH;
5197
- applyGuards(options.guards);
5248
+ applyGuards(options.guards, options.adapters);
5198
5249
  return {
5199
5250
  module: _AgentModule,
5200
5251
  global: true,
@@ -5203,7 +5254,7 @@ var AgentModule = class _AgentModule {
5203
5254
  routerFor(path),
5204
5255
  ...options.imports ?? []
5205
5256
  ],
5206
- controllers: controllersForSurface(options.surface),
5257
+ controllers: controllersForSurface(options.surface, options.adapters),
5207
5258
  providers: [
5208
5259
  {
5209
5260
  provide: import_nestjs_agent_core27.AGENT_OPTIONS,
@@ -5221,7 +5272,8 @@ var AgentModule = class _AgentModule {
5221
5272
  inject: options.inject ?? []
5222
5273
  },
5223
5274
  ...sharedProviders(options.durable ?? false),
5224
- ...guardProviders(options.guards)
5275
+ ...guardProviders(options.guards),
5276
+ ...adapterProviders(options.adapters)
5225
5277
  ],
5226
5278
  exports: exportsFor()
5227
5279
  };
@@ -5232,8 +5284,328 @@ AgentModule = _ts_decorate22([
5232
5284
  (0, import_common23.Module)({})
5233
5285
  ], AgentModule);
5234
5286
 
5235
- // src/resolver/header-actor-resolver.ts
5287
+ // src/ag-ui/ag-ui.adapter.ts
5288
+ var import_nestjs_agent_core28 = require("@dudousxd/nestjs-agent-core");
5289
+ var import_ag_ui = require("@dudousxd/nestjs-agent-core/ag-ui");
5236
5290
  var import_common24 = require("@nestjs/common");
5291
+ function _ts_decorate23(decorators, target, key, desc) {
5292
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
5293
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
5294
+ r = Reflect.decorate(decorators, target, key, desc);
5295
+ } else {
5296
+ for (var i = decorators.length - 1; i >= 0; i--) {
5297
+ if (d = decorators[i]) {
5298
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5299
+ }
5300
+ }
5301
+ }
5302
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
5303
+ }
5304
+ __name(_ts_decorate23, "_ts_decorate");
5305
+ function _ts_metadata22(metadataKey, metadataValue) {
5306
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
5307
+ return Reflect.metadata(metadataKey, metadataValue);
5308
+ }
5309
+ }
5310
+ __name(_ts_metadata22, "_ts_metadata");
5311
+ function _ts_param21(paramIndex, decorator) {
5312
+ return function(target, key) {
5313
+ decorator(target, key, paramIndex);
5314
+ };
5315
+ }
5316
+ __name(_ts_param21, "_ts_param");
5317
+ var AG_UI_VIA = "ag-ui";
5318
+ function invalid(code, message) {
5319
+ return new import_common24.BadRequestException({
5320
+ statusCode: 400,
5321
+ code,
5322
+ message
5323
+ });
5324
+ }
5325
+ __name(invalid, "invalid");
5326
+ function warningEvents(warnings) {
5327
+ return warnings.map((message) => ({
5328
+ type: "CUSTOM",
5329
+ name: import_ag_ui.AG_UI_CUSTOM.warning,
5330
+ value: {
5331
+ message
5332
+ }
5333
+ }));
5334
+ }
5335
+ __name(warningEvents, "warningEvents");
5336
+ var AgUiRunHandler = class {
5337
+ static {
5338
+ __name(this, "AgUiRunHandler");
5339
+ }
5340
+ agent;
5341
+ actorResolver;
5342
+ options;
5343
+ staging;
5344
+ quietMs;
5345
+ constructor(agent, actorResolver, options, staging, quietMs) {
5346
+ this.agent = agent;
5347
+ this.actorResolver = actorResolver;
5348
+ this.options = options;
5349
+ this.staging = staging;
5350
+ this.quietMs = quietMs;
5351
+ }
5352
+ async handle(req, res, body) {
5353
+ const input = (0, import_ag_ui.parseRunInput)(body);
5354
+ if (typeof input === "string") {
5355
+ throw invalid("invalid_input", input);
5356
+ }
5357
+ const forwarded = (0, import_ag_ui.readForwardedProps)(input.forwardedProps);
5358
+ const actor = await this.actorResolver.resolve(req);
5359
+ const warnings = [];
5360
+ if (Array.isArray(input.tools) && input.tools.length > 0) {
5361
+ warnings.push("Frontend tools are not supported by this agent: the tools list was ignored.");
5362
+ }
5363
+ const quiet = this.quietMs !== void 0 ? {
5364
+ quietMs: this.quietMs
5365
+ } : {};
5366
+ if (input.resume !== void 0 && input.resume.length > 0) {
5367
+ const plan = (0, import_ag_ui.planResume)(input.resume);
5368
+ if (typeof plan === "string") {
5369
+ throw invalid("invalid_resume", plan);
5370
+ }
5371
+ for (const id of plan.unrecognised) {
5372
+ warnings.push(`The resume entry ${id} answers an interrupt this agent did not raise.`);
5373
+ }
5374
+ const first = plan.decisions[0];
5375
+ if (first !== void 0) {
5376
+ const streamRunId = first.address.stream;
5377
+ await this.agent.assertResumable(actor, streamRunId);
5378
+ await this.settle(actor, plan.decisions);
5379
+ await this.pipe(res, streamRunId, {
5380
+ threadId: input.threadId,
5381
+ runId: input.runId,
5382
+ streamRunId,
5383
+ skip: first.address.position,
5384
+ answered: plan.decisions.map((decision) => decision.address.toolCallId),
5385
+ ...quiet,
5386
+ preamble: warningEvents(warnings)
5387
+ });
5388
+ return;
5389
+ }
5390
+ }
5391
+ const turn = (0, import_ag_ui.readUserTurn)(input.messages);
5392
+ if (turn === null) {
5393
+ throw invalid("no_user_message", "messages carries no user message to answer");
5394
+ }
5395
+ warnings.push(...turn.dropped);
5396
+ const owner = await this.agent.threadOwner(input.threadId);
5397
+ if (owner !== null && owner !== actor.id) {
5398
+ throw new import_common24.ForbiddenException("thread belongs to another actor");
5399
+ }
5400
+ const refs = await this.stage(actor, turn.media, warnings);
5401
+ if (turn.text.trim().length === 0 && refs.length === 0) {
5402
+ throw invalid("no_user_message", "the user message to answer is empty");
5403
+ }
5404
+ const context = (0, import_ag_ui.readContext)(input.context);
5405
+ const pageContext = forwarded.pageContext !== void 0 || context !== void 0 ? {
5406
+ ...forwarded.pageContext,
5407
+ ...context !== void 0 ? {
5408
+ agUiContext: context
5409
+ } : {}
5410
+ } : void 0;
5411
+ const started = await this.agent.chat({
5412
+ actor,
5413
+ message: turn.text,
5414
+ ...owner !== null ? {
5415
+ threadId: input.threadId
5416
+ } : {
5417
+ newThreadId: input.threadId
5418
+ },
5419
+ ...forwarded.agent !== void 0 ? {
5420
+ agentName: forwarded.agent
5421
+ } : {},
5422
+ ...forwarded.model !== void 0 ? {
5423
+ model: forwarded.model
5424
+ } : {},
5425
+ ...pageContext !== void 0 ? {
5426
+ pageContext
5427
+ } : {},
5428
+ ...refs.length > 0 ? {
5429
+ attachments: refs
5430
+ } : {}
5431
+ });
5432
+ await this.pipe(res, started.runId, {
5433
+ threadId: input.threadId,
5434
+ runId: input.runId,
5435
+ streamRunId: started.runId,
5436
+ streamThreadId: started.threadId,
5437
+ ...quiet,
5438
+ preamble: warningEvents(warnings)
5439
+ });
5440
+ }
5441
+ /** Stage the turn's inline media through the bound store, within its limits; say what was not used. */
5442
+ async stage(actor, media, warnings) {
5443
+ const refs = [];
5444
+ const limits = attachmentLimits(this.options, this.staging);
5445
+ for (const item of media) {
5446
+ const label = `The ${item.kind} "${item.filename}" was not used`;
5447
+ if (this.staging === void 0) {
5448
+ warnings.push(`${label}: attachments are not enabled on this agent.`);
5449
+ } else if (refs.length >= limits.maxPerMessage) {
5450
+ warnings.push(`${label}: a message carries at most ${limits.maxPerMessage} attachments.`);
5451
+ } else if (!limits.allowedContentTypes.includes(item.contentType)) {
5452
+ warnings.push(`${label}: ${item.contentType} is not an accepted type.`);
5453
+ } else if (item.data.length > limits.maxBytes) {
5454
+ warnings.push(`${label}: it is larger than ${limits.maxBytes} bytes.`);
5455
+ } else {
5456
+ try {
5457
+ const staged = await this.staging.stage({
5458
+ data: item.data,
5459
+ filename: item.filename,
5460
+ contentType: item.contentType,
5461
+ sizeBytes: item.data.length,
5462
+ actor
5463
+ });
5464
+ refs.push({
5465
+ mediaId: staged.mediaId
5466
+ });
5467
+ } catch {
5468
+ warnings.push(`${label}: it could not be stored.`);
5469
+ }
5470
+ }
5471
+ }
5472
+ return refs;
5473
+ }
5474
+ /**
5475
+ * Deliver what a resume list decided, through the same calls the native decision routes make.
5476
+ * Everything that can refuse — who may decide, an answer a question's rules reject, a payload that
5477
+ * says nothing — is checked for EVERY entry before the first one is delivered, so a list with one
5478
+ * bad entry settles nothing.
5479
+ */
5480
+ async settle(actor, decisions) {
5481
+ const deliveries = [];
5482
+ for (const { address, entry } of decisions) {
5483
+ const { toolCallId: toolCallId2 } = address;
5484
+ const abandoned = entry.status === "cancelled";
5485
+ if (address.kind === "approval") {
5486
+ await this.agent.checkDecision(actor, toolCallId2);
5487
+ const decision = abandoned ? {
5488
+ approved: false
5489
+ } : (0, import_ag_ui.readApprovalPayload)(entry.payload);
5490
+ if (decision === null) {
5491
+ throw invalid("invalid_resume", "an approval is answered with { approved: boolean, reason?, remember? }");
5492
+ }
5493
+ const reason = rejectReason(decision.reason ?? (abandoned ? "abandoned" : void 0));
5494
+ deliveries.push(() => decision.approved ? this.agent.approve(actor, toolCallId2, {
5495
+ via: AG_UI_VIA,
5496
+ ...decision.remember === true ? {
5497
+ remember: true
5498
+ } : {}
5499
+ }) : this.agent.reject(actor, toolCallId2, reason, {
5500
+ via: AG_UI_VIA
5501
+ }));
5502
+ continue;
5503
+ }
5504
+ if (abandoned) {
5505
+ await this.agent.checkAnswer(actor, toolCallId2, {});
5506
+ deliveries.push(() => this.agent.skip(actor, toolCallId2, {
5507
+ via: AG_UI_VIA
5508
+ }));
5509
+ continue;
5510
+ }
5511
+ const read = (0, import_ag_ui.readAnswersPayload)(entry.payload);
5512
+ if (read === null) {
5513
+ throw invalid("invalid_resume", "a question set is answered with { answers: { <questionId>: string[] } }");
5514
+ }
5515
+ const answers2 = answers(read) ?? {};
5516
+ await this.agent.checkAnswer(actor, toolCallId2, answers2);
5517
+ deliveries.push(() => this.agent.answer(actor, toolCallId2, answers2, {
5518
+ via: AG_UI_VIA
5519
+ }));
5520
+ }
5521
+ for (const deliver of deliveries) await deliver();
5522
+ }
5523
+ /**
5524
+ * Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
5525
+ * to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
5526
+ * and the request that answers re-attaches to it.
5527
+ */
5528
+ async pipe(res, runId, options) {
5529
+ res.status(200);
5530
+ res.setHeader("Content-Type", "text/event-stream");
5531
+ res.setHeader("Cache-Control", "no-cache, no-transform");
5532
+ res.setHeader("Connection", "keep-alive");
5533
+ res.setHeader("X-Accel-Buffering", "no");
5534
+ res.setHeader("X-Agent-Run-Id", runId);
5535
+ res.flushHeaders();
5536
+ let terminal = false;
5537
+ try {
5538
+ const frames = (0, import_ag_ui.agUiFramesFromNdjson)(this.agent.subscribe(runId));
5539
+ for await (const event of (0, import_ag_ui.agUiEvents)(frames, options)) {
5540
+ if (event.type === "RUN_FINISHED" || event.type === "RUN_ERROR") terminal = true;
5541
+ res.write((0, import_ag_ui.agUiSse)(event));
5542
+ }
5543
+ } catch {
5544
+ if (!terminal) {
5545
+ res.write((0, import_ag_ui.agUiSse)({
5546
+ type: "RUN_ERROR",
5547
+ message: "The run could not be followed.",
5548
+ code: "run_failed"
5549
+ }));
5550
+ }
5551
+ }
5552
+ res.end();
5553
+ }
5554
+ };
5555
+ function agUiAdapter(options = {}) {
5556
+ const path = (options.path ?? "ag-ui").replace(/^\/+|\/+$/g, "");
5557
+ const quietMs = options.quietMs;
5558
+ let AgUiController = class AgUiController extends AgUiRunHandler {
5559
+ static {
5560
+ __name(this, "AgUiController");
5561
+ }
5562
+ constructor(agent, actorResolver, moduleOptions, staging) {
5563
+ super(agent, actorResolver, moduleOptions, staging, quietMs);
5564
+ }
5565
+ run(req, res, body) {
5566
+ return this.handle(req, res, body);
5567
+ }
5568
+ };
5569
+ _ts_decorate23([
5570
+ (0, import_common24.Post)(path),
5571
+ (0, import_common24.HttpCode)(200),
5572
+ _ts_param21(0, (0, import_common24.Req)()),
5573
+ _ts_param21(1, (0, import_common24.Res)()),
5574
+ _ts_param21(2, (0, import_common24.Body)()),
5575
+ _ts_metadata22("design:type", Function),
5576
+ _ts_metadata22("design:paramtypes", [
5577
+ typeof Request === "undefined" ? Object : Request,
5578
+ typeof Response === "undefined" ? Object : Response,
5579
+ Object
5580
+ ]),
5581
+ _ts_metadata22("design:returntype", typeof Promise === "undefined" ? Object : Promise)
5582
+ ], AgUiController.prototype, "run", null);
5583
+ AgUiController = _ts_decorate23([
5584
+ (0, import_common24.Controller)(),
5585
+ _ts_param21(0, (0, import_common24.Inject)(AgentService)),
5586
+ _ts_param21(1, (0, import_common24.Inject)(import_nestjs_agent_core28.AGENT_ACTOR_RESOLVER)),
5587
+ _ts_param21(2, (0, import_common24.Inject)(import_nestjs_agent_core28.AGENT_OPTIONS)),
5588
+ _ts_param21(3, (0, import_common24.Optional)()),
5589
+ _ts_param21(3, (0, import_common24.Inject)(import_nestjs_agent_core28.AGENT_ATTACHMENT_STAGING)),
5590
+ _ts_metadata22("design:type", Function),
5591
+ _ts_metadata22("design:paramtypes", [
5592
+ typeof AgentService === "undefined" ? Object : AgentService,
5593
+ typeof ActorResolver === "undefined" ? Object : ActorResolver,
5594
+ typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
5595
+ typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
5596
+ ])
5597
+ ], AgUiController);
5598
+ return {
5599
+ name: "ag-ui",
5600
+ controllers: [
5601
+ AgUiController
5602
+ ]
5603
+ };
5604
+ }
5605
+ __name(agUiAdapter, "agUiAdapter");
5606
+
5607
+ // src/resolver/header-actor-resolver.ts
5608
+ var import_common25 = require("@nestjs/common");
5237
5609
  function readHeader(req, name) {
5238
5610
  if (typeof req !== "object" || req === null || !("headers" in req)) return void 0;
5239
5611
  const { headers } = req;
@@ -5249,7 +5621,7 @@ var HeaderActorResolver = class {
5249
5621
  resolve(req) {
5250
5622
  const id = readHeader(req, "x-actor-id");
5251
5623
  if (id === void 0 || id.length === 0) {
5252
- throw new import_common24.UnauthorizedException("HeaderActorResolver: missing x-actor-id header. No default actor is fabricated. Send x-actor-id from a trusted gateway, or configure AgentModule.forRoot({ actorResolver }) with a resolver that reads your authenticated principal.");
5624
+ throw new import_common25.UnauthorizedException("HeaderActorResolver: missing x-actor-id header. No default actor is fabricated. Send x-actor-id from a trusted gateway, or configure AgentModule.forRoot({ actorResolver }) with a resolver that reads your authenticated principal.");
5253
5625
  }
5254
5626
  const roles = (readHeader(req, "x-actor-role") ?? "").split(",").map((role) => role.trim()).filter((role) => role.length > 0);
5255
5627
  const tenantRef = readHeader(req, "x-tenant-ref");
@@ -5264,7 +5636,7 @@ var HeaderActorResolver = class {
5264
5636
  };
5265
5637
 
5266
5638
  // src/resolver/request-user-actor-resolver.ts
5267
- var import_common25 = require("@nestjs/common");
5639
+ var import_common26 = require("@nestjs/common");
5268
5640
  function field(user, ...names) {
5269
5641
  for (const name of names) {
5270
5642
  const value = user[name];
@@ -5276,7 +5648,7 @@ __name(field, "field");
5276
5648
  function defaultRequestUserMapper(user) {
5277
5649
  const id = field(user, "id", "sub", "_id", "userId");
5278
5650
  if (id === void 0) {
5279
- throw new import_common25.UnauthorizedException("requestUserActorResolver: req.user has no id/sub/_id/userId \u2014 pass a mapper: requestUserActorResolver((user) => ({ id: \u2026, roles: \u2026 }))");
5651
+ throw new import_common26.UnauthorizedException("requestUserActorResolver: req.user has no id/sub/_id/userId \u2014 pass a mapper: requestUserActorResolver((user) => ({ id: \u2026, roles: \u2026 }))");
5280
5652
  }
5281
5653
  const rawRoles = field(user, "roles", "role");
5282
5654
  const roles = Array.isArray(rawRoles) ? rawRoles.map(String) : typeof rawRoles === "string" ? [
@@ -5297,7 +5669,7 @@ function requestUserActorResolver(map) {
5297
5669
  async resolve(req) {
5298
5670
  const user = typeof req === "object" && req !== null ? req.user : void 0;
5299
5671
  if (user === void 0 || user === null || user === false) {
5300
- throw new import_common25.UnauthorizedException("Sign in to use the agent.");
5672
+ throw new import_common26.UnauthorizedException("Sign in to use the agent.");
5301
5673
  }
5302
5674
  if (map !== void 0) return map(user, req);
5303
5675
  return defaultRequestUserMapper(user);
@@ -5315,6 +5687,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
5315
5687
  AGENT_TOOL_BRAND,
5316
5688
  AI_TOOL_METADATA,
5317
5689
  ATTACHMENT_PAGE_SIZE,
5690
+ AgUiRunHandler,
5318
5691
  Agent,
5319
5692
  AgentApprovalPortAdapter,
5320
5693
  AgentDepsFactory,
@@ -5348,6 +5721,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
5348
5721
  SystemPrompt,
5349
5722
  SystemPromptContributor,
5350
5723
  ToolsController,
5724
+ agUiAdapter,
5351
5725
  attachmentLimits,
5352
5726
  declaredSkillProvider,
5353
5727
  defaultRequestUserMapper,