@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.js
CHANGED
|
@@ -950,6 +950,9 @@ var AgentService = class {
|
|
|
950
950
|
actor: params.actor,
|
|
951
951
|
...params.transient === true ? {
|
|
952
952
|
transient: true
|
|
953
|
+
} : {},
|
|
954
|
+
...params.newThreadId !== void 0 ? {
|
|
955
|
+
id: params.newThreadId
|
|
953
956
|
} : {}
|
|
954
957
|
});
|
|
955
958
|
threadId = created.id;
|
|
@@ -1374,6 +1377,38 @@ var AgentService = class {
|
|
|
1374
1377
|
});
|
|
1375
1378
|
throw new RunNotActiveException(runId);
|
|
1376
1379
|
}
|
|
1380
|
+
/** Who owns the thread, or `null` when there is no such (live) thread. */
|
|
1381
|
+
async threadOwner(threadId) {
|
|
1382
|
+
return this.store.ownerOfThread(threadId);
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* May `actor` continue the run whose stream is `runId` — the AG-UI resume? Only the actor whose
|
|
1386
|
+
* thread is streaming it (`403` otherwise), and only while it still is: a run that is over is
|
|
1387
|
+
* waiting on no one (`409 run_not_active`), whatever an old interrupt id says.
|
|
1388
|
+
*/
|
|
1389
|
+
async assertResumable(actor, runId) {
|
|
1390
|
+
const owner = await this.store.ownerOfActiveStream(runId);
|
|
1391
|
+
if (owner === null) {
|
|
1392
|
+
throw new RunNotActiveException(runId);
|
|
1393
|
+
}
|
|
1394
|
+
if (owner !== actor.id) {
|
|
1395
|
+
throw new ForbiddenException("run belongs to another actor");
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Everything {@link approve} / {@link reject} check before they signal — who may decide, and
|
|
1400
|
+
* that the request has not lapsed — without signalling. For a caller that settles several
|
|
1401
|
+
* decisions at once and must refuse all of them if one is refused (an AG-UI resume).
|
|
1402
|
+
*/
|
|
1403
|
+
async checkDecision(actor, toolCallId2) {
|
|
1404
|
+
await this.assertMayDecide(actor, toolCallId2);
|
|
1405
|
+
await this.assertNotExpired(toolCallId2);
|
|
1406
|
+
}
|
|
1407
|
+
/** Everything {@link answer} checks before it signals, without signalling — see {@link checkDecision}. */
|
|
1408
|
+
async checkAnswer(actor, toolCallId2, answers2) {
|
|
1409
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
1410
|
+
await this.assertAnswersFit(toolCallId2, answers2);
|
|
1411
|
+
}
|
|
1377
1412
|
async cancel(actor, runId) {
|
|
1378
1413
|
await this.assertOwnsActiveStream(actor, runId);
|
|
1379
1414
|
return this.runner.cancel(runId);
|
|
@@ -4268,6 +4303,9 @@ var LedgerQuotaProvider = class {
|
|
|
4268
4303
|
}
|
|
4269
4304
|
};
|
|
4270
4305
|
|
|
4306
|
+
// src/queue/chat-queue.token.ts
|
|
4307
|
+
var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
|
|
4308
|
+
|
|
4271
4309
|
// src/runner/inline-agent-runner.ts
|
|
4272
4310
|
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_STORE as AGENT_STORE4, RUN_ENDED_BEFORE_TOOL_CALL, RunCancelledError, agentFailureCode, encodeStreamEvent as encodeStreamEvent2, publishAgentRunFailed, releaseThreadRun, runAgentLoop, settleAll, settleUnsettledDelegation, streamFailure as streamFailure2 } from "@dudousxd/nestjs-agent-core";
|
|
4273
4311
|
import { Inject as Inject20, Injectable as Injectable8, Logger as Logger5, Optional as Optional8 } from "@nestjs/common";
|
|
@@ -4972,6 +5010,10 @@ function sharedProviders(durable) {
|
|
|
4972
5010
|
// The thread message queue — every surface, since both runners and the durable workflow settle
|
|
4973
5011
|
// into it, and the chat routes enqueue into it.
|
|
4974
5012
|
ChatQueueService,
|
|
5013
|
+
{
|
|
5014
|
+
provide: AGENT_CHAT_QUEUE,
|
|
5015
|
+
useExisting: ChatQueueService
|
|
5016
|
+
},
|
|
4975
5017
|
InlineAgentRunner,
|
|
4976
5018
|
AgentService,
|
|
4977
5019
|
// Bound ALWAYS (durable or inline) — the console's cross-thread approvals inbox routes decisions
|
|
@@ -5034,6 +5076,7 @@ function exportsFor() {
|
|
|
5034
5076
|
AgentDepsFactory2,
|
|
5035
5077
|
AgentService,
|
|
5036
5078
|
ChatQueueService,
|
|
5079
|
+
AGENT_CHAT_QUEUE,
|
|
5037
5080
|
InlineAgentRunner,
|
|
5038
5081
|
AGENT_APPROVAL_PORT
|
|
5039
5082
|
];
|
|
@@ -5054,15 +5097,28 @@ var BASE_CONTROLLERS = [
|
|
|
5054
5097
|
ConfigController,
|
|
5055
5098
|
AttachmentsController
|
|
5056
5099
|
];
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5100
|
+
function adapterControllers(adapters) {
|
|
5101
|
+
return (adapters ?? []).flatMap((adapter) => adapter.controllers);
|
|
5102
|
+
}
|
|
5103
|
+
__name(adapterControllers, "adapterControllers");
|
|
5104
|
+
function adapterProviders(adapters) {
|
|
5105
|
+
return (adapters ?? []).flatMap((adapter) => adapter.providers ?? []);
|
|
5106
|
+
}
|
|
5107
|
+
__name(adapterProviders, "adapterProviders");
|
|
5108
|
+
function controllersForSurface(surface, adapters) {
|
|
5109
|
+
return surface === "engine" ? [] : [
|
|
5110
|
+
...BASE_CONTROLLERS,
|
|
5111
|
+
...adapterControllers(adapters)
|
|
5112
|
+
];
|
|
5060
5113
|
}
|
|
5061
5114
|
__name(controllersForSurface, "controllersForSurface");
|
|
5062
5115
|
var GUARDS_METADATA = "__guards__";
|
|
5063
|
-
function applyGuards(guards) {
|
|
5116
|
+
function applyGuards(guards, adapters) {
|
|
5064
5117
|
const resolved = guards ?? [];
|
|
5065
|
-
for (const controller of
|
|
5118
|
+
for (const controller of [
|
|
5119
|
+
...BASE_CONTROLLERS,
|
|
5120
|
+
...adapterControllers(adapters)
|
|
5121
|
+
]) {
|
|
5066
5122
|
Reflect.defineMetadata(GUARDS_METADATA, resolved, controller);
|
|
5067
5123
|
}
|
|
5068
5124
|
}
|
|
@@ -5088,7 +5144,7 @@ var AgentModule = class _AgentModule {
|
|
|
5088
5144
|
}
|
|
5089
5145
|
static forRoot(options) {
|
|
5090
5146
|
const path = options.path ?? DEFAULT_PATH;
|
|
5091
|
-
applyGuards(options.guards);
|
|
5147
|
+
applyGuards(options.guards, options.adapters);
|
|
5092
5148
|
return {
|
|
5093
5149
|
module: _AgentModule,
|
|
5094
5150
|
global: true,
|
|
@@ -5096,21 +5152,22 @@ var AgentModule = class _AgentModule {
|
|
|
5096
5152
|
DiscoveryModule,
|
|
5097
5153
|
routerFor(path)
|
|
5098
5154
|
],
|
|
5099
|
-
controllers: controllersForSurface(options.surface),
|
|
5155
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5100
5156
|
providers: [
|
|
5101
5157
|
{
|
|
5102
5158
|
provide: AGENT_OPTIONS7,
|
|
5103
5159
|
useValue: options
|
|
5104
5160
|
},
|
|
5105
5161
|
...sharedProviders(options.durable ?? false),
|
|
5106
|
-
...guardProviders(options.guards)
|
|
5162
|
+
...guardProviders(options.guards),
|
|
5163
|
+
...adapterProviders(options.adapters)
|
|
5107
5164
|
],
|
|
5108
5165
|
exports: exportsFor()
|
|
5109
5166
|
};
|
|
5110
5167
|
}
|
|
5111
5168
|
static forRootAsync(options) {
|
|
5112
5169
|
const path = options.path ?? DEFAULT_PATH;
|
|
5113
|
-
applyGuards(options.guards);
|
|
5170
|
+
applyGuards(options.guards, options.adapters);
|
|
5114
5171
|
return {
|
|
5115
5172
|
module: _AgentModule,
|
|
5116
5173
|
global: true,
|
|
@@ -5119,7 +5176,7 @@ var AgentModule = class _AgentModule {
|
|
|
5119
5176
|
routerFor(path),
|
|
5120
5177
|
...options.imports ?? []
|
|
5121
5178
|
],
|
|
5122
|
-
controllers: controllersForSurface(options.surface),
|
|
5179
|
+
controllers: controllersForSurface(options.surface, options.adapters),
|
|
5123
5180
|
providers: [
|
|
5124
5181
|
{
|
|
5125
5182
|
provide: AGENT_OPTIONS7,
|
|
@@ -5137,7 +5194,8 @@ var AgentModule = class _AgentModule {
|
|
|
5137
5194
|
inject: options.inject ?? []
|
|
5138
5195
|
},
|
|
5139
5196
|
...sharedProviders(options.durable ?? false),
|
|
5140
|
-
...guardProviders(options.guards)
|
|
5197
|
+
...guardProviders(options.guards),
|
|
5198
|
+
...adapterProviders(options.adapters)
|
|
5141
5199
|
],
|
|
5142
5200
|
exports: exportsFor()
|
|
5143
5201
|
};
|
|
@@ -5148,6 +5206,326 @@ AgentModule = _ts_decorate22([
|
|
|
5148
5206
|
Module({})
|
|
5149
5207
|
], AgentModule);
|
|
5150
5208
|
|
|
5209
|
+
// src/ag-ui/ag-ui.adapter.ts
|
|
5210
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER14, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING5, AGENT_OPTIONS as AGENT_OPTIONS8 } from "@dudousxd/nestjs-agent-core";
|
|
5211
|
+
import { AG_UI_CUSTOM, agUiEvents, agUiFramesFromNdjson, agUiSse, parseRunInput, planResume, readAnswersPayload, readApprovalPayload, readContext, readForwardedProps, readUserTurn } from "@dudousxd/nestjs-agent-core/ag-ui";
|
|
5212
|
+
import { BadRequestException as BadRequestException6, Body as Body6, Controller as Controller14, ForbiddenException as ForbiddenException3, HttpCode as HttpCode2, Inject as Inject21, Optional as Optional9, Post as Post7, Req as Req13, Res as Res2 } from "@nestjs/common";
|
|
5213
|
+
function _ts_decorate23(decorators, target, key, desc) {
|
|
5214
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5215
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
5216
|
+
r = Reflect.decorate(decorators, target, key, desc);
|
|
5217
|
+
} else {
|
|
5218
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
5219
|
+
if (d = decorators[i]) {
|
|
5220
|
+
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5221
|
+
}
|
|
5222
|
+
}
|
|
5223
|
+
}
|
|
5224
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
5225
|
+
}
|
|
5226
|
+
__name(_ts_decorate23, "_ts_decorate");
|
|
5227
|
+
function _ts_metadata22(metadataKey, metadataValue) {
|
|
5228
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
|
|
5229
|
+
return Reflect.metadata(metadataKey, metadataValue);
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
__name(_ts_metadata22, "_ts_metadata");
|
|
5233
|
+
function _ts_param21(paramIndex, decorator) {
|
|
5234
|
+
return function(target, key) {
|
|
5235
|
+
decorator(target, key, paramIndex);
|
|
5236
|
+
};
|
|
5237
|
+
}
|
|
5238
|
+
__name(_ts_param21, "_ts_param");
|
|
5239
|
+
var AG_UI_VIA = "ag-ui";
|
|
5240
|
+
function invalid(code, message) {
|
|
5241
|
+
return new BadRequestException6({
|
|
5242
|
+
statusCode: 400,
|
|
5243
|
+
code,
|
|
5244
|
+
message
|
|
5245
|
+
});
|
|
5246
|
+
}
|
|
5247
|
+
__name(invalid, "invalid");
|
|
5248
|
+
function warningEvents(warnings) {
|
|
5249
|
+
return warnings.map((message) => ({
|
|
5250
|
+
type: "CUSTOM",
|
|
5251
|
+
name: AG_UI_CUSTOM.warning,
|
|
5252
|
+
value: {
|
|
5253
|
+
message
|
|
5254
|
+
}
|
|
5255
|
+
}));
|
|
5256
|
+
}
|
|
5257
|
+
__name(warningEvents, "warningEvents");
|
|
5258
|
+
var AgUiRunHandler = class {
|
|
5259
|
+
static {
|
|
5260
|
+
__name(this, "AgUiRunHandler");
|
|
5261
|
+
}
|
|
5262
|
+
agent;
|
|
5263
|
+
actorResolver;
|
|
5264
|
+
options;
|
|
5265
|
+
staging;
|
|
5266
|
+
quietMs;
|
|
5267
|
+
constructor(agent, actorResolver, options, staging, quietMs) {
|
|
5268
|
+
this.agent = agent;
|
|
5269
|
+
this.actorResolver = actorResolver;
|
|
5270
|
+
this.options = options;
|
|
5271
|
+
this.staging = staging;
|
|
5272
|
+
this.quietMs = quietMs;
|
|
5273
|
+
}
|
|
5274
|
+
async handle(req, res, body) {
|
|
5275
|
+
const input = parseRunInput(body);
|
|
5276
|
+
if (typeof input === "string") {
|
|
5277
|
+
throw invalid("invalid_input", input);
|
|
5278
|
+
}
|
|
5279
|
+
const forwarded = readForwardedProps(input.forwardedProps);
|
|
5280
|
+
const actor = await this.actorResolver.resolve(req);
|
|
5281
|
+
const warnings = [];
|
|
5282
|
+
if (Array.isArray(input.tools) && input.tools.length > 0) {
|
|
5283
|
+
warnings.push("Frontend tools are not supported by this agent: the tools list was ignored.");
|
|
5284
|
+
}
|
|
5285
|
+
const quiet = this.quietMs !== void 0 ? {
|
|
5286
|
+
quietMs: this.quietMs
|
|
5287
|
+
} : {};
|
|
5288
|
+
if (input.resume !== void 0 && input.resume.length > 0) {
|
|
5289
|
+
const plan = planResume(input.resume);
|
|
5290
|
+
if (typeof plan === "string") {
|
|
5291
|
+
throw invalid("invalid_resume", plan);
|
|
5292
|
+
}
|
|
5293
|
+
for (const id of plan.unrecognised) {
|
|
5294
|
+
warnings.push(`The resume entry ${id} answers an interrupt this agent did not raise.`);
|
|
5295
|
+
}
|
|
5296
|
+
const first = plan.decisions[0];
|
|
5297
|
+
if (first !== void 0) {
|
|
5298
|
+
const streamRunId = first.address.stream;
|
|
5299
|
+
await this.agent.assertResumable(actor, streamRunId);
|
|
5300
|
+
await this.settle(actor, plan.decisions);
|
|
5301
|
+
await this.pipe(res, streamRunId, {
|
|
5302
|
+
threadId: input.threadId,
|
|
5303
|
+
runId: input.runId,
|
|
5304
|
+
streamRunId,
|
|
5305
|
+
skip: first.address.position,
|
|
5306
|
+
answered: plan.decisions.map((decision) => decision.address.toolCallId),
|
|
5307
|
+
...quiet,
|
|
5308
|
+
preamble: warningEvents(warnings)
|
|
5309
|
+
});
|
|
5310
|
+
return;
|
|
5311
|
+
}
|
|
5312
|
+
}
|
|
5313
|
+
const turn = readUserTurn(input.messages);
|
|
5314
|
+
if (turn === null) {
|
|
5315
|
+
throw invalid("no_user_message", "messages carries no user message to answer");
|
|
5316
|
+
}
|
|
5317
|
+
warnings.push(...turn.dropped);
|
|
5318
|
+
const owner = await this.agent.threadOwner(input.threadId);
|
|
5319
|
+
if (owner !== null && owner !== actor.id) {
|
|
5320
|
+
throw new ForbiddenException3("thread belongs to another actor");
|
|
5321
|
+
}
|
|
5322
|
+
const refs = await this.stage(actor, turn.media, warnings);
|
|
5323
|
+
if (turn.text.trim().length === 0 && refs.length === 0) {
|
|
5324
|
+
throw invalid("no_user_message", "the user message to answer is empty");
|
|
5325
|
+
}
|
|
5326
|
+
const context = readContext(input.context);
|
|
5327
|
+
const pageContext = forwarded.pageContext !== void 0 || context !== void 0 ? {
|
|
5328
|
+
...forwarded.pageContext,
|
|
5329
|
+
...context !== void 0 ? {
|
|
5330
|
+
agUiContext: context
|
|
5331
|
+
} : {}
|
|
5332
|
+
} : void 0;
|
|
5333
|
+
const started = await this.agent.chat({
|
|
5334
|
+
actor,
|
|
5335
|
+
message: turn.text,
|
|
5336
|
+
...owner !== null ? {
|
|
5337
|
+
threadId: input.threadId
|
|
5338
|
+
} : {
|
|
5339
|
+
newThreadId: input.threadId
|
|
5340
|
+
},
|
|
5341
|
+
...forwarded.agent !== void 0 ? {
|
|
5342
|
+
agentName: forwarded.agent
|
|
5343
|
+
} : {},
|
|
5344
|
+
...forwarded.model !== void 0 ? {
|
|
5345
|
+
model: forwarded.model
|
|
5346
|
+
} : {},
|
|
5347
|
+
...pageContext !== void 0 ? {
|
|
5348
|
+
pageContext
|
|
5349
|
+
} : {},
|
|
5350
|
+
...refs.length > 0 ? {
|
|
5351
|
+
attachments: refs
|
|
5352
|
+
} : {}
|
|
5353
|
+
});
|
|
5354
|
+
await this.pipe(res, started.runId, {
|
|
5355
|
+
threadId: input.threadId,
|
|
5356
|
+
runId: input.runId,
|
|
5357
|
+
streamRunId: started.runId,
|
|
5358
|
+
streamThreadId: started.threadId,
|
|
5359
|
+
...quiet,
|
|
5360
|
+
preamble: warningEvents(warnings)
|
|
5361
|
+
});
|
|
5362
|
+
}
|
|
5363
|
+
/** Stage the turn's inline media through the bound store, within its limits; say what was not used. */
|
|
5364
|
+
async stage(actor, media, warnings) {
|
|
5365
|
+
const refs = [];
|
|
5366
|
+
const limits = attachmentLimits(this.options, this.staging);
|
|
5367
|
+
for (const item of media) {
|
|
5368
|
+
const label = `The ${item.kind} "${item.filename}" was not used`;
|
|
5369
|
+
if (this.staging === void 0) {
|
|
5370
|
+
warnings.push(`${label}: attachments are not enabled on this agent.`);
|
|
5371
|
+
} else if (refs.length >= limits.maxPerMessage) {
|
|
5372
|
+
warnings.push(`${label}: a message carries at most ${limits.maxPerMessage} attachments.`);
|
|
5373
|
+
} else if (!limits.allowedContentTypes.includes(item.contentType)) {
|
|
5374
|
+
warnings.push(`${label}: ${item.contentType} is not an accepted type.`);
|
|
5375
|
+
} else if (item.data.length > limits.maxBytes) {
|
|
5376
|
+
warnings.push(`${label}: it is larger than ${limits.maxBytes} bytes.`);
|
|
5377
|
+
} else {
|
|
5378
|
+
try {
|
|
5379
|
+
const staged = await this.staging.stage({
|
|
5380
|
+
data: item.data,
|
|
5381
|
+
filename: item.filename,
|
|
5382
|
+
contentType: item.contentType,
|
|
5383
|
+
sizeBytes: item.data.length,
|
|
5384
|
+
actor
|
|
5385
|
+
});
|
|
5386
|
+
refs.push({
|
|
5387
|
+
mediaId: staged.mediaId
|
|
5388
|
+
});
|
|
5389
|
+
} catch {
|
|
5390
|
+
warnings.push(`${label}: it could not be stored.`);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
return refs;
|
|
5395
|
+
}
|
|
5396
|
+
/**
|
|
5397
|
+
* Deliver what a resume list decided, through the same calls the native decision routes make.
|
|
5398
|
+
* Everything that can refuse — who may decide, an answer a question's rules reject, a payload that
|
|
5399
|
+
* says nothing — is checked for EVERY entry before the first one is delivered, so a list with one
|
|
5400
|
+
* bad entry settles nothing.
|
|
5401
|
+
*/
|
|
5402
|
+
async settle(actor, decisions) {
|
|
5403
|
+
const deliveries = [];
|
|
5404
|
+
for (const { address, entry } of decisions) {
|
|
5405
|
+
const { toolCallId: toolCallId2 } = address;
|
|
5406
|
+
const abandoned = entry.status === "cancelled";
|
|
5407
|
+
if (address.kind === "approval") {
|
|
5408
|
+
await this.agent.checkDecision(actor, toolCallId2);
|
|
5409
|
+
const decision = abandoned ? {
|
|
5410
|
+
approved: false
|
|
5411
|
+
} : readApprovalPayload(entry.payload);
|
|
5412
|
+
if (decision === null) {
|
|
5413
|
+
throw invalid("invalid_resume", "an approval is answered with { approved: boolean, reason?, remember? }");
|
|
5414
|
+
}
|
|
5415
|
+
const reason = rejectReason(decision.reason ?? (abandoned ? "abandoned" : void 0));
|
|
5416
|
+
deliveries.push(() => decision.approved ? this.agent.approve(actor, toolCallId2, {
|
|
5417
|
+
via: AG_UI_VIA,
|
|
5418
|
+
...decision.remember === true ? {
|
|
5419
|
+
remember: true
|
|
5420
|
+
} : {}
|
|
5421
|
+
}) : this.agent.reject(actor, toolCallId2, reason, {
|
|
5422
|
+
via: AG_UI_VIA
|
|
5423
|
+
}));
|
|
5424
|
+
continue;
|
|
5425
|
+
}
|
|
5426
|
+
if (abandoned) {
|
|
5427
|
+
await this.agent.checkAnswer(actor, toolCallId2, {});
|
|
5428
|
+
deliveries.push(() => this.agent.skip(actor, toolCallId2, {
|
|
5429
|
+
via: AG_UI_VIA
|
|
5430
|
+
}));
|
|
5431
|
+
continue;
|
|
5432
|
+
}
|
|
5433
|
+
const read = readAnswersPayload(entry.payload);
|
|
5434
|
+
if (read === null) {
|
|
5435
|
+
throw invalid("invalid_resume", "a question set is answered with { answers: { <questionId>: string[] } }");
|
|
5436
|
+
}
|
|
5437
|
+
const answers2 = answers(read) ?? {};
|
|
5438
|
+
await this.agent.checkAnswer(actor, toolCallId2, answers2);
|
|
5439
|
+
deliveries.push(() => this.agent.answer(actor, toolCallId2, answers2, {
|
|
5440
|
+
via: AG_UI_VIA
|
|
5441
|
+
}));
|
|
5442
|
+
}
|
|
5443
|
+
for (const deliver of deliveries) await deliver();
|
|
5444
|
+
}
|
|
5445
|
+
/**
|
|
5446
|
+
* Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
|
|
5447
|
+
* to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
|
|
5448
|
+
* and the request that answers re-attaches to it.
|
|
5449
|
+
*/
|
|
5450
|
+
async pipe(res, runId, options) {
|
|
5451
|
+
res.status(200);
|
|
5452
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
5453
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
5454
|
+
res.setHeader("Connection", "keep-alive");
|
|
5455
|
+
res.setHeader("X-Accel-Buffering", "no");
|
|
5456
|
+
res.setHeader("X-Agent-Run-Id", runId);
|
|
5457
|
+
res.flushHeaders();
|
|
5458
|
+
let terminal = false;
|
|
5459
|
+
try {
|
|
5460
|
+
const frames = agUiFramesFromNdjson(this.agent.subscribe(runId));
|
|
5461
|
+
for await (const event of agUiEvents(frames, options)) {
|
|
5462
|
+
if (event.type === "RUN_FINISHED" || event.type === "RUN_ERROR") terminal = true;
|
|
5463
|
+
res.write(agUiSse(event));
|
|
5464
|
+
}
|
|
5465
|
+
} catch {
|
|
5466
|
+
if (!terminal) {
|
|
5467
|
+
res.write(agUiSse({
|
|
5468
|
+
type: "RUN_ERROR",
|
|
5469
|
+
message: "The run could not be followed.",
|
|
5470
|
+
code: "run_failed"
|
|
5471
|
+
}));
|
|
5472
|
+
}
|
|
5473
|
+
}
|
|
5474
|
+
res.end();
|
|
5475
|
+
}
|
|
5476
|
+
};
|
|
5477
|
+
function agUiAdapter(options = {}) {
|
|
5478
|
+
const path = (options.path ?? "ag-ui").replace(/^\/+|\/+$/g, "");
|
|
5479
|
+
const quietMs = options.quietMs;
|
|
5480
|
+
let AgUiController = class AgUiController extends AgUiRunHandler {
|
|
5481
|
+
static {
|
|
5482
|
+
__name(this, "AgUiController");
|
|
5483
|
+
}
|
|
5484
|
+
constructor(agent, actorResolver, moduleOptions, staging) {
|
|
5485
|
+
super(agent, actorResolver, moduleOptions, staging, quietMs);
|
|
5486
|
+
}
|
|
5487
|
+
run(req, res, body) {
|
|
5488
|
+
return this.handle(req, res, body);
|
|
5489
|
+
}
|
|
5490
|
+
};
|
|
5491
|
+
_ts_decorate23([
|
|
5492
|
+
Post7(path),
|
|
5493
|
+
HttpCode2(200),
|
|
5494
|
+
_ts_param21(0, Req13()),
|
|
5495
|
+
_ts_param21(1, Res2()),
|
|
5496
|
+
_ts_param21(2, Body6()),
|
|
5497
|
+
_ts_metadata22("design:type", Function),
|
|
5498
|
+
_ts_metadata22("design:paramtypes", [
|
|
5499
|
+
typeof Request === "undefined" ? Object : Request,
|
|
5500
|
+
typeof Response === "undefined" ? Object : Response,
|
|
5501
|
+
Object
|
|
5502
|
+
]),
|
|
5503
|
+
_ts_metadata22("design:returntype", typeof Promise === "undefined" ? Object : Promise)
|
|
5504
|
+
], AgUiController.prototype, "run", null);
|
|
5505
|
+
AgUiController = _ts_decorate23([
|
|
5506
|
+
Controller14(),
|
|
5507
|
+
_ts_param21(0, Inject21(AgentService)),
|
|
5508
|
+
_ts_param21(1, Inject21(AGENT_ACTOR_RESOLVER14)),
|
|
5509
|
+
_ts_param21(2, Inject21(AGENT_OPTIONS8)),
|
|
5510
|
+
_ts_param21(3, Optional9()),
|
|
5511
|
+
_ts_param21(3, Inject21(AGENT_ATTACHMENT_STAGING5)),
|
|
5512
|
+
_ts_metadata22("design:type", Function),
|
|
5513
|
+
_ts_metadata22("design:paramtypes", [
|
|
5514
|
+
typeof AgentService === "undefined" ? Object : AgentService,
|
|
5515
|
+
typeof ActorResolver === "undefined" ? Object : ActorResolver,
|
|
5516
|
+
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
5517
|
+
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
|
|
5518
|
+
])
|
|
5519
|
+
], AgUiController);
|
|
5520
|
+
return {
|
|
5521
|
+
name: "ag-ui",
|
|
5522
|
+
controllers: [
|
|
5523
|
+
AgUiController
|
|
5524
|
+
]
|
|
5525
|
+
};
|
|
5526
|
+
}
|
|
5527
|
+
__name(agUiAdapter, "agUiAdapter");
|
|
5528
|
+
|
|
5151
5529
|
// src/resolver/header-actor-resolver.ts
|
|
5152
5530
|
import { UnauthorizedException } from "@nestjs/common";
|
|
5153
5531
|
function readHeader(req, name) {
|
|
@@ -5225,10 +5603,12 @@ __name(requestUserActorResolver, "requestUserActorResolver");
|
|
|
5225
5603
|
// src/index.ts
|
|
5226
5604
|
export * from "@dudousxd/nestjs-agent-core";
|
|
5227
5605
|
export {
|
|
5606
|
+
AGENT_CHAT_QUEUE,
|
|
5228
5607
|
AGENT_METADATA,
|
|
5229
5608
|
AGENT_TOOL_BRAND,
|
|
5230
5609
|
AI_TOOL_METADATA,
|
|
5231
5610
|
ATTACHMENT_PAGE_SIZE,
|
|
5611
|
+
AgUiRunHandler,
|
|
5232
5612
|
Agent,
|
|
5233
5613
|
AgentApprovalPortAdapter,
|
|
5234
5614
|
AgentDepsFactory2 as AgentDepsFactory,
|
|
@@ -5262,6 +5642,7 @@ export {
|
|
|
5262
5642
|
SystemPrompt,
|
|
5263
5643
|
SystemPromptContributor,
|
|
5264
5644
|
ToolsController,
|
|
5645
|
+
agUiAdapter,
|
|
5265
5646
|
attachmentLimits,
|
|
5266
5647
|
declaredSkillProvider,
|
|
5267
5648
|
defaultRequestUserMapper,
|