@dudousxd/nestjs-agent 1.17.0 → 1.18.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/{chat-queue.service-Bqq00NN1.d.cts → chat-queue.service-5LIogd9K.d.cts} +27 -1
- package/dist/{chat-queue.service-Bqq00NN1.d.ts → chat-queue.service-5LIogd9K.d.ts} +27 -1
- package/dist/durable/index.cjs +1015 -955
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +1 -1
- package/dist/durable/index.d.ts +1 -1
- package/dist/durable/index.js +968 -908
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +400 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -5
- package/dist/index.d.ts +87 -5
- package/dist/index.js +392 -11
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -22,10 +22,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
22
22
|
// src/index.ts
|
|
23
23
|
var index_exports = {};
|
|
24
24
|
__export(index_exports, {
|
|
25
|
+
AGENT_CHAT_QUEUE: () => AGENT_CHAT_QUEUE,
|
|
25
26
|
AGENT_METADATA: () => AGENT_METADATA,
|
|
26
27
|
AGENT_TOOL_BRAND: () => AGENT_TOOL_BRAND,
|
|
27
28
|
AI_TOOL_METADATA: () => AI_TOOL_METADATA,
|
|
28
29
|
ATTACHMENT_PAGE_SIZE: () => ATTACHMENT_PAGE_SIZE,
|
|
30
|
+
AgUiRunHandler: () => AgUiRunHandler,
|
|
29
31
|
Agent: () => Agent,
|
|
30
32
|
AgentApprovalPortAdapter: () => AgentApprovalPortAdapter,
|
|
31
33
|
AgentDepsFactory: () => AgentDepsFactory2,
|
|
@@ -59,6 +61,7 @@ __export(index_exports, {
|
|
|
59
61
|
SystemPrompt: () => SystemPrompt,
|
|
60
62
|
SystemPromptContributor: () => SystemPromptContributor,
|
|
61
63
|
ToolsController: () => ToolsController,
|
|
64
|
+
agUiAdapter: () => agUiAdapter,
|
|
62
65
|
attachmentLimits: () => attachmentLimits,
|
|
63
66
|
declaredSkillProvider: () => declaredSkillProvider,
|
|
64
67
|
defaultRequestUserMapper: () => defaultRequestUserMapper,
|
|
@@ -1025,6 +1028,9 @@ var AgentService = class {
|
|
|
1025
1028
|
actor: params.actor,
|
|
1026
1029
|
...params.transient === true ? {
|
|
1027
1030
|
transient: true
|
|
1031
|
+
} : {},
|
|
1032
|
+
...params.newThreadId !== void 0 ? {
|
|
1033
|
+
id: params.newThreadId
|
|
1028
1034
|
} : {}
|
|
1029
1035
|
});
|
|
1030
1036
|
threadId = created.id;
|
|
@@ -1449,6 +1455,38 @@ var AgentService = class {
|
|
|
1449
1455
|
});
|
|
1450
1456
|
throw new RunNotActiveException(runId);
|
|
1451
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
|
+
}
|
|
1452
1490
|
async cancel(actor, runId) {
|
|
1453
1491
|
await this.assertOwnsActiveStream(actor, runId);
|
|
1454
1492
|
return this.runner.cancel(runId);
|
|
@@ -4343,6 +4381,9 @@ var LedgerQuotaProvider = class {
|
|
|
4343
4381
|
}
|
|
4344
4382
|
};
|
|
4345
4383
|
|
|
4384
|
+
// src/queue/chat-queue.token.ts
|
|
4385
|
+
var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
|
|
4386
|
+
|
|
4346
4387
|
// src/runner/inline-agent-runner.ts
|
|
4347
4388
|
var import_nestjs_agent_core25 = require("@dudousxd/nestjs-agent-core");
|
|
4348
4389
|
var import_common22 = require("@nestjs/common");
|
|
@@ -5047,6 +5088,10 @@ function sharedProviders(durable) {
|
|
|
5047
5088
|
// The thread message queue — every surface, since both runners and the durable workflow settle
|
|
5048
5089
|
// into it, and the chat routes enqueue into it.
|
|
5049
5090
|
ChatQueueService,
|
|
5091
|
+
{
|
|
5092
|
+
provide: AGENT_CHAT_QUEUE,
|
|
5093
|
+
useExisting: ChatQueueService
|
|
5094
|
+
},
|
|
5050
5095
|
InlineAgentRunner,
|
|
5051
5096
|
AgentService,
|
|
5052
5097
|
// Bound ALWAYS (durable or inline) — the console's cross-thread approvals inbox routes decisions
|
|
@@ -5109,6 +5154,7 @@ function exportsFor() {
|
|
|
5109
5154
|
AgentDepsFactory2,
|
|
5110
5155
|
AgentService,
|
|
5111
5156
|
ChatQueueService,
|
|
5157
|
+
AGENT_CHAT_QUEUE,
|
|
5112
5158
|
InlineAgentRunner,
|
|
5113
5159
|
import_nestjs_agent_core27.AGENT_APPROVAL_PORT
|
|
5114
5160
|
];
|
|
@@ -5129,15 +5175,28 @@ var BASE_CONTROLLERS = [
|
|
|
5129
5175
|
ConfigController,
|
|
5130
5176
|
AttachmentsController
|
|
5131
5177
|
];
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
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
|
+
];
|
|
5135
5191
|
}
|
|
5136
5192
|
__name(controllersForSurface, "controllersForSurface");
|
|
5137
5193
|
var GUARDS_METADATA = "__guards__";
|
|
5138
|
-
function applyGuards(guards) {
|
|
5194
|
+
function applyGuards(guards, adapters) {
|
|
5139
5195
|
const resolved = guards ?? [];
|
|
5140
|
-
for (const controller of
|
|
5196
|
+
for (const controller of [
|
|
5197
|
+
...BASE_CONTROLLERS,
|
|
5198
|
+
...adapterControllers(adapters)
|
|
5199
|
+
]) {
|
|
5141
5200
|
Reflect.defineMetadata(GUARDS_METADATA, resolved, controller);
|
|
5142
5201
|
}
|
|
5143
5202
|
}
|
|
@@ -5163,7 +5222,7 @@ var AgentModule = class _AgentModule {
|
|
|
5163
5222
|
}
|
|
5164
5223
|
static forRoot(options) {
|
|
5165
5224
|
const path = options.path ?? DEFAULT_PATH;
|
|
5166
|
-
applyGuards(options.guards);
|
|
5225
|
+
applyGuards(options.guards, options.adapters);
|
|
5167
5226
|
return {
|
|
5168
5227
|
module: _AgentModule,
|
|
5169
5228
|
global: true,
|
|
@@ -5171,21 +5230,22 @@ var AgentModule = class _AgentModule {
|
|
|
5171
5230
|
import_core4.DiscoveryModule,
|
|
5172
5231
|
routerFor(path)
|
|
5173
5232
|
],
|
|
5174
|
-
controllers: controllersForSurface(options.surface),
|
|
5233
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5175
5234
|
providers: [
|
|
5176
5235
|
{
|
|
5177
5236
|
provide: import_nestjs_agent_core27.AGENT_OPTIONS,
|
|
5178
5237
|
useValue: options
|
|
5179
5238
|
},
|
|
5180
5239
|
...sharedProviders(options.durable ?? false),
|
|
5181
|
-
...guardProviders(options.guards)
|
|
5240
|
+
...guardProviders(options.guards),
|
|
5241
|
+
...adapterProviders(options.adapters)
|
|
5182
5242
|
],
|
|
5183
5243
|
exports: exportsFor()
|
|
5184
5244
|
};
|
|
5185
5245
|
}
|
|
5186
5246
|
static forRootAsync(options) {
|
|
5187
5247
|
const path = options.path ?? DEFAULT_PATH;
|
|
5188
|
-
applyGuards(options.guards);
|
|
5248
|
+
applyGuards(options.guards, options.adapters);
|
|
5189
5249
|
return {
|
|
5190
5250
|
module: _AgentModule,
|
|
5191
5251
|
global: true,
|
|
@@ -5194,7 +5254,7 @@ var AgentModule = class _AgentModule {
|
|
|
5194
5254
|
routerFor(path),
|
|
5195
5255
|
...options.imports ?? []
|
|
5196
5256
|
],
|
|
5197
|
-
controllers: controllersForSurface(options.surface),
|
|
5257
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5198
5258
|
providers: [
|
|
5199
5259
|
{
|
|
5200
5260
|
provide: import_nestjs_agent_core27.AGENT_OPTIONS,
|
|
@@ -5212,7 +5272,8 @@ var AgentModule = class _AgentModule {
|
|
|
5212
5272
|
inject: options.inject ?? []
|
|
5213
5273
|
},
|
|
5214
5274
|
...sharedProviders(options.durable ?? false),
|
|
5215
|
-
...guardProviders(options.guards)
|
|
5275
|
+
...guardProviders(options.guards),
|
|
5276
|
+
...adapterProviders(options.adapters)
|
|
5216
5277
|
],
|
|
5217
5278
|
exports: exportsFor()
|
|
5218
5279
|
};
|
|
@@ -5223,8 +5284,328 @@ AgentModule = _ts_decorate22([
|
|
|
5223
5284
|
(0, import_common23.Module)({})
|
|
5224
5285
|
], AgentModule);
|
|
5225
5286
|
|
|
5226
|
-
// src/
|
|
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");
|
|
5227
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");
|
|
5228
5609
|
function readHeader(req, name) {
|
|
5229
5610
|
if (typeof req !== "object" || req === null || !("headers" in req)) return void 0;
|
|
5230
5611
|
const { headers } = req;
|
|
@@ -5240,7 +5621,7 @@ var HeaderActorResolver = class {
|
|
|
5240
5621
|
resolve(req) {
|
|
5241
5622
|
const id = readHeader(req, "x-actor-id");
|
|
5242
5623
|
if (id === void 0 || id.length === 0) {
|
|
5243
|
-
throw new
|
|
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.");
|
|
5244
5625
|
}
|
|
5245
5626
|
const roles = (readHeader(req, "x-actor-role") ?? "").split(",").map((role) => role.trim()).filter((role) => role.length > 0);
|
|
5246
5627
|
const tenantRef = readHeader(req, "x-tenant-ref");
|
|
@@ -5255,7 +5636,7 @@ var HeaderActorResolver = class {
|
|
|
5255
5636
|
};
|
|
5256
5637
|
|
|
5257
5638
|
// src/resolver/request-user-actor-resolver.ts
|
|
5258
|
-
var
|
|
5639
|
+
var import_common26 = require("@nestjs/common");
|
|
5259
5640
|
function field(user, ...names) {
|
|
5260
5641
|
for (const name of names) {
|
|
5261
5642
|
const value = user[name];
|
|
@@ -5267,7 +5648,7 @@ __name(field, "field");
|
|
|
5267
5648
|
function defaultRequestUserMapper(user) {
|
|
5268
5649
|
const id = field(user, "id", "sub", "_id", "userId");
|
|
5269
5650
|
if (id === void 0) {
|
|
5270
|
-
throw new
|
|
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 }))");
|
|
5271
5652
|
}
|
|
5272
5653
|
const rawRoles = field(user, "roles", "role");
|
|
5273
5654
|
const roles = Array.isArray(rawRoles) ? rawRoles.map(String) : typeof rawRoles === "string" ? [
|
|
@@ -5288,7 +5669,7 @@ function requestUserActorResolver(map) {
|
|
|
5288
5669
|
async resolve(req) {
|
|
5289
5670
|
const user = typeof req === "object" && req !== null ? req.user : void 0;
|
|
5290
5671
|
if (user === void 0 || user === null || user === false) {
|
|
5291
|
-
throw new
|
|
5672
|
+
throw new import_common26.UnauthorizedException("Sign in to use the agent.");
|
|
5292
5673
|
}
|
|
5293
5674
|
if (map !== void 0) return map(user, req);
|
|
5294
5675
|
return defaultRequestUserMapper(user);
|
|
@@ -5301,10 +5682,12 @@ __name(requestUserActorResolver, "requestUserActorResolver");
|
|
|
5301
5682
|
__reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports);
|
|
5302
5683
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5303
5684
|
0 && (module.exports = {
|
|
5685
|
+
AGENT_CHAT_QUEUE,
|
|
5304
5686
|
AGENT_METADATA,
|
|
5305
5687
|
AGENT_TOOL_BRAND,
|
|
5306
5688
|
AI_TOOL_METADATA,
|
|
5307
5689
|
ATTACHMENT_PAGE_SIZE,
|
|
5690
|
+
AgUiRunHandler,
|
|
5308
5691
|
Agent,
|
|
5309
5692
|
AgentApprovalPortAdapter,
|
|
5310
5693
|
AgentDepsFactory,
|
|
@@ -5338,6 +5721,7 @@ __reExport(index_exports, require("@dudousxd/nestjs-agent-core"), module.exports
|
|
|
5338
5721
|
SystemPrompt,
|
|
5339
5722
|
SystemPromptContributor,
|
|
5340
5723
|
ToolsController,
|
|
5724
|
+
agUiAdapter,
|
|
5341
5725
|
attachmentLimits,
|
|
5342
5726
|
declaredSkillProvider,
|
|
5343
5727
|
defaultRequestUserMapper,
|