@dudousxd/nestjs-agent 1.21.0 → 1.23.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/README.md +7 -0
- package/dist/{chat-queue.service-XG9RQCjU.d.ts → chat-queue.service-CwxJDrBM.d.ts} +76 -5
- package/dist/{chat-queue.service-CGsR40Ct.d.cts → chat-queue.service-D1z3WjFI.d.cts} +76 -5
- package/dist/durable/index.cjs +398 -256
- 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 +186 -44
- package/dist/durable/index.js.map +1 -1
- package/dist/genui/index.cjs +1 -0
- package/dist/genui/index.cjs.map +1 -1
- package/dist/genui/index.js +1 -0
- package/dist/genui/index.js.map +1 -1
- package/dist/index.cjs +468 -269
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +51 -14
- package/dist/index.d.ts +51 -14
- package/dist/index.js +249 -51
- package/dist/index.js.map +1 -1
- package/dist/sink-redis/index.cjs +7 -2
- package/dist/sink-redis/index.cjs.map +1 -1
- package/dist/sink-redis/index.d.cts +6 -3
- package/dist/sink-redis/index.d.ts +6 -3
- package/dist/sink-redis/index.js +7 -2
- package/dist/sink-redis/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { defineCatalog, genuiTools } from "@dudousxd/nestjs-agent-core/genui";
|
|
|
17
17
|
import { Inject, Module } from "@nestjs/common";
|
|
18
18
|
|
|
19
19
|
// src/functional-tool.ts
|
|
20
|
+
import { createFunctionalTool } from "@dudousxd/nestjs-agent-core";
|
|
20
21
|
var AGENT_TOOL_BRAND = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:functional-tool");
|
|
21
22
|
function brand(tool) {
|
|
22
23
|
return {
|
|
@@ -53,6 +54,7 @@ function provideAgentTools(factory, inject) {
|
|
|
53
54
|
};
|
|
54
55
|
}
|
|
55
56
|
__name(provideAgentTools, "provideAgentTools");
|
|
57
|
+
var defineTool = createFunctionalTool;
|
|
56
58
|
|
|
57
59
|
// src/genui/agent-genui.module.ts
|
|
58
60
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -589,7 +591,7 @@ function childSinkWriter(writer) {
|
|
|
589
591
|
__name(childSinkWriter, "childSinkWriter");
|
|
590
592
|
|
|
591
593
|
// src/proposals/action-proposal.service.ts
|
|
592
|
-
import { AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_STORE as AGENT_STORE2, mayDecideApproval, parseTextActionProposalCommand, resolveTextActionProposalDecision } from "@dudousxd/nestjs-agent-core";
|
|
594
|
+
import { AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_STORE as AGENT_STORE2, DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY, mayDecideApproval, parseTextActionProposalCommand, resolveTextActionProposalDecision, textActionProposalReply, toActionProposalMutationView, toActionProposalView } from "@dudousxd/nestjs-agent-core";
|
|
593
595
|
import { ForbiddenException, Inject as Inject3, Injectable as Injectable2, NotFoundException, NotImplementedException } from "@nestjs/common";
|
|
594
596
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
595
597
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -626,7 +628,19 @@ var ActionProposalService = class {
|
|
|
626
628
|
constructor(store, options) {
|
|
627
629
|
this.store = store;
|
|
628
630
|
this.options = options;
|
|
631
|
+
const text = options.actionProposalText;
|
|
632
|
+
this.vocabulary = {
|
|
633
|
+
...DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY,
|
|
634
|
+
...text?.vocabulary
|
|
635
|
+
};
|
|
636
|
+
this.replies = {
|
|
637
|
+
...DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES,
|
|
638
|
+
...text?.replies
|
|
639
|
+
};
|
|
629
640
|
}
|
|
641
|
+
/** The words a text decision is made of, and what the agent answers — English unless configured. */
|
|
642
|
+
vocabulary;
|
|
643
|
+
replies;
|
|
630
644
|
capability() {
|
|
631
645
|
const store = this.store;
|
|
632
646
|
if (typeof store.getThreadActionProposalScope !== "function" || typeof store.listActionProposals !== "function") throw new NotImplementedException("Action proposals are unavailable");
|
|
@@ -655,7 +669,8 @@ var ActionProposalService = class {
|
|
|
655
669
|
for (const row of rows) if (scope.actorRef === actor.id || await this.mayDecide(actor, row)) visible.push(row);
|
|
656
670
|
const last = rows.at(-1);
|
|
657
671
|
return {
|
|
658
|
-
|
|
672
|
+
// The public view: a row carries the worker's lease token and the tool's idempotency key.
|
|
673
|
+
items: visible.map(toActionProposalView),
|
|
659
674
|
...rows.length === 1e3 && last ? {
|
|
660
675
|
next: {
|
|
661
676
|
createdAt: last.createdAt,
|
|
@@ -672,7 +687,7 @@ var ActionProposalService = class {
|
|
|
672
687
|
const proposal = await this.capability().getActionProposal(scope, proposalId);
|
|
673
688
|
if (!proposal) throw new NotFoundException("Proposal not found");
|
|
674
689
|
if (!await this.mayDecide(actor, proposal)) throw new ForbiddenException("May not decide this proposal");
|
|
675
|
-
|
|
690
|
+
const result = await this.capability().decideActionProposal(scope, proposalId, {
|
|
676
691
|
decision: command.decision,
|
|
677
692
|
actorRef: actor.id,
|
|
678
693
|
via: command.via ?? "web",
|
|
@@ -683,9 +698,10 @@ var ActionProposalService = class {
|
|
|
683
698
|
reason: command.reason
|
|
684
699
|
} : {}
|
|
685
700
|
});
|
|
701
|
+
return toActionProposalMutationView(result);
|
|
686
702
|
}
|
|
687
703
|
async handleTextDecision(threadId, actor, text) {
|
|
688
|
-
const command = parseTextActionProposalCommand(text);
|
|
704
|
+
const command = parseTextActionProposalCommand(text, this.vocabulary);
|
|
689
705
|
if (command.status === "unmatched") return command;
|
|
690
706
|
if (command.proposalId !== void 0) {
|
|
691
707
|
const result2 = await this.decide(threadId, command.proposalId, actor, {
|
|
@@ -693,7 +709,7 @@ var ActionProposalService = class {
|
|
|
693
709
|
remember: command.remember,
|
|
694
710
|
via: "text"
|
|
695
711
|
});
|
|
696
|
-
return this.textReceipt(threadId, result2);
|
|
712
|
+
return this.textReceipt(threadId, result2, command.decision);
|
|
697
713
|
}
|
|
698
714
|
const candidates = [];
|
|
699
715
|
const scope = await this.scope(threadId, actor);
|
|
@@ -702,30 +718,38 @@ var ActionProposalService = class {
|
|
|
702
718
|
limit: 1e3
|
|
703
719
|
});
|
|
704
720
|
for (const proposal of pending) if (await this.mayDecide(actor, proposal)) candidates.push(proposal);
|
|
705
|
-
const resolution = resolveTextActionProposalDecision(text, candidates);
|
|
721
|
+
const resolution = resolveTextActionProposalDecision(text, candidates, this.vocabulary);
|
|
706
722
|
if (resolution.status === "unmatched") return resolution;
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
723
|
+
const saturated = pending.length === 1e3 && !text.includes("#");
|
|
724
|
+
if (resolution.status === "ambiguous" || saturated) {
|
|
725
|
+
const proposalIds = candidates.map(({ id }) => id);
|
|
726
|
+
return {
|
|
727
|
+
threadId,
|
|
728
|
+
proposalDecision: {
|
|
729
|
+
status: "ambiguous",
|
|
730
|
+
proposalIds
|
|
731
|
+
},
|
|
732
|
+
text: saturated ? this.replies.tooMany : this.replies.ambiguous(proposalIds)
|
|
733
|
+
};
|
|
734
|
+
}
|
|
715
735
|
const result = await this.decide(threadId, resolution.proposalId, actor, {
|
|
716
736
|
decision: resolution.decision,
|
|
717
737
|
remember: resolution.remember,
|
|
718
738
|
via: "text"
|
|
719
739
|
});
|
|
720
|
-
return this.textReceipt(threadId, result);
|
|
740
|
+
return this.textReceipt(threadId, result, resolution.decision);
|
|
721
741
|
}
|
|
722
|
-
textReceipt(threadId, result) {
|
|
742
|
+
textReceipt(threadId, result, decision) {
|
|
723
743
|
return {
|
|
724
744
|
threadId,
|
|
725
745
|
proposalDecision: result,
|
|
726
|
-
text:
|
|
746
|
+
text: this.reply(result, decision)
|
|
727
747
|
};
|
|
728
748
|
}
|
|
749
|
+
/** The configured reply to a decision the store answered with `result`. */
|
|
750
|
+
reply(result, decision) {
|
|
751
|
+
return textActionProposalReply(result, decision, this.replies);
|
|
752
|
+
}
|
|
729
753
|
};
|
|
730
754
|
ActionProposalService = _ts_decorate3([
|
|
731
755
|
Injectable2(),
|
|
@@ -742,6 +766,33 @@ ActionProposalService = _ts_decorate3([
|
|
|
742
766
|
import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK2, AGENT_STORE as AGENT_STORE3, encodeStreamEvent, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
|
|
743
767
|
import { Inject as Inject4, Injectable as Injectable3, Logger, NotImplementedException as NotImplementedException2, Optional as Optional2 } from "@nestjs/common";
|
|
744
768
|
|
|
769
|
+
// src/quota-exceeded.ts
|
|
770
|
+
import { publishAgentQuotaExceeded } from "@dudousxd/nestjs-agent-core";
|
|
771
|
+
function publishQuotaBlocked(actor, report, blocked) {
|
|
772
|
+
const window = report.windows.find((candidate) => candidate.period === blocked.period);
|
|
773
|
+
const payload = {
|
|
774
|
+
actorId: actor.id,
|
|
775
|
+
period: blocked.period,
|
|
776
|
+
...blocked.reason !== void 0 ? {
|
|
777
|
+
reason: blocked.reason
|
|
778
|
+
} : {},
|
|
779
|
+
...window?.usedTokens !== void 0 ? {
|
|
780
|
+
usedTokens: window.usedTokens
|
|
781
|
+
} : {},
|
|
782
|
+
...window?.limitTokens !== void 0 ? {
|
|
783
|
+
limitTokens: window.limitTokens
|
|
784
|
+
} : {},
|
|
785
|
+
...window !== void 0 ? {
|
|
786
|
+
usedUsd: window.usedUsd
|
|
787
|
+
} : {},
|
|
788
|
+
...window?.limitUsd !== void 0 ? {
|
|
789
|
+
limitUsd: window.limitUsd
|
|
790
|
+
} : {}
|
|
791
|
+
};
|
|
792
|
+
publishAgentQuotaExceeded(payload);
|
|
793
|
+
}
|
|
794
|
+
__name(publishQuotaBlocked, "publishQuotaBlocked");
|
|
795
|
+
|
|
745
796
|
// src/thread-persona.ts
|
|
746
797
|
async function threadPersona(store, threadId) {
|
|
747
798
|
const projecting = store;
|
|
@@ -1041,6 +1092,9 @@ var ChatQueueService = class _ChatQueueService {
|
|
|
1041
1092
|
} : {},
|
|
1042
1093
|
...input.uiCapabilities !== void 0 ? {
|
|
1043
1094
|
uiCapabilities: input.uiCapabilities
|
|
1095
|
+
} : {},
|
|
1096
|
+
...input.hostContext !== void 0 ? {
|
|
1097
|
+
hostContext: input.hostContext
|
|
1044
1098
|
} : {}
|
|
1045
1099
|
});
|
|
1046
1100
|
await store.setQueuePause(threadId, {
|
|
@@ -1085,12 +1139,14 @@ var ChatQueueService = class _ChatQueueService {
|
|
|
1085
1139
|
return null;
|
|
1086
1140
|
}
|
|
1087
1141
|
try {
|
|
1088
|
-
const
|
|
1142
|
+
const report = await this.quotaProvider.report({
|
|
1089
1143
|
actor
|
|
1090
1144
|
});
|
|
1145
|
+
const { blocked } = report;
|
|
1091
1146
|
if (blocked === void 0) {
|
|
1092
1147
|
return null;
|
|
1093
1148
|
}
|
|
1149
|
+
publishQuotaBlocked(actor, report, blocked);
|
|
1094
1150
|
return blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`;
|
|
1095
1151
|
} catch {
|
|
1096
1152
|
return null;
|
|
@@ -1124,6 +1180,9 @@ var ChatQueueService = class _ChatQueueService {
|
|
|
1124
1180
|
...message.uiCapabilities !== void 0 ? {
|
|
1125
1181
|
uiCapabilities: message.uiCapabilities
|
|
1126
1182
|
} : {},
|
|
1183
|
+
...message.hostContext !== void 0 ? {
|
|
1184
|
+
hostContext: message.hostContext
|
|
1185
|
+
} : {},
|
|
1127
1186
|
...message.model !== void 0 ? {
|
|
1128
1187
|
model: message.model
|
|
1129
1188
|
} : {}
|
|
@@ -1292,6 +1351,21 @@ var AgentService = class {
|
|
|
1292
1351
|
this.queue = queue;
|
|
1293
1352
|
this.proposals = proposals;
|
|
1294
1353
|
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Decide one independent proposal through the scoped proposal service — what the native
|
|
1356
|
+
* `action-proposals/:id/approve|reject` routes call — and the reply to show for it. `404` when
|
|
1357
|
+
* proposals are not on, `403`/`404` when this actor may not decide it.
|
|
1358
|
+
*/
|
|
1359
|
+
async decideActionProposal(actor, threadId, proposalId, command) {
|
|
1360
|
+
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) {
|
|
1361
|
+
throw new NotFoundException2("Proposal not found");
|
|
1362
|
+
}
|
|
1363
|
+
const result = await this.proposals.decide(threadId, proposalId, actor, command);
|
|
1364
|
+
return {
|
|
1365
|
+
proposalDecision: result,
|
|
1366
|
+
text: this.proposals.reply(result, command.decision)
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1295
1369
|
async handleTextDecision(threadId, actor, text) {
|
|
1296
1370
|
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) return {
|
|
1297
1371
|
status: "unmatched"
|
|
@@ -1339,10 +1413,12 @@ var AgentService = class {
|
|
|
1339
1413
|
if (this.options?.quota === void 0 || this.quotaProvider === void 0) {
|
|
1340
1414
|
return;
|
|
1341
1415
|
}
|
|
1342
|
-
const
|
|
1416
|
+
const report = await this.quotaProvider.report({
|
|
1343
1417
|
actor
|
|
1344
1418
|
});
|
|
1419
|
+
const { blocked } = report;
|
|
1345
1420
|
if (blocked !== void 0) {
|
|
1421
|
+
publishQuotaBlocked(actor, report, blocked);
|
|
1346
1422
|
throw new HttpException({
|
|
1347
1423
|
statusCode: HttpStatus.TOO_MANY_REQUESTS,
|
|
1348
1424
|
code: "quota_exceeded",
|
|
@@ -1477,6 +1553,9 @@ var AgentService = class {
|
|
|
1477
1553
|
}
|
|
1478
1554
|
const created = await this.store.createThread({
|
|
1479
1555
|
actor: params.actor,
|
|
1556
|
+
...agentName !== void 0 ? {
|
|
1557
|
+
agentName
|
|
1558
|
+
} : {},
|
|
1480
1559
|
...params.transient === true ? {
|
|
1481
1560
|
transient: true
|
|
1482
1561
|
} : {},
|
|
@@ -1489,7 +1568,7 @@ var AgentService = class {
|
|
|
1489
1568
|
});
|
|
1490
1569
|
threadId = created.id;
|
|
1491
1570
|
} else {
|
|
1492
|
-
await this.assertOwnsThread(params.actor, threadId);
|
|
1571
|
+
if (params.authorized !== true) await this.assertOwnsThread(params.actor, threadId);
|
|
1493
1572
|
if (params.personaId !== void 0) {
|
|
1494
1573
|
await this.pinThreadPersona(threadId, params.personaId);
|
|
1495
1574
|
}
|
|
@@ -1515,6 +1594,9 @@ var AgentService = class {
|
|
|
1515
1594
|
...params.uiCapabilities !== void 0 ? {
|
|
1516
1595
|
uiCapabilities: params.uiCapabilities
|
|
1517
1596
|
} : {},
|
|
1597
|
+
...params.hostContext !== void 0 ? {
|
|
1598
|
+
hostContext: params.hostContext
|
|
1599
|
+
} : {},
|
|
1518
1600
|
...model !== void 0 ? {
|
|
1519
1601
|
model
|
|
1520
1602
|
} : {}
|
|
@@ -1537,7 +1619,7 @@ var AgentService = class {
|
|
|
1537
1619
|
});
|
|
1538
1620
|
}
|
|
1539
1621
|
if (live === null && mode !== "queue") {
|
|
1540
|
-
const runId = crypto.randomUUID();
|
|
1622
|
+
const runId = this.runner.runIdFor?.(input) ?? crypto.randomUUID();
|
|
1541
1623
|
if (await queue.queueStore().claimActiveStream(threadId, runId, stale !== null ? {
|
|
1542
1624
|
replacing: stale
|
|
1543
1625
|
} : {})) {
|
|
@@ -1605,6 +1687,9 @@ var AgentService = class {
|
|
|
1605
1687
|
...input.uiCapabilities !== void 0 ? {
|
|
1606
1688
|
uiCapabilities: input.uiCapabilities
|
|
1607
1689
|
} : {},
|
|
1690
|
+
...input.hostContext !== void 0 ? {
|
|
1691
|
+
hostContext: input.hostContext
|
|
1692
|
+
} : {},
|
|
1608
1693
|
...interrupting !== void 0 ? {
|
|
1609
1694
|
interrupt: true,
|
|
1610
1695
|
at: "head"
|
|
@@ -4633,6 +4718,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
|
4633
4718
|
} : {}
|
|
4634
4719
|
}, {
|
|
4635
4720
|
execute: /* @__PURE__ */ __name((input, ctx) => instance.execute(input, ctx), "execute"),
|
|
4721
|
+
...typeof handler.present === "function" ? {
|
|
4722
|
+
present: /* @__PURE__ */ __name((output, ctx) => instance.present(output, ctx), "present")
|
|
4723
|
+
} : {},
|
|
4636
4724
|
...typeof handler.preflight === "function" ? {
|
|
4637
4725
|
preflight: /* @__PURE__ */ __name((input, ctx, options) => instance.preflight(input, ctx, options), "preflight")
|
|
4638
4726
|
} : {},
|
|
@@ -5746,15 +5834,15 @@ function _ts_decorate26(decorators, target, key, desc) {
|
|
|
5746
5834
|
__name(_ts_decorate26, "_ts_decorate");
|
|
5747
5835
|
var DEFAULT_PATH = "agent";
|
|
5748
5836
|
var logger = new Logger7("AgentModule");
|
|
5749
|
-
function
|
|
5837
|
+
function externalWrapper(modules, token) {
|
|
5750
5838
|
for (const module of modules.values()) {
|
|
5751
5839
|
if (module.metatype === AgentModule) continue;
|
|
5752
|
-
const wrapper = module.providers.get(
|
|
5840
|
+
const wrapper = module.providers.get(token);
|
|
5753
5841
|
if (wrapper !== void 0) return wrapper;
|
|
5754
5842
|
}
|
|
5755
5843
|
return void 0;
|
|
5756
5844
|
}
|
|
5757
|
-
__name(
|
|
5845
|
+
__name(externalWrapper, "externalWrapper");
|
|
5758
5846
|
function forwardingStore(wrapper) {
|
|
5759
5847
|
const target = /* @__PURE__ */ __name(() => {
|
|
5760
5848
|
const instance = wrapper.instance;
|
|
@@ -5777,23 +5865,47 @@ function forwardingStore(wrapper) {
|
|
|
5777
5865
|
__name(forwardingStore, "forwardingStore");
|
|
5778
5866
|
function resolveStore(options, modules) {
|
|
5779
5867
|
if (options.store !== void 0) return options.store;
|
|
5780
|
-
const external =
|
|
5868
|
+
const external = externalWrapper(modules, AGENT_STORE7);
|
|
5781
5869
|
if (external !== void 0) return forwardingStore(external);
|
|
5782
5870
|
logger.warn("No `store` configured and no store module imported \u2014 using the in-memory store. Threads are lost on restart and not shared between processes: not for production. Pass `store`, or import a store module (e.g. MikroOrmAgentStoreModule.forFeature()).");
|
|
5783
5871
|
return new InMemoryAgentStore();
|
|
5784
5872
|
}
|
|
5785
5873
|
__name(resolveStore, "resolveStore");
|
|
5874
|
+
function resolveRolesPolicy(options, modules) {
|
|
5875
|
+
const external = externalWrapper(modules, AGENT_ROLES_POLICY2);
|
|
5876
|
+
if (options.rolesPolicy !== void 0) {
|
|
5877
|
+
if (external !== void 0) {
|
|
5878
|
+
logger.warn("Both a `rolesPolicy` option and a module binding AGENT_ROLES_POLICY (e.g. AgentAuthzModule) are configured \u2014 the `rolesPolicy` option wins.");
|
|
5879
|
+
}
|
|
5880
|
+
return options.rolesPolicy;
|
|
5881
|
+
}
|
|
5882
|
+
if (external !== void 0) return forwardingPolicy(external);
|
|
5883
|
+
return options.emptyRoles === "deny" ? new ClosedRolesPolicy(options.defaultRoles) : new DefaultRolesPolicy(options.defaultRoles);
|
|
5884
|
+
}
|
|
5885
|
+
__name(resolveRolesPolicy, "resolveRolesPolicy");
|
|
5886
|
+
function forwardingPolicy(wrapper) {
|
|
5887
|
+
return {
|
|
5888
|
+
can(actor, tool) {
|
|
5889
|
+
const policy = wrapper.instance;
|
|
5890
|
+
if (policy === void 0 || policy === null) {
|
|
5891
|
+
throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
|
|
5892
|
+
}
|
|
5893
|
+
return policy.can(actor, tool);
|
|
5894
|
+
}
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
__name(forwardingPolicy, "forwardingPolicy");
|
|
5786
5898
|
function isQuotaProvider(quota) {
|
|
5787
5899
|
return quota !== void 0 && typeof quota.report === "function";
|
|
5788
5900
|
}
|
|
5789
5901
|
__name(isQuotaProvider, "isQuotaProvider");
|
|
5790
5902
|
function resolveCatalog(options) {
|
|
5791
5903
|
if (options.models !== void 0) return options.models;
|
|
5792
|
-
const carried = options.model
|
|
5904
|
+
const carried = options.model?.catalog;
|
|
5793
5905
|
return carried !== void 0 && typeof carried.list === "function" ? carried : void 0;
|
|
5794
5906
|
}
|
|
5795
5907
|
__name(resolveCatalog, "resolveCatalog");
|
|
5796
|
-
function sharedProviders(durable) {
|
|
5908
|
+
function sharedProviders(durable, engine) {
|
|
5797
5909
|
const providers = [
|
|
5798
5910
|
{
|
|
5799
5911
|
provide: AGENT_TOOL_REGISTRY3,
|
|
@@ -5844,9 +5956,10 @@ function sharedProviders(durable) {
|
|
|
5844
5956
|
},
|
|
5845
5957
|
{
|
|
5846
5958
|
provide: AGENT_ROLES_POLICY2,
|
|
5847
|
-
useFactory: /* @__PURE__ */ __name((options) =>
|
|
5959
|
+
useFactory: /* @__PURE__ */ __name((options, modules) => resolveRolesPolicy(options, modules), "useFactory"),
|
|
5848
5960
|
inject: [
|
|
5849
|
-
AGENT_OPTIONS9
|
|
5961
|
+
AGENT_OPTIONS9,
|
|
5962
|
+
ModulesContainer
|
|
5850
5963
|
]
|
|
5851
5964
|
},
|
|
5852
5965
|
{
|
|
@@ -5923,7 +6036,12 @@ function sharedProviders(durable) {
|
|
|
5923
6036
|
ModulesContainer
|
|
5924
6037
|
]
|
|
5925
6038
|
});
|
|
5926
|
-
if (
|
|
6039
|
+
if (engine !== void 0) {
|
|
6040
|
+
providers.push(...engine.providers, {
|
|
6041
|
+
provide: AGENT_RUNNER2,
|
|
6042
|
+
useExisting: engine.runner
|
|
6043
|
+
});
|
|
6044
|
+
} else if (durable) {
|
|
5927
6045
|
providers.push({
|
|
5928
6046
|
provide: AGENT_RUNNER2,
|
|
5929
6047
|
useFactory: /* @__PURE__ */ __name((durableRunner) => {
|
|
@@ -5948,8 +6066,9 @@ function sharedProviders(durable) {
|
|
|
5948
6066
|
return providers;
|
|
5949
6067
|
}
|
|
5950
6068
|
__name(sharedProviders, "sharedProviders");
|
|
5951
|
-
function exportsFor() {
|
|
6069
|
+
function exportsFor(engine) {
|
|
5952
6070
|
return [
|
|
6071
|
+
...engine?.exports ?? [],
|
|
5953
6072
|
AGENT_OPTIONS9,
|
|
5954
6073
|
AGENT_TOOL_REGISTRY3,
|
|
5955
6074
|
AGENT_REGISTRY6,
|
|
@@ -5999,10 +6118,11 @@ function adapterProviders(adapters) {
|
|
|
5999
6118
|
return (adapters ?? []).flatMap((adapter) => adapter.providers ?? []);
|
|
6000
6119
|
}
|
|
6001
6120
|
__name(adapterProviders, "adapterProviders");
|
|
6002
|
-
function controllersForSurface(surface, adapters) {
|
|
6121
|
+
function controllersForSurface(surface, adapters, engine) {
|
|
6003
6122
|
return surface === "engine" ? [] : [
|
|
6004
6123
|
...BASE_CONTROLLERS,
|
|
6005
|
-
...adapterControllers(adapters)
|
|
6124
|
+
...adapterControllers(adapters),
|
|
6125
|
+
...engine?.controllers ?? []
|
|
6006
6126
|
];
|
|
6007
6127
|
}
|
|
6008
6128
|
__name(controllersForSurface, "controllersForSurface");
|
|
@@ -6032,12 +6152,22 @@ function routerFor(path) {
|
|
|
6032
6152
|
]);
|
|
6033
6153
|
}
|
|
6034
6154
|
__name(routerFor, "routerFor");
|
|
6155
|
+
function assertRunnable(options) {
|
|
6156
|
+
if (options.engine !== void 0 && options.durable === true) {
|
|
6157
|
+
throw new Error(`AgentModule: \`durable: true\` runs turns on the library's loop, but the \`${options.engine.name}\` engine runs them instead. Drop \`durable\` (the engine decides how its turns survive a restart).`);
|
|
6158
|
+
}
|
|
6159
|
+
if (options.engine === void 0 && options.model === void 0) {
|
|
6160
|
+
throw new Error("AgentModule: set `model` (the loop runs the turns) or `engine` (something else does).");
|
|
6161
|
+
}
|
|
6162
|
+
}
|
|
6163
|
+
__name(assertRunnable, "assertRunnable");
|
|
6035
6164
|
var AgentModule = class _AgentModule {
|
|
6036
6165
|
static {
|
|
6037
6166
|
__name(this, "AgentModule");
|
|
6038
6167
|
}
|
|
6039
6168
|
static forRoot(options) {
|
|
6040
6169
|
const path = options.path ?? DEFAULT_PATH;
|
|
6170
|
+
assertRunnable(options);
|
|
6041
6171
|
applyGuards(options.guards, options.adapters);
|
|
6042
6172
|
return {
|
|
6043
6173
|
module: _AgentModule,
|
|
@@ -6046,21 +6176,27 @@ var AgentModule = class _AgentModule {
|
|
|
6046
6176
|
DiscoveryModule,
|
|
6047
6177
|
routerFor(path)
|
|
6048
6178
|
],
|
|
6049
|
-
controllers: controllersForSurface(options.surface, options.adapters),
|
|
6179
|
+
controllers: controllersForSurface(options.surface, options.adapters, options.engine),
|
|
6050
6180
|
providers: [
|
|
6051
6181
|
{
|
|
6052
6182
|
provide: AGENT_OPTIONS9,
|
|
6053
6183
|
useValue: options
|
|
6054
6184
|
},
|
|
6055
|
-
...sharedProviders(options.durable ?? false),
|
|
6185
|
+
...sharedProviders(options.durable ?? false, options.engine),
|
|
6056
6186
|
...guardProviders(options.guards),
|
|
6057
6187
|
...adapterProviders(options.adapters)
|
|
6058
6188
|
],
|
|
6059
|
-
exports: exportsFor()
|
|
6189
|
+
exports: exportsFor(options.engine)
|
|
6060
6190
|
};
|
|
6061
6191
|
}
|
|
6062
6192
|
static forRootAsync(options) {
|
|
6063
6193
|
const path = options.path ?? DEFAULT_PATH;
|
|
6194
|
+
if (options.engine !== void 0) {
|
|
6195
|
+
assertRunnable({
|
|
6196
|
+
engine: options.engine,
|
|
6197
|
+
durable: options.durable ?? false
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6064
6200
|
applyGuards(options.guards, options.adapters);
|
|
6065
6201
|
return {
|
|
6066
6202
|
module: _AgentModule,
|
|
@@ -6070,7 +6206,7 @@ var AgentModule = class _AgentModule {
|
|
|
6070
6206
|
routerFor(path),
|
|
6071
6207
|
...options.imports ?? []
|
|
6072
6208
|
],
|
|
6073
|
-
controllers: controllersForSurface(options.surface, options.adapters),
|
|
6209
|
+
controllers: controllersForSurface(options.surface, options.adapters, options.engine),
|
|
6074
6210
|
providers: [
|
|
6075
6211
|
{
|
|
6076
6212
|
provide: AGENT_OPTIONS9,
|
|
@@ -6080,18 +6216,25 @@ var AgentModule = class _AgentModule {
|
|
|
6080
6216
|
// anything today (AgentDurableModule takes its own mirror option — see its doc for why),
|
|
6081
6217
|
// but it's stamped here too so the EFFECTIVE value is always observable off
|
|
6082
6218
|
// AGENT_OPTIONS, sync or async alike.
|
|
6083
|
-
useFactory: /* @__PURE__ */ __name(async (...args) =>
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6219
|
+
useFactory: /* @__PURE__ */ __name(async (...args) => {
|
|
6220
|
+
const resolved = {
|
|
6221
|
+
...await options.useFactory(...args),
|
|
6222
|
+
durable: options.durable ?? false,
|
|
6223
|
+
surface: options.surface ?? "both",
|
|
6224
|
+
...options.engine !== void 0 ? {
|
|
6225
|
+
engine: options.engine
|
|
6226
|
+
} : {}
|
|
6227
|
+
};
|
|
6228
|
+
assertRunnable(resolved);
|
|
6229
|
+
return resolved;
|
|
6230
|
+
}, "useFactory"),
|
|
6088
6231
|
inject: options.inject ?? []
|
|
6089
6232
|
},
|
|
6090
|
-
...sharedProviders(options.durable ?? false),
|
|
6233
|
+
...sharedProviders(options.durable ?? false, options.engine),
|
|
6091
6234
|
...guardProviders(options.guards),
|
|
6092
6235
|
...adapterProviders(options.adapters)
|
|
6093
6236
|
],
|
|
6094
|
-
exports: exportsFor()
|
|
6237
|
+
exports: exportsFor(options.engine)
|
|
6095
6238
|
};
|
|
6096
6239
|
}
|
|
6097
6240
|
};
|
|
@@ -6188,6 +6331,19 @@ var AgUiRunHandler = class {
|
|
|
6188
6331
|
warnings.push(`The resume entry ${id} answers an interrupt this agent did not raise.`);
|
|
6189
6332
|
}
|
|
6190
6333
|
const first = plan.decisions[0];
|
|
6334
|
+
if (first !== void 0 && plan.decisions.every((d) => d.address.kind === "proposal")) {
|
|
6335
|
+
const decided = await this.decideProposals(actor, plan.decisions);
|
|
6336
|
+
this.writeEvents(res, [
|
|
6337
|
+
...warningEvents(warnings),
|
|
6338
|
+
...decided.flatMap((outcome, index) => actionProposalDecisionEvents({
|
|
6339
|
+
threadId: input.threadId,
|
|
6340
|
+
runId: index === 0 ? input.runId : `${input.runId}:${index}`,
|
|
6341
|
+
text: outcome.text,
|
|
6342
|
+
proposalDecision: outcome.proposalDecision
|
|
6343
|
+
}))
|
|
6344
|
+
]);
|
|
6345
|
+
return;
|
|
6346
|
+
}
|
|
6191
6347
|
if (first !== void 0) {
|
|
6192
6348
|
const streamRunId = first.address.stream;
|
|
6193
6349
|
await this.agent.assertResumable(actor, streamRunId);
|
|
@@ -6216,11 +6372,7 @@ var AgUiRunHandler = class {
|
|
|
6216
6372
|
if (owner !== null && turn.media.length === 0) {
|
|
6217
6373
|
const decision = await this.agent.handleTextDecision(input.threadId, actor, turn.text);
|
|
6218
6374
|
if ("proposalDecision" in decision) {
|
|
6219
|
-
|
|
6220
|
-
res.setHeader("Content-Type", "text/event-stream");
|
|
6221
|
-
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
6222
|
-
res.flushHeaders();
|
|
6223
|
-
for (const event of [
|
|
6375
|
+
this.writeEvents(res, [
|
|
6224
6376
|
...warningEvents(warnings),
|
|
6225
6377
|
...actionProposalDecisionEvents({
|
|
6226
6378
|
threadId: input.threadId,
|
|
@@ -6228,8 +6380,7 @@ var AgUiRunHandler = class {
|
|
|
6228
6380
|
text: decision.text,
|
|
6229
6381
|
proposalDecision: decision.proposalDecision
|
|
6230
6382
|
})
|
|
6231
|
-
])
|
|
6232
|
-
res.end();
|
|
6383
|
+
]);
|
|
6233
6384
|
return;
|
|
6234
6385
|
}
|
|
6235
6386
|
}
|
|
@@ -6321,9 +6472,11 @@ var AgUiRunHandler = class {
|
|
|
6321
6472
|
*/
|
|
6322
6473
|
async settle(actor, decisions) {
|
|
6323
6474
|
const deliveries = [];
|
|
6475
|
+
const proposals = decisions.filter((decision) => decision.address.kind === "proposal");
|
|
6324
6476
|
for (const { address, entry } of decisions) {
|
|
6325
6477
|
const { toolCallId: toolCallId2 } = address;
|
|
6326
6478
|
const abandoned = entry.status === "cancelled";
|
|
6479
|
+
if (address.kind === "proposal") continue;
|
|
6327
6480
|
if (address.kind === "approval") {
|
|
6328
6481
|
await this.agent.checkDecision(actor, toolCallId2);
|
|
6329
6482
|
const decision = abandoned ? {
|
|
@@ -6360,9 +6513,53 @@ var AgUiRunHandler = class {
|
|
|
6360
6513
|
via: AG_UI_VIA
|
|
6361
6514
|
}));
|
|
6362
6515
|
}
|
|
6516
|
+
if (proposals.length > 0) await this.decideProposals(actor, proposals);
|
|
6363
6517
|
for (const deliver of deliveries) await deliver();
|
|
6364
6518
|
}
|
|
6365
6519
|
/**
|
|
6520
|
+
* Decide independent proposals through the proposal service — the call the native
|
|
6521
|
+
* `action-proposals/:id/approve|reject` routes make — never by signalling the origin run, which
|
|
6522
|
+
* is not waiting. Every payload is checked before the first decision; a refusal is the service's
|
|
6523
|
+
* own `403`/`404`.
|
|
6524
|
+
*/
|
|
6525
|
+
async decideProposals(actor, decisions) {
|
|
6526
|
+
const planned = decisions.map(({ address, entry }) => {
|
|
6527
|
+
const decision = entry.status === "cancelled" ? {
|
|
6528
|
+
approved: false
|
|
6529
|
+
} : readApprovalPayload(entry.payload);
|
|
6530
|
+
if (decision === null || address.proposalId === void 0 || address.threadId === void 0) {
|
|
6531
|
+
throw invalid("invalid_resume", "an approval is answered with { approved: boolean, reason?, remember? }");
|
|
6532
|
+
}
|
|
6533
|
+
return {
|
|
6534
|
+
address,
|
|
6535
|
+
decision
|
|
6536
|
+
};
|
|
6537
|
+
});
|
|
6538
|
+
const outcomes = [];
|
|
6539
|
+
for (const { address, decision } of planned) {
|
|
6540
|
+
outcomes.push(await this.agent.decideActionProposal(actor, address.threadId, address.proposalId, {
|
|
6541
|
+
decision: decision.approved ? "approved" : "rejected",
|
|
6542
|
+
via: AG_UI_VIA,
|
|
6543
|
+
...decision.remember !== void 0 ? {
|
|
6544
|
+
remember: decision.remember
|
|
6545
|
+
} : {},
|
|
6546
|
+
...decision.reason !== void 0 ? {
|
|
6547
|
+
reason: decision.reason
|
|
6548
|
+
} : {}
|
|
6549
|
+
}));
|
|
6550
|
+
}
|
|
6551
|
+
return outcomes;
|
|
6552
|
+
}
|
|
6553
|
+
/** Answer with a complete list of events, no run behind them. */
|
|
6554
|
+
writeEvents(res, events) {
|
|
6555
|
+
res.status(200);
|
|
6556
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
6557
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
6558
|
+
res.flushHeaders();
|
|
6559
|
+
for (const event of events) res.write(agUiSse(event));
|
|
6560
|
+
res.end();
|
|
6561
|
+
}
|
|
6562
|
+
/**
|
|
6366
6563
|
* Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
|
|
6367
6564
|
* to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
|
|
6368
6565
|
* and the request that answers re-attaches to it.
|
|
@@ -6569,6 +6766,7 @@ export {
|
|
|
6569
6766
|
attachmentLimits,
|
|
6570
6767
|
declaredSkillProvider,
|
|
6571
6768
|
defaultRequestUserMapper,
|
|
6769
|
+
defineTool,
|
|
6572
6770
|
delegateToolName,
|
|
6573
6771
|
provideAgentTool,
|
|
6574
6772
|
provideAgentTools,
|