@dudousxd/nestjs-agent 1.21.0 → 1.22.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-CTyX_yNr.d.ts} +33 -2
- package/dist/{chat-queue.service-CGsR40Ct.d.cts → chat-queue.service-Dx9OsjcF.d.cts} +33 -2
- package/dist/durable/index.cjs +334 -237
- 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 +122 -25
- 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 +404 -250
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -14
- package/dist/index.d.ts +43 -14
- package/dist/index.js +185 -32
- 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;
|
|
@@ -1085,12 +1136,14 @@ var ChatQueueService = class _ChatQueueService {
|
|
|
1085
1136
|
return null;
|
|
1086
1137
|
}
|
|
1087
1138
|
try {
|
|
1088
|
-
const
|
|
1139
|
+
const report = await this.quotaProvider.report({
|
|
1089
1140
|
actor
|
|
1090
1141
|
});
|
|
1142
|
+
const { blocked } = report;
|
|
1091
1143
|
if (blocked === void 0) {
|
|
1092
1144
|
return null;
|
|
1093
1145
|
}
|
|
1146
|
+
publishQuotaBlocked(actor, report, blocked);
|
|
1094
1147
|
return blocked.reason ?? `The ${blocked.period === "day" ? "daily" : "monthly"} quota is used up`;
|
|
1095
1148
|
} catch {
|
|
1096
1149
|
return null;
|
|
@@ -1292,6 +1345,21 @@ var AgentService = class {
|
|
|
1292
1345
|
this.queue = queue;
|
|
1293
1346
|
this.proposals = proposals;
|
|
1294
1347
|
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Decide one independent proposal through the scoped proposal service — what the native
|
|
1350
|
+
* `action-proposals/:id/approve|reject` routes call — and the reply to show for it. `404` when
|
|
1351
|
+
* proposals are not on, `403`/`404` when this actor may not decide it.
|
|
1352
|
+
*/
|
|
1353
|
+
async decideActionProposal(actor, threadId, proposalId, command) {
|
|
1354
|
+
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) {
|
|
1355
|
+
throw new NotFoundException2("Proposal not found");
|
|
1356
|
+
}
|
|
1357
|
+
const result = await this.proposals.decide(threadId, proposalId, actor, command);
|
|
1358
|
+
return {
|
|
1359
|
+
proposalDecision: result,
|
|
1360
|
+
text: this.proposals.reply(result, command.decision)
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1295
1363
|
async handleTextDecision(threadId, actor, text) {
|
|
1296
1364
|
if (this.options?.actionApprovalMode !== "independent" || !this.proposals) return {
|
|
1297
1365
|
status: "unmatched"
|
|
@@ -1339,10 +1407,12 @@ var AgentService = class {
|
|
|
1339
1407
|
if (this.options?.quota === void 0 || this.quotaProvider === void 0) {
|
|
1340
1408
|
return;
|
|
1341
1409
|
}
|
|
1342
|
-
const
|
|
1410
|
+
const report = await this.quotaProvider.report({
|
|
1343
1411
|
actor
|
|
1344
1412
|
});
|
|
1413
|
+
const { blocked } = report;
|
|
1345
1414
|
if (blocked !== void 0) {
|
|
1415
|
+
publishQuotaBlocked(actor, report, blocked);
|
|
1346
1416
|
throw new HttpException({
|
|
1347
1417
|
statusCode: HttpStatus.TOO_MANY_REQUESTS,
|
|
1348
1418
|
code: "quota_exceeded",
|
|
@@ -4633,6 +4703,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
|
4633
4703
|
} : {}
|
|
4634
4704
|
}, {
|
|
4635
4705
|
execute: /* @__PURE__ */ __name((input, ctx) => instance.execute(input, ctx), "execute"),
|
|
4706
|
+
...typeof handler.present === "function" ? {
|
|
4707
|
+
present: /* @__PURE__ */ __name((output, ctx) => instance.present(output, ctx), "present")
|
|
4708
|
+
} : {},
|
|
4636
4709
|
...typeof handler.preflight === "function" ? {
|
|
4637
4710
|
preflight: /* @__PURE__ */ __name((input, ctx, options) => instance.preflight(input, ctx, options), "preflight")
|
|
4638
4711
|
} : {},
|
|
@@ -5746,15 +5819,15 @@ function _ts_decorate26(decorators, target, key, desc) {
|
|
|
5746
5819
|
__name(_ts_decorate26, "_ts_decorate");
|
|
5747
5820
|
var DEFAULT_PATH = "agent";
|
|
5748
5821
|
var logger = new Logger7("AgentModule");
|
|
5749
|
-
function
|
|
5822
|
+
function externalWrapper(modules, token) {
|
|
5750
5823
|
for (const module of modules.values()) {
|
|
5751
5824
|
if (module.metatype === AgentModule) continue;
|
|
5752
|
-
const wrapper = module.providers.get(
|
|
5825
|
+
const wrapper = module.providers.get(token);
|
|
5753
5826
|
if (wrapper !== void 0) return wrapper;
|
|
5754
5827
|
}
|
|
5755
5828
|
return void 0;
|
|
5756
5829
|
}
|
|
5757
|
-
__name(
|
|
5830
|
+
__name(externalWrapper, "externalWrapper");
|
|
5758
5831
|
function forwardingStore(wrapper) {
|
|
5759
5832
|
const target = /* @__PURE__ */ __name(() => {
|
|
5760
5833
|
const instance = wrapper.instance;
|
|
@@ -5777,12 +5850,36 @@ function forwardingStore(wrapper) {
|
|
|
5777
5850
|
__name(forwardingStore, "forwardingStore");
|
|
5778
5851
|
function resolveStore(options, modules) {
|
|
5779
5852
|
if (options.store !== void 0) return options.store;
|
|
5780
|
-
const external =
|
|
5853
|
+
const external = externalWrapper(modules, AGENT_STORE7);
|
|
5781
5854
|
if (external !== void 0) return forwardingStore(external);
|
|
5782
5855
|
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
5856
|
return new InMemoryAgentStore();
|
|
5784
5857
|
}
|
|
5785
5858
|
__name(resolveStore, "resolveStore");
|
|
5859
|
+
function resolveRolesPolicy(options, modules) {
|
|
5860
|
+
const external = externalWrapper(modules, AGENT_ROLES_POLICY2);
|
|
5861
|
+
if (options.rolesPolicy !== void 0) {
|
|
5862
|
+
if (external !== void 0) {
|
|
5863
|
+
logger.warn("Both a `rolesPolicy` option and a module binding AGENT_ROLES_POLICY (e.g. AgentAuthzModule) are configured \u2014 the `rolesPolicy` option wins.");
|
|
5864
|
+
}
|
|
5865
|
+
return options.rolesPolicy;
|
|
5866
|
+
}
|
|
5867
|
+
if (external !== void 0) return forwardingPolicy(external);
|
|
5868
|
+
return options.emptyRoles === "deny" ? new ClosedRolesPolicy(options.defaultRoles) : new DefaultRolesPolicy(options.defaultRoles);
|
|
5869
|
+
}
|
|
5870
|
+
__name(resolveRolesPolicy, "resolveRolesPolicy");
|
|
5871
|
+
function forwardingPolicy(wrapper) {
|
|
5872
|
+
return {
|
|
5873
|
+
can(actor, tool) {
|
|
5874
|
+
const policy = wrapper.instance;
|
|
5875
|
+
if (policy === void 0 || policy === null) {
|
|
5876
|
+
throw new Error("AgentModule: the AGENT_ROLES_POLICY bound by another module is not ready yet");
|
|
5877
|
+
}
|
|
5878
|
+
return policy.can(actor, tool);
|
|
5879
|
+
}
|
|
5880
|
+
};
|
|
5881
|
+
}
|
|
5882
|
+
__name(forwardingPolicy, "forwardingPolicy");
|
|
5786
5883
|
function isQuotaProvider(quota) {
|
|
5787
5884
|
return quota !== void 0 && typeof quota.report === "function";
|
|
5788
5885
|
}
|
|
@@ -5844,9 +5941,10 @@ function sharedProviders(durable) {
|
|
|
5844
5941
|
},
|
|
5845
5942
|
{
|
|
5846
5943
|
provide: AGENT_ROLES_POLICY2,
|
|
5847
|
-
useFactory: /* @__PURE__ */ __name((options) =>
|
|
5944
|
+
useFactory: /* @__PURE__ */ __name((options, modules) => resolveRolesPolicy(options, modules), "useFactory"),
|
|
5848
5945
|
inject: [
|
|
5849
|
-
AGENT_OPTIONS9
|
|
5946
|
+
AGENT_OPTIONS9,
|
|
5947
|
+
ModulesContainer
|
|
5850
5948
|
]
|
|
5851
5949
|
},
|
|
5852
5950
|
{
|
|
@@ -6188,6 +6286,19 @@ var AgUiRunHandler = class {
|
|
|
6188
6286
|
warnings.push(`The resume entry ${id} answers an interrupt this agent did not raise.`);
|
|
6189
6287
|
}
|
|
6190
6288
|
const first = plan.decisions[0];
|
|
6289
|
+
if (first !== void 0 && plan.decisions.every((d) => d.address.kind === "proposal")) {
|
|
6290
|
+
const decided = await this.decideProposals(actor, plan.decisions);
|
|
6291
|
+
this.writeEvents(res, [
|
|
6292
|
+
...warningEvents(warnings),
|
|
6293
|
+
...decided.flatMap((outcome, index) => actionProposalDecisionEvents({
|
|
6294
|
+
threadId: input.threadId,
|
|
6295
|
+
runId: index === 0 ? input.runId : `${input.runId}:${index}`,
|
|
6296
|
+
text: outcome.text,
|
|
6297
|
+
proposalDecision: outcome.proposalDecision
|
|
6298
|
+
}))
|
|
6299
|
+
]);
|
|
6300
|
+
return;
|
|
6301
|
+
}
|
|
6191
6302
|
if (first !== void 0) {
|
|
6192
6303
|
const streamRunId = first.address.stream;
|
|
6193
6304
|
await this.agent.assertResumable(actor, streamRunId);
|
|
@@ -6216,11 +6327,7 @@ var AgUiRunHandler = class {
|
|
|
6216
6327
|
if (owner !== null && turn.media.length === 0) {
|
|
6217
6328
|
const decision = await this.agent.handleTextDecision(input.threadId, actor, turn.text);
|
|
6218
6329
|
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 [
|
|
6330
|
+
this.writeEvents(res, [
|
|
6224
6331
|
...warningEvents(warnings),
|
|
6225
6332
|
...actionProposalDecisionEvents({
|
|
6226
6333
|
threadId: input.threadId,
|
|
@@ -6228,8 +6335,7 @@ var AgUiRunHandler = class {
|
|
|
6228
6335
|
text: decision.text,
|
|
6229
6336
|
proposalDecision: decision.proposalDecision
|
|
6230
6337
|
})
|
|
6231
|
-
])
|
|
6232
|
-
res.end();
|
|
6338
|
+
]);
|
|
6233
6339
|
return;
|
|
6234
6340
|
}
|
|
6235
6341
|
}
|
|
@@ -6321,9 +6427,11 @@ var AgUiRunHandler = class {
|
|
|
6321
6427
|
*/
|
|
6322
6428
|
async settle(actor, decisions) {
|
|
6323
6429
|
const deliveries = [];
|
|
6430
|
+
const proposals = decisions.filter((decision) => decision.address.kind === "proposal");
|
|
6324
6431
|
for (const { address, entry } of decisions) {
|
|
6325
6432
|
const { toolCallId: toolCallId2 } = address;
|
|
6326
6433
|
const abandoned = entry.status === "cancelled";
|
|
6434
|
+
if (address.kind === "proposal") continue;
|
|
6327
6435
|
if (address.kind === "approval") {
|
|
6328
6436
|
await this.agent.checkDecision(actor, toolCallId2);
|
|
6329
6437
|
const decision = abandoned ? {
|
|
@@ -6360,9 +6468,53 @@ var AgUiRunHandler = class {
|
|
|
6360
6468
|
via: AG_UI_VIA
|
|
6361
6469
|
}));
|
|
6362
6470
|
}
|
|
6471
|
+
if (proposals.length > 0) await this.decideProposals(actor, proposals);
|
|
6363
6472
|
for (const deliver of deliveries) await deliver();
|
|
6364
6473
|
}
|
|
6365
6474
|
/**
|
|
6475
|
+
* Decide independent proposals through the proposal service — the call the native
|
|
6476
|
+
* `action-proposals/:id/approve|reject` routes make — never by signalling the origin run, which
|
|
6477
|
+
* is not waiting. Every payload is checked before the first decision; a refusal is the service's
|
|
6478
|
+
* own `403`/`404`.
|
|
6479
|
+
*/
|
|
6480
|
+
async decideProposals(actor, decisions) {
|
|
6481
|
+
const planned = decisions.map(({ address, entry }) => {
|
|
6482
|
+
const decision = entry.status === "cancelled" ? {
|
|
6483
|
+
approved: false
|
|
6484
|
+
} : readApprovalPayload(entry.payload);
|
|
6485
|
+
if (decision === null || address.proposalId === void 0 || address.threadId === void 0) {
|
|
6486
|
+
throw invalid("invalid_resume", "an approval is answered with { approved: boolean, reason?, remember? }");
|
|
6487
|
+
}
|
|
6488
|
+
return {
|
|
6489
|
+
address,
|
|
6490
|
+
decision
|
|
6491
|
+
};
|
|
6492
|
+
});
|
|
6493
|
+
const outcomes = [];
|
|
6494
|
+
for (const { address, decision } of planned) {
|
|
6495
|
+
outcomes.push(await this.agent.decideActionProposal(actor, address.threadId, address.proposalId, {
|
|
6496
|
+
decision: decision.approved ? "approved" : "rejected",
|
|
6497
|
+
via: AG_UI_VIA,
|
|
6498
|
+
...decision.remember !== void 0 ? {
|
|
6499
|
+
remember: decision.remember
|
|
6500
|
+
} : {},
|
|
6501
|
+
...decision.reason !== void 0 ? {
|
|
6502
|
+
reason: decision.reason
|
|
6503
|
+
} : {}
|
|
6504
|
+
}));
|
|
6505
|
+
}
|
|
6506
|
+
return outcomes;
|
|
6507
|
+
}
|
|
6508
|
+
/** Answer with a complete list of events, no run behind them. */
|
|
6509
|
+
writeEvents(res, events) {
|
|
6510
|
+
res.status(200);
|
|
6511
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
6512
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
6513
|
+
res.flushHeaders();
|
|
6514
|
+
for (const event of events) res.write(agUiSse(event));
|
|
6515
|
+
res.end();
|
|
6516
|
+
}
|
|
6517
|
+
/**
|
|
6366
6518
|
* Pipe a run to the client as AG-UI 1.0 over SSE: one event per `data:` line, from `RUN_STARTED`
|
|
6367
6519
|
* to the run's terminal event. It ends when the run stops to ask — the library run stays parked,
|
|
6368
6520
|
* and the request that answers re-attaches to it.
|
|
@@ -6569,6 +6721,7 @@ export {
|
|
|
6569
6721
|
attachmentLimits,
|
|
6570
6722
|
declaredSkillProvider,
|
|
6571
6723
|
defaultRequestUserMapper,
|
|
6724
|
+
defineTool,
|
|
6572
6725
|
delegateToolName,
|
|
6573
6726
|
provideAgentTool,
|
|
6574
6727
|
provideAgentTools,
|