@dudousxd/nestjs-agent 1.17.1 → 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 +61 -11
- 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 +61 -11
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +390 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +78 -5
- package/dist/index.d.ts +78 -5
- package/dist/index.js +383 -11
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
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);
|
|
@@ -5138,15 +5175,28 @@ var BASE_CONTROLLERS = [
|
|
|
5138
5175
|
ConfigController,
|
|
5139
5176
|
AttachmentsController
|
|
5140
5177
|
];
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
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
|
|
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/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|