@dudousxd/nestjs-agent 1.19.2 → 1.20.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 +2 -0
- package/dist/{chat-queue.service-CKZkjlMK.d.cts → chat-queue.service-C0hr7dqx.d.cts} +41 -2
- package/dist/{chat-queue.service-CKZkjlMK.d.ts → chat-queue.service-C0hr7dqx.d.ts} +41 -2
- package/dist/durable/index.cjs +424 -32
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +41 -5
- package/dist/durable/index.d.ts +41 -5
- package/dist/durable/index.js +482 -90
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +274 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -4
- package/dist/index.d.ts +50 -4
- package/dist/index.js +327 -68
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/durable/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
3
3
|
|
|
4
4
|
// src/durable/agent-run.workflow.ts
|
|
5
5
|
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY2, AGENT_STORE, RUN_ENDED_BEFORE_TOOL_CALL, RunCancelledError, agentFailureCode, encodeStreamEvent as encodeStreamEvent2, isReplayIntegrityError, publishAgentRunFailed, releaseThreadRun, runAgentLoop, settleAll, settleDeadRun, settleUnsettledDelegation, streamFailure } from "@dudousxd/nestjs-agent-core";
|
|
6
|
-
import { RUN_GATEWAY, Workflow } from "@dudousxd/nestjs-durable";
|
|
6
|
+
import { RUN_GATEWAY, Workflow, WorkflowService } from "@dudousxd/nestjs-durable";
|
|
7
7
|
import { isWorkflowControlFlowSignal } from "@dudousxd/nestjs-durable-core";
|
|
8
8
|
import { Inject as Inject2, Injectable as Injectable2, Logger, Optional } from "@nestjs/common";
|
|
9
9
|
|
|
@@ -33,7 +33,7 @@ __name(childSinkWriter, "childSinkWriter");
|
|
|
33
33
|
var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
|
|
34
34
|
|
|
35
35
|
// src/durable/agent-run.steps.ts
|
|
36
|
-
import { AGENT_DEPS_FACTORY, createFrameBuffer, createUiCollector, encodeStreamEvent, invokeWithTransientRetry, observeTurnFrames, publishAgentToolRetry, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
|
|
36
|
+
import { AGENT_DEPS_FACTORY, createFrameBuffer, createUiCollector, encodeStreamEvent, intersectAllowLists, invokeWithTransientRetry, observeTurnFrames, publishAgentToolRetry, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
|
|
37
37
|
import { Step } from "@dudousxd/nestjs-durable";
|
|
38
38
|
import { Inject, Injectable } from "@nestjs/common";
|
|
39
39
|
|
|
@@ -97,14 +97,21 @@ var AgentRunSteps = class {
|
|
|
97
97
|
const tools = withMemoryTool({
|
|
98
98
|
tools: withSkillTool({
|
|
99
99
|
tools: withAskTool({
|
|
100
|
-
tools: await deps.registry.definitionsFor(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
100
|
+
tools: await deps.registry.definitionsFor(
|
|
101
|
+
input.actor,
|
|
102
|
+
deps.rolesPolicy,
|
|
103
|
+
// The persona narrowing the loop journaled in `persona:resolve` rides the envelope:
|
|
104
|
+
// this worker's own persona config may already say something else.
|
|
105
|
+
intersectAllowLists(deps.toolAllowList, input.personaAllowedTools),
|
|
106
|
+
{
|
|
107
|
+
...input.threadId !== void 0 ? {
|
|
108
|
+
threadId: input.threadId
|
|
109
|
+
} : {},
|
|
110
|
+
...input.agentName !== void 0 ? {
|
|
111
|
+
agentName: input.agentName
|
|
112
|
+
} : {}
|
|
113
|
+
}
|
|
114
|
+
),
|
|
108
115
|
ask: deps.ask
|
|
109
116
|
}),
|
|
110
117
|
enabled: deps.skills !== void 0
|
|
@@ -177,7 +184,9 @@ var AgentRunSteps = class {
|
|
|
177
184
|
toolType: input.toolType
|
|
178
185
|
}, () => invokeWithTransientRetry(() => {
|
|
179
186
|
ui.restart();
|
|
180
|
-
const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy
|
|
187
|
+
const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy, input.allowedTools !== void 0 ? {
|
|
188
|
+
allowedTools: input.allowedTools
|
|
189
|
+
} : {});
|
|
181
190
|
return input.timeoutMs !== void 0 ? withToolTimeout(invocation, input.timeoutMs, input.toolName) : invocation;
|
|
182
191
|
}, transientRetry, {
|
|
183
192
|
onRetry: /* @__PURE__ */ __name((attempt, error) => {
|
|
@@ -254,12 +263,60 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
254
263
|
store;
|
|
255
264
|
runs;
|
|
256
265
|
queue;
|
|
266
|
+
workflows;
|
|
257
267
|
logger = new Logger(_AgentRunWorkflow.name);
|
|
258
|
-
constructor(factory, store, runs, queue) {
|
|
268
|
+
constructor(factory, store, runs, queue, workflows) {
|
|
259
269
|
this.factory = factory;
|
|
260
270
|
this.store = store;
|
|
261
271
|
this.runs = runs;
|
|
262
272
|
this.queue = queue;
|
|
273
|
+
this.workflows = workflows;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Start a detached delegation as a TOP-LEVEL run, under an id derived from this run and the call.
|
|
277
|
+
*
|
|
278
|
+
* Not `ctx.startChild`, because the runtime treats a `spawn:` child as part of its parent: a Stop
|
|
279
|
+
* on the parent cascades to every run it spawned. A detached run is exactly the one the person did
|
|
280
|
+
* NOT ask to stop — they stopped the turn they were watching, and the work it handed off is meant
|
|
281
|
+
* to outlive that turn (it is meant to outlive it finishing, after all). Cascaded, it died parked
|
|
282
|
+
* on its approval, where its body never runs again, so nothing settled the delegation and the card
|
|
283
|
+
* said "started" for ever. The agent-level edge stays: the child's input still carries
|
|
284
|
+
* `parentRunId`, which is what the run rows record.
|
|
285
|
+
*
|
|
286
|
+
* Journaled as one `detach:<toolCallId>` localStep whose body runs outside the ambient workflow
|
|
287
|
+
* ctx (so the start goes to the engine and writes no position in this run). Its recorded result
|
|
288
|
+
* keeps a replay from starting it again, and a body re-run after a crash between the start and
|
|
289
|
+
* the checkpoint asks for the same id, which the runtime answers with the run it already has.
|
|
290
|
+
* The child is stamped with this run's namespace, as `ctx.startChild` would have stamped it, so an
|
|
291
|
+
* operator re-driving a tenant's turn does not move its delegate off that tenant's workers.
|
|
292
|
+
*/
|
|
293
|
+
startDetached(ctx, toolCallId2, childInput) {
|
|
294
|
+
return stepOf(ctx)(`detach:${toolCallId2}`, async () => {
|
|
295
|
+
const workflows = this.workflows;
|
|
296
|
+
if (workflows === void 0) {
|
|
297
|
+
throw new Error("A detached delegation needs WorkflowService (DurableModule) to start its run, and none is bound.");
|
|
298
|
+
}
|
|
299
|
+
const childRunId = `${ctx.runId}.detached.${toolCallId2}`;
|
|
300
|
+
const namespace = await this.namespaceOf(ctx.runId);
|
|
301
|
+
try {
|
|
302
|
+
await workflows.start(_AgentRunWorkflow, childInput, childRunId, namespace !== void 0 ? {
|
|
303
|
+
namespace
|
|
304
|
+
} : void 0);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
if (!isWorkflowControlFlowSignal(error)) {
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return childRunId;
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/** The namespace this run is stamped with, where the runtime can say. */
|
|
314
|
+
async namespaceOf(runId) {
|
|
315
|
+
try {
|
|
316
|
+
return (await this.runs?.getRunDetail(runId))?.run.namespace;
|
|
317
|
+
} catch {
|
|
318
|
+
return void 0;
|
|
319
|
+
}
|
|
263
320
|
}
|
|
264
321
|
/**
|
|
265
322
|
* Move the thread past this settling turn — to the next queued message, started here as a
|
|
@@ -460,6 +517,10 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
460
517
|
// OWN runId, and that is what `runForToolCall` answers with.
|
|
461
518
|
// - `deliverTo` instead. The parent's tool result is a receipt, so the answer needs an
|
|
462
519
|
// address of its own, and by the time it exists nobody is holding one.
|
|
520
|
+
// - no runtime parent. A Stop on this turn must not reach the work it handed off, so the
|
|
521
|
+
// run is started on its own (`startDetached`), not as a `spawn:` child. A run that
|
|
522
|
+
// journaled the `spawn:` before this release replays it: `ctx.patched` answers false at a
|
|
523
|
+
// position that already holds one.
|
|
463
524
|
startAgent: /* @__PURE__ */ __name(async ({ agentName, task, toolCallId: toolCallId2 }) => {
|
|
464
525
|
const subThreadId = await stepOf(ctx)(`subthread:${agentName}`, async () => {
|
|
465
526
|
const thread = await this.store.createThread({
|
|
@@ -468,7 +529,7 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
468
529
|
});
|
|
469
530
|
return thread.id;
|
|
470
531
|
});
|
|
471
|
-
const
|
|
532
|
+
const childInput = {
|
|
472
533
|
agentName,
|
|
473
534
|
threadId: subThreadId,
|
|
474
535
|
actor: input.actor,
|
|
@@ -481,9 +542,14 @@ var AgentRunWorkflow = class _AgentRunWorkflow {
|
|
|
481
542
|
threadId: input.threadId,
|
|
482
543
|
toolCallId: toolCallId2
|
|
483
544
|
}
|
|
484
|
-
}
|
|
545
|
+
};
|
|
546
|
+
if (!await ctx.patched("agent:detached-unlinked")) {
|
|
547
|
+
return {
|
|
548
|
+
runId: await ctx.startChild(_AgentRunWorkflow, childInput)
|
|
549
|
+
};
|
|
550
|
+
}
|
|
485
551
|
return {
|
|
486
|
-
runId:
|
|
552
|
+
runId: await this.startDetached(ctx, toolCallId2, childInput)
|
|
487
553
|
};
|
|
488
554
|
}, "startAgent"),
|
|
489
555
|
// The two long steps as engine-dispatched `ctx.step`s, so a turn isn't pinned to this
|
|
@@ -596,12 +662,14 @@ AgentRunWorkflow = _ts_decorate2([
|
|
|
596
662
|
_ts_param2(2, Inject2(RUN_GATEWAY)),
|
|
597
663
|
_ts_param2(3, Optional()),
|
|
598
664
|
_ts_param2(3, Inject2(AGENT_CHAT_QUEUE)),
|
|
665
|
+
_ts_param2(4, Optional()),
|
|
599
666
|
_ts_metadata2("design:type", Function),
|
|
600
667
|
_ts_metadata2("design:paramtypes", [
|
|
601
668
|
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
602
669
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
603
670
|
typeof RunGateway === "undefined" ? Object : RunGateway,
|
|
604
|
-
typeof ChatQueueService === "undefined" ? Object : ChatQueueService
|
|
671
|
+
typeof ChatQueueService === "undefined" ? Object : ChatQueueService,
|
|
672
|
+
typeof WorkflowService === "undefined" ? Object : WorkflowService
|
|
605
673
|
])
|
|
606
674
|
], AgentRunWorkflow);
|
|
607
675
|
function isSignalTimeout(error) {
|
|
@@ -611,8 +679,8 @@ __name(isSignalTimeout, "isSignalTimeout");
|
|
|
611
679
|
|
|
612
680
|
// src/durable/durable-agent-runner.ts
|
|
613
681
|
import { randomUUID } from "crypto";
|
|
614
|
-
import { AGENT_SINK, AGENT_STORE as AGENT_STORE2, encodeStreamEvent as encodeStreamEvent3, releaseThreadRun as releaseThreadRun2 } from "@dudousxd/nestjs-agent-core";
|
|
615
|
-
import { RUN_GATEWAY as RUN_GATEWAY2, WorkflowService } from "@dudousxd/nestjs-durable";
|
|
682
|
+
import { AGENT_SINK, AGENT_STORE as AGENT_STORE2, encodeStreamEvent as encodeStreamEvent3, releaseThreadRun as releaseThreadRun2, settleUnsettledDelegation as settleUnsettledDelegation2 } from "@dudousxd/nestjs-agent-core";
|
|
683
|
+
import { RUN_GATEWAY as RUN_GATEWAY2, WorkflowService as WorkflowService2 } from "@dudousxd/nestjs-durable";
|
|
616
684
|
import { isWorkflowControlFlowSignal as isWorkflowControlFlowSignal2 } from "@dudousxd/nestjs-durable-core";
|
|
617
685
|
import { Inject as Inject3, Injectable as Injectable3, Logger as Logger2, Optional as Optional2 } from "@nestjs/common";
|
|
618
686
|
|
|
@@ -722,6 +790,20 @@ function isThreadTurn(input) {
|
|
|
722
790
|
return typeof input === "object" && input !== null && input.sinkRunId === void 0 && input.deliverTo === void 0;
|
|
723
791
|
}
|
|
724
792
|
__name(isThreadTurn, "isThreadTurn");
|
|
793
|
+
function deliveryOf(input) {
|
|
794
|
+
if (typeof input !== "object" || input === null) {
|
|
795
|
+
return void 0;
|
|
796
|
+
}
|
|
797
|
+
const { deliverTo, agentName } = input;
|
|
798
|
+
if (typeof deliverTo !== "object" || deliverTo === null || typeof deliverTo.threadId !== "string" || typeof deliverTo.toolCallId !== "string") {
|
|
799
|
+
return void 0;
|
|
800
|
+
}
|
|
801
|
+
return {
|
|
802
|
+
delivery: deliverTo,
|
|
803
|
+
agent: typeof agentName === "string" ? agentName : "default"
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
__name(deliveryOf, "deliveryOf");
|
|
725
807
|
var DurableAgentRunner = class _DurableAgentRunner {
|
|
726
808
|
static {
|
|
727
809
|
__name(this, "DurableAgentRunner");
|
|
@@ -801,11 +883,16 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
801
883
|
*/
|
|
802
884
|
async cancel(runId) {
|
|
803
885
|
this.logger.log(`cancelling agent run ${runId}`);
|
|
804
|
-
const
|
|
886
|
+
const detail = await this.detailOf(runId);
|
|
887
|
+
const input = detail?.run.input;
|
|
805
888
|
const threadId = threadOfRun(input);
|
|
806
889
|
await this.runs.cancel(runId, {
|
|
807
890
|
compensate: true
|
|
808
891
|
});
|
|
892
|
+
await this.settleCancelledDelegation(runId, input);
|
|
893
|
+
for (const childId of detail?.children ?? []) {
|
|
894
|
+
await this.settleCascadedDetached(childId);
|
|
895
|
+
}
|
|
809
896
|
const writer = await this.sink.open(runId);
|
|
810
897
|
if (threadId !== void 0) {
|
|
811
898
|
if (this.queue?.supported === true && isThreadTurn(input)) {
|
|
@@ -836,7 +923,57 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
836
923
|
});
|
|
837
924
|
}
|
|
838
925
|
/**
|
|
839
|
-
*
|
|
926
|
+
* Settle the delegation a DETACHED run was started for, once it has been stopped. A run parked on
|
|
927
|
+
* a human never runs its body again — the runtime settles it from outside — so the body's own
|
|
928
|
+
* `deliver:detached:unsettled` is not reached, and without this the card in the calling thread says
|
|
929
|
+
* "started" for ever. Settles once (see `settleUnsettledDelegation`), so a body that did observe
|
|
930
|
+
* the Stop and a run that had already answered are both left as they are. A no-op for any run
|
|
931
|
+
* that does not deliver into another thread.
|
|
932
|
+
*/
|
|
933
|
+
async settleCancelledDelegation(runId, input) {
|
|
934
|
+
const target = deliveryOf(input);
|
|
935
|
+
if (target === void 0) {
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
try {
|
|
939
|
+
await settleUnsettledDelegation2({
|
|
940
|
+
store: this.store,
|
|
941
|
+
delivery: target.delivery,
|
|
942
|
+
agent: target.agent,
|
|
943
|
+
runId,
|
|
944
|
+
status: "cancelled"
|
|
945
|
+
});
|
|
946
|
+
} catch (error) {
|
|
947
|
+
this.logger.error(`could not settle the delegation of cancelled run ${runId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* A detached child the runtime cancelled along with its parent (a `spawn:` journaled before
|
|
952
|
+
* detached runs were started on their own): end it the way a Stop on its own id would have.
|
|
953
|
+
*/
|
|
954
|
+
async settleCascadedDetached(childId) {
|
|
955
|
+
const child = await this.detailOf(childId);
|
|
956
|
+
const status = child?.run.status;
|
|
957
|
+
if (child === void 0 || deliveryOf(child.run.input) === void 0 || status !== "cancelled" && status !== "cancelling") {
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
const subThreadId = threadOfRun(child.run.input);
|
|
961
|
+
if (subThreadId !== void 0) {
|
|
962
|
+
await releaseThreadRun2(this.store, subThreadId, childId);
|
|
963
|
+
}
|
|
964
|
+
await this.settleCancelledDelegation(childId, child.run.input);
|
|
965
|
+
const writer = await this.sink.open(childId);
|
|
966
|
+
await writer.write(encodeStreamEvent3({
|
|
967
|
+
kind: "cancelled"
|
|
968
|
+
}));
|
|
969
|
+
await writer.end();
|
|
970
|
+
await this.store.recordRunEnd?.({
|
|
971
|
+
runId: childId,
|
|
972
|
+
status: "cancelled"
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* What the runtime recorded for a run — the input it was started with (which thread it was streaming), its status and the runs it spawned — or `undefined` where the gateway cannot say.
|
|
840
977
|
*
|
|
841
978
|
* A read failure answers `undefined` instead of propagating, the same posture `AgentRunWorkflow`
|
|
842
979
|
* takes for its own cancel observation: failing to ask is not an answer worth failing a cancel
|
|
@@ -845,9 +982,9 @@ var DurableAgentRunner = class _DurableAgentRunner {
|
|
|
845
982
|
* with a subscriber holding a stream that never settles, from the one call whose entire job is to
|
|
846
983
|
* make a run stop.
|
|
847
984
|
*/
|
|
848
|
-
async
|
|
985
|
+
async detailOf(runId) {
|
|
849
986
|
try {
|
|
850
|
-
return
|
|
987
|
+
return await this.runs.getRunDetail(runId) ?? void 0;
|
|
851
988
|
} catch {
|
|
852
989
|
return void 0;
|
|
853
990
|
}
|
|
@@ -862,7 +999,7 @@ DurableAgentRunner = _ts_decorate3([
|
|
|
862
999
|
_ts_param3(4, Inject3(AGENT_CHAT_QUEUE)),
|
|
863
1000
|
_ts_metadata3("design:type", Function),
|
|
864
1001
|
_ts_metadata3("design:paramtypes", [
|
|
865
|
-
typeof
|
|
1002
|
+
typeof WorkflowService2 === "undefined" ? Object : WorkflowService2,
|
|
866
1003
|
typeof RunGateway === "undefined" ? Object : RunGateway,
|
|
867
1004
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
868
1005
|
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
@@ -957,14 +1094,14 @@ AgentDurableModule = _ts_decorate4([
|
|
|
957
1094
|
], AgentDurableModule);
|
|
958
1095
|
|
|
959
1096
|
// src/agent.module.ts
|
|
960
|
-
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER13, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as
|
|
1097
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER13, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY8, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS7, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK4, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE7, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
|
|
961
1098
|
import { Global as Global2, Logger as Logger8, Module as Module2 } from "@nestjs/common";
|
|
962
1099
|
import { DiscoveryModule, ModulesContainer, RouterModule } from "@nestjs/core";
|
|
963
1100
|
|
|
964
1101
|
// src/agent-deps.factory.ts
|
|
965
|
-
import { AGENT_MEMORY, AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS, AGENT_STORE as AGENT_STORE3, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2, normalizeDelegation, summarizeWithModel, windowHistory } from "@dudousxd/nestjs-agent-core";
|
|
1102
|
+
import { AGENT_MEMORY, AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS, AGENT_STORE as AGENT_STORE3, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2, findPersona, intersectAllowLists as intersectAllowLists2, normalizeDelegation, personaCatalogEntry, resolvePersonaAlias, summarizeWithModel, windowHistory } from "@dudousxd/nestjs-agent-core";
|
|
966
1103
|
import { AGENT_OPTIONS } from "@dudousxd/nestjs-agent-core";
|
|
967
|
-
import { Inject as Inject4, Injectable as Injectable4, Optional as Optional3 } from "@nestjs/common";
|
|
1104
|
+
import { BadRequestException, Inject as Inject4, Injectable as Injectable4, Optional as Optional3 } from "@nestjs/common";
|
|
968
1105
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
969
1106
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
970
1107
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -1062,8 +1199,64 @@ var AgentDepsFactory2 = class {
|
|
|
1062
1199
|
...delegated
|
|
1063
1200
|
];
|
|
1064
1201
|
}
|
|
1202
|
+
/**
|
|
1203
|
+
* The agent a name stands for: itself when it is a registered agent (or unknown — the bare
|
|
1204
|
+
* assistant), else the agent whose persona took the name over (`Persona.aliases`) and that persona.
|
|
1205
|
+
*/
|
|
1206
|
+
resolveAgent(name) {
|
|
1207
|
+
if (this.agents.has(name)) {
|
|
1208
|
+
return {
|
|
1209
|
+
agentName: name
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
const alias = resolvePersonaAlias(this.agents.list(), name);
|
|
1213
|
+
return alias === void 0 ? {
|
|
1214
|
+
agentName: name
|
|
1215
|
+
} : {
|
|
1216
|
+
agentName: alias.agent,
|
|
1217
|
+
persona: alias.persona
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
/** `agentName`'s personas as a picker reads them. Empty when it declares none. */
|
|
1221
|
+
personaCatalog(agentName) {
|
|
1222
|
+
return (this.agents.get(agentName)?.personas ?? []).map(personaCatalogEntry);
|
|
1223
|
+
}
|
|
1224
|
+
/** The persona `agentName` runs under when nothing names one. Undefined → none. */
|
|
1225
|
+
defaultPersona(agentName) {
|
|
1226
|
+
return this.agents.get(agentName)?.defaultPersona;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* The persona a turn of `agentName` runs under, most specific first: the one the send names
|
|
1230
|
+
* (refused with `400 persona_not_found` when the agent does not declare it), else the thread's
|
|
1231
|
+
* pinned one when this agent declares it, else the agent's default. Undefined → none.
|
|
1232
|
+
*/
|
|
1233
|
+
resolvePersona(args) {
|
|
1234
|
+
const definition = this.agents.get(args.agentName);
|
|
1235
|
+
if (args.requested !== void 0) {
|
|
1236
|
+
if (findPersona(definition, args.requested) === void 0) {
|
|
1237
|
+
throw new BadRequestException({
|
|
1238
|
+
statusCode: 400,
|
|
1239
|
+
code: "persona_not_found",
|
|
1240
|
+
message: `agent "${args.agentName}" has no persona "${args.requested}"`
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
return args.requested;
|
|
1244
|
+
}
|
|
1245
|
+
const pinned = args.threadPersona ?? void 0;
|
|
1246
|
+
if (pinned !== void 0 && findPersona(definition, pinned) !== void 0) {
|
|
1247
|
+
return pinned;
|
|
1248
|
+
}
|
|
1249
|
+
return definition?.defaultPersona;
|
|
1250
|
+
}
|
|
1065
1251
|
forAgent(agentName) {
|
|
1066
1252
|
const name = agentName ?? this.defaultAgentName();
|
|
1253
|
+
if (agentName !== void 0 && !this.agents.has(agentName)) {
|
|
1254
|
+
const alias = resolvePersonaAlias(this.agents.list(), agentName);
|
|
1255
|
+
const persona = alias === void 0 ? void 0 : findPersona(this.agents.get(alias.agent), alias.persona);
|
|
1256
|
+
if (alias !== void 0 && persona !== void 0) {
|
|
1257
|
+
return this.withPersona(this.forAgent(alias.agent), persona);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1067
1260
|
const definition = this.agents.get(name);
|
|
1068
1261
|
const toolAllowList = this.effectiveTools(definition);
|
|
1069
1262
|
const followUpsCount = this.followUpsCount();
|
|
@@ -1128,6 +1321,9 @@ var AgentDepsFactory2 = class {
|
|
|
1128
1321
|
...toolAllowList !== void 0 ? {
|
|
1129
1322
|
toolAllowList
|
|
1130
1323
|
} : {},
|
|
1324
|
+
...definition?.personas !== void 0 ? {
|
|
1325
|
+
personas: definition.personas
|
|
1326
|
+
} : {},
|
|
1131
1327
|
...this.options.toolTimeoutMs !== void 0 ? {
|
|
1132
1328
|
toolTimeoutMs: this.options.toolTimeoutMs
|
|
1133
1329
|
} : {},
|
|
@@ -1146,6 +1342,45 @@ var AgentDepsFactory2 = class {
|
|
|
1146
1342
|
};
|
|
1147
1343
|
}
|
|
1148
1344
|
/**
|
|
1345
|
+
* A persona baked into an agent's deps — how a run journaled under an agent name that a persona
|
|
1346
|
+
* has since taken over (`Persona.aliases`) is served. That run names no persona of its own (it
|
|
1347
|
+
* predates them, and its input cannot change), so the persona applies the way the old agent's own
|
|
1348
|
+
* config did: as config, re-read on every replay, with no checkpoint of its own.
|
|
1349
|
+
*/
|
|
1350
|
+
withPersona(deps, persona) {
|
|
1351
|
+
const base = deps.systemPrompt;
|
|
1352
|
+
const ref = {
|
|
1353
|
+
id: persona.id,
|
|
1354
|
+
label: persona.label
|
|
1355
|
+
};
|
|
1356
|
+
const resolve = /* @__PURE__ */ __name(async (prompt, ctx) => typeof prompt === "function" ? prompt(ctx) : prompt, "resolve");
|
|
1357
|
+
const own = persona.systemPrompt;
|
|
1358
|
+
const systemPrompt = /* @__PURE__ */ __name(async (ctx) => {
|
|
1359
|
+
const scoped = {
|
|
1360
|
+
...ctx,
|
|
1361
|
+
persona: ref
|
|
1362
|
+
};
|
|
1363
|
+
if (own === void 0) {
|
|
1364
|
+
return resolve(base, scoped);
|
|
1365
|
+
}
|
|
1366
|
+
const basePrompt = typeof own === "function" ? await resolve(base, scoped) : void 0;
|
|
1367
|
+
return resolve(own, {
|
|
1368
|
+
...scoped,
|
|
1369
|
+
...basePrompt !== void 0 ? {
|
|
1370
|
+
basePrompt
|
|
1371
|
+
} : {}
|
|
1372
|
+
});
|
|
1373
|
+
}, "systemPrompt");
|
|
1374
|
+
const toolAllowList = intersectAllowLists2(deps.toolAllowList, persona.allowedTools);
|
|
1375
|
+
return {
|
|
1376
|
+
...deps,
|
|
1377
|
+
systemPrompt,
|
|
1378
|
+
...toolAllowList !== void 0 ? {
|
|
1379
|
+
toolAllowList
|
|
1380
|
+
} : {}
|
|
1381
|
+
};
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1149
1384
|
* The ceiling on how much of a thread this agent's turns carry, most specific wins: the agent's
|
|
1150
1385
|
* own `@Agent({ history })`, else a module-wide custom `historyPolicy`, else the module-wide
|
|
1151
1386
|
* `history` window. Undefined → unbounded, the behaviour of a module that configures none.
|
|
@@ -1220,12 +1455,24 @@ AgentDepsFactory2 = _ts_decorate5([
|
|
|
1220
1455
|
], AgentDepsFactory2);
|
|
1221
1456
|
|
|
1222
1457
|
// src/agent.service.ts
|
|
1223
|
-
import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as
|
|
1224
|
-
import { BadRequestException, ConflictException as ConflictException2, ForbiddenException, GoneException, HttpException, HttpStatus, Inject as Inject6, Injectable as Injectable6, NotFoundException, NotImplementedException as NotImplementedException2, Optional as Optional5 } from "@nestjs/common";
|
|
1458
|
+
import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE5, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval, readElicitationQuestions, settleDeadRun as settleDeadRun2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
|
|
1459
|
+
import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException, GoneException, HttpException, HttpStatus, Inject as Inject6, Injectable as Injectable6, NotFoundException, NotImplementedException as NotImplementedException2, Optional as Optional5 } from "@nestjs/common";
|
|
1225
1460
|
|
|
1226
1461
|
// src/queue/chat-queue.service.ts
|
|
1227
|
-
import { AGENT_ATTACHMENT_STAGING, AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK3, AGENT_STORE as AGENT_STORE4, encodeStreamEvent as encodeStreamEvent4, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
|
|
1462
|
+
import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK3, AGENT_STORE as AGENT_STORE4, encodeStreamEvent as encodeStreamEvent4, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
|
|
1228
1463
|
import { Inject as Inject5, Injectable as Injectable5, Logger as Logger3, NotImplementedException, Optional as Optional4 } from "@nestjs/common";
|
|
1464
|
+
|
|
1465
|
+
// src/thread-persona.ts
|
|
1466
|
+
async function threadPersona(store, threadId) {
|
|
1467
|
+
const projecting = store;
|
|
1468
|
+
if (typeof projecting.personaForThread === "function") {
|
|
1469
|
+
return projecting.personaForThread(threadId);
|
|
1470
|
+
}
|
|
1471
|
+
return (await store.getThread(threadId))?.persona ?? null;
|
|
1472
|
+
}
|
|
1473
|
+
__name(threadPersona, "threadPersona");
|
|
1474
|
+
|
|
1475
|
+
// src/queue/chat-queue.service.ts
|
|
1229
1476
|
function _ts_decorate6(decorators, target, key, desc) {
|
|
1230
1477
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1231
1478
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -1262,18 +1509,20 @@ var ChatQueueService2 = class _ChatQueueService {
|
|
|
1262
1509
|
quotaProvider;
|
|
1263
1510
|
options;
|
|
1264
1511
|
staging;
|
|
1512
|
+
deps;
|
|
1265
1513
|
logger = new Logger3(_ChatQueueService.name);
|
|
1266
1514
|
/**
|
|
1267
1515
|
* Runs this process claimed a thread for and has not handed to a runner yet. A holder in here is
|
|
1268
1516
|
* alive whatever the runner says — it simply has not registered the run yet.
|
|
1269
1517
|
*/
|
|
1270
1518
|
starting = /* @__PURE__ */ new Set();
|
|
1271
|
-
constructor(store, sink, quotaProvider, options, staging) {
|
|
1519
|
+
constructor(store, sink, quotaProvider, options, staging, deps) {
|
|
1272
1520
|
this.store = store;
|
|
1273
1521
|
this.sink = sink;
|
|
1274
1522
|
this.quotaProvider = quotaProvider;
|
|
1275
1523
|
this.options = options;
|
|
1276
1524
|
this.staging = staging;
|
|
1525
|
+
this.deps = deps;
|
|
1277
1526
|
}
|
|
1278
1527
|
/** Whether the bound store can hold a queue. Without one, a busy thread is not queued. */
|
|
1279
1528
|
get supported() {
|
|
@@ -1571,13 +1820,17 @@ var ChatQueueService2 = class _ChatQueueService {
|
|
|
1571
1820
|
*/
|
|
1572
1821
|
async inputFor(message) {
|
|
1573
1822
|
const attachments = await this.freshAttachments(message.actor, message.attachments ?? []);
|
|
1823
|
+
const { agentName, persona } = await this.targetFor(message);
|
|
1574
1824
|
return {
|
|
1575
1825
|
threadId: message.threadId,
|
|
1576
1826
|
actor: message.actor,
|
|
1577
1827
|
userText: message.content,
|
|
1578
1828
|
day: utcDay(),
|
|
1579
|
-
...
|
|
1580
|
-
agentName
|
|
1829
|
+
...agentName !== void 0 ? {
|
|
1830
|
+
agentName
|
|
1831
|
+
} : {},
|
|
1832
|
+
...persona !== void 0 ? {
|
|
1833
|
+
persona
|
|
1581
1834
|
} : {},
|
|
1582
1835
|
...attachments.length > 0 ? {
|
|
1583
1836
|
attachments
|
|
@@ -1590,6 +1843,37 @@ var ChatQueueService2 = class _ChatQueueService {
|
|
|
1590
1843
|
} : {}
|
|
1591
1844
|
};
|
|
1592
1845
|
}
|
|
1846
|
+
/**
|
|
1847
|
+
* The agent and persona a queued message starts as. A message carries the persona its send
|
|
1848
|
+
* resolved; one that carries none — queued before personas existed, or by a host that sets none —
|
|
1849
|
+
* resolves it now, exactly as a send would: an agent name a persona took over, then the thread's
|
|
1850
|
+
* pinned persona, then the agent's default. Never refused here: nobody is waiting on a 400.
|
|
1851
|
+
*/
|
|
1852
|
+
async targetFor(message) {
|
|
1853
|
+
const deps = this.deps;
|
|
1854
|
+
if (message.persona !== void 0 || deps === void 0 || message.agentName === void 0) {
|
|
1855
|
+
return {
|
|
1856
|
+
...message.agentName !== void 0 ? {
|
|
1857
|
+
agentName: message.agentName
|
|
1858
|
+
} : {},
|
|
1859
|
+
...message.persona !== void 0 ? {
|
|
1860
|
+
persona: message.persona
|
|
1861
|
+
} : {}
|
|
1862
|
+
};
|
|
1863
|
+
}
|
|
1864
|
+
const target = deps.resolveAgent(message.agentName);
|
|
1865
|
+
const hasPersonas = deps.personaCatalog(target.agentName).length > 0;
|
|
1866
|
+
const persona = target.persona ?? (hasPersonas ? deps.resolvePersona({
|
|
1867
|
+
agentName: target.agentName,
|
|
1868
|
+
threadPersona: await threadPersona(this.store, message.threadId)
|
|
1869
|
+
}) : void 0);
|
|
1870
|
+
return {
|
|
1871
|
+
agentName: target.agentName,
|
|
1872
|
+
...persona !== void 0 ? {
|
|
1873
|
+
persona
|
|
1874
|
+
} : {}
|
|
1875
|
+
};
|
|
1876
|
+
}
|
|
1593
1877
|
async freshAttachments(actor, attachments) {
|
|
1594
1878
|
const staging = this.staging;
|
|
1595
1879
|
if (attachments.length === 0 || staging === void 0 || typeof staging.resolve !== "function") {
|
|
@@ -1617,13 +1901,16 @@ ChatQueueService2 = _ts_decorate6([
|
|
|
1617
1901
|
_ts_param5(3, Inject5(AGENT_OPTIONS2)),
|
|
1618
1902
|
_ts_param5(4, Optional4()),
|
|
1619
1903
|
_ts_param5(4, Inject5(AGENT_ATTACHMENT_STAGING)),
|
|
1904
|
+
_ts_param5(5, Optional4()),
|
|
1905
|
+
_ts_param5(5, Inject5(AGENT_DEPS_FACTORY3)),
|
|
1620
1906
|
_ts_metadata5("design:type", Function),
|
|
1621
1907
|
_ts_metadata5("design:paramtypes", [
|
|
1622
1908
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
1623
1909
|
typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
|
|
1624
1910
|
typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
|
|
1625
1911
|
typeof Pick === "undefined" ? Object : Pick,
|
|
1626
|
-
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
|
|
1912
|
+
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore,
|
|
1913
|
+
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
|
|
1627
1914
|
])
|
|
1628
1915
|
], ChatQueueService2);
|
|
1629
1916
|
function pauseReasonFor(outcome, head) {
|
|
@@ -1795,17 +2082,17 @@ var AgentService = class {
|
|
|
1795
2082
|
*/
|
|
1796
2083
|
async assertModelAllowed(actor, agent, model) {
|
|
1797
2084
|
if (this.models === void 0) {
|
|
1798
|
-
throw new
|
|
2085
|
+
throw new BadRequestException2(`model "${model}" cannot be selected: no ModelCatalog is configured (AgentModule.forRoot({ models }))`);
|
|
1799
2086
|
}
|
|
1800
2087
|
const entry = findCatalogModel(await this.models.list({
|
|
1801
2088
|
actor,
|
|
1802
2089
|
agent
|
|
1803
2090
|
}), model);
|
|
1804
2091
|
if (entry === void 0) {
|
|
1805
|
-
throw new
|
|
2092
|
+
throw new BadRequestException2(`model "${model}" is not offered`);
|
|
1806
2093
|
}
|
|
1807
2094
|
if (!entry.available) {
|
|
1808
|
-
throw new
|
|
2095
|
+
throw new BadRequestException2(`model "${model}" is not available${entry.unavailableReason ? `: ${entry.unavailableReason}` : ""}`);
|
|
1809
2096
|
}
|
|
1810
2097
|
return entry.id;
|
|
1811
2098
|
}
|
|
@@ -1821,7 +2108,7 @@ var AgentService = class {
|
|
|
1821
2108
|
})).locked : void 0;
|
|
1822
2109
|
if (locked !== void 0) {
|
|
1823
2110
|
if (requested !== void 0 && requested !== locked.model) {
|
|
1824
|
-
throw new
|
|
2111
|
+
throw new BadRequestException2(`model "${requested}" cannot be selected: ${locked.reason ?? `this agent always uses "${locked.model}"`}`);
|
|
1825
2112
|
}
|
|
1826
2113
|
return locked.model;
|
|
1827
2114
|
}
|
|
@@ -1877,13 +2164,15 @@ var AgentService = class {
|
|
|
1877
2164
|
*/
|
|
1878
2165
|
async send(params) {
|
|
1879
2166
|
await this.assertWithinQuota(params.actor);
|
|
1880
|
-
const
|
|
2167
|
+
const target = this.deps.resolveAgent(await this.resolveAgentName(params.agentName, params.threadId));
|
|
2168
|
+
const agentName = target.agentName;
|
|
2169
|
+
const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId);
|
|
1881
2170
|
const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
|
|
1882
2171
|
const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
|
|
1883
2172
|
let threadId = params.threadId;
|
|
1884
2173
|
if (threadId === void 0) {
|
|
1885
2174
|
if (params.regenerate === true) {
|
|
1886
|
-
throw new
|
|
2175
|
+
throw new BadRequestException2("regenerate requires an existing threadId");
|
|
1887
2176
|
}
|
|
1888
2177
|
const created = await this.store.createThread({
|
|
1889
2178
|
actor: params.actor,
|
|
@@ -1892,11 +2181,17 @@ var AgentService = class {
|
|
|
1892
2181
|
} : {},
|
|
1893
2182
|
...params.newThreadId !== void 0 ? {
|
|
1894
2183
|
id: params.newThreadId
|
|
2184
|
+
} : {},
|
|
2185
|
+
...params.personaId !== void 0 ? {
|
|
2186
|
+
persona: params.personaId
|
|
1895
2187
|
} : {}
|
|
1896
2188
|
});
|
|
1897
2189
|
threadId = created.id;
|
|
1898
2190
|
} else {
|
|
1899
2191
|
await this.assertOwnsThread(params.actor, threadId);
|
|
2192
|
+
if (params.personaId !== void 0) {
|
|
2193
|
+
await this.pinThreadPersona(threadId, params.personaId);
|
|
2194
|
+
}
|
|
1900
2195
|
}
|
|
1901
2196
|
const input = {
|
|
1902
2197
|
threadId,
|
|
@@ -1904,6 +2199,9 @@ var AgentService = class {
|
|
|
1904
2199
|
userText: params.message,
|
|
1905
2200
|
day: utcDay(),
|
|
1906
2201
|
agentName,
|
|
2202
|
+
...persona !== void 0 ? {
|
|
2203
|
+
persona
|
|
2204
|
+
} : {},
|
|
1907
2205
|
...params.regenerate === true ? {
|
|
1908
2206
|
regenerate: true
|
|
1909
2207
|
} : {},
|
|
@@ -1990,6 +2288,9 @@ var AgentService = class {
|
|
|
1990
2288
|
...input.agentName !== void 0 ? {
|
|
1991
2289
|
agentName: input.agentName
|
|
1992
2290
|
} : {},
|
|
2291
|
+
...input.persona !== void 0 ? {
|
|
2292
|
+
persona: input.persona
|
|
2293
|
+
} : {},
|
|
1993
2294
|
...input.model !== void 0 ? {
|
|
1994
2295
|
model: input.model
|
|
1995
2296
|
} : {},
|
|
@@ -2042,7 +2343,7 @@ var AgentService = class {
|
|
|
2042
2343
|
const store = queue.queueStore();
|
|
2043
2344
|
const threadId = await this.assertOwnsQueuedMessage(actor, messageId);
|
|
2044
2345
|
if (patch.message !== void 0 && patch.message.trim().length === 0) {
|
|
2045
|
-
throw new
|
|
2346
|
+
throw new BadRequestException2("message must not be empty");
|
|
2046
2347
|
}
|
|
2047
2348
|
const attachments = patch.attachments === void 0 || patch.attachments === null ? patch.attachments : await this.resolveAttachments(actor, patch.attachments);
|
|
2048
2349
|
if (patch.message !== void 0 || attachments !== void 0) {
|
|
@@ -2060,7 +2361,7 @@ var AgentService = class {
|
|
|
2060
2361
|
}
|
|
2061
2362
|
if (patch.position !== void 0) {
|
|
2062
2363
|
if (!Number.isInteger(patch.position) || patch.position < 0) {
|
|
2063
|
-
throw new
|
|
2364
|
+
throw new BadRequestException2("position must be a non-negative integer");
|
|
2064
2365
|
}
|
|
2065
2366
|
if (!await store.moveQueuedMessage(messageId, patch.position)) {
|
|
2066
2367
|
throw new GoneException(`queued message ${messageId} already started or was removed`);
|
|
@@ -2384,16 +2685,22 @@ var AgentService = class {
|
|
|
2384
2685
|
async updateThread(actor, threadId, patch) {
|
|
2385
2686
|
const title = patch.title !== void 0 ? this.validateTitle(patch.title) : void 0;
|
|
2386
2687
|
await this.assertOwnsThread(actor, threadId);
|
|
2387
|
-
if (patch.defaultAgent === void 0 && patch.model === void 0) {
|
|
2688
|
+
if (patch.defaultAgent === void 0 && patch.model === void 0 && patch.persona === void 0) {
|
|
2388
2689
|
if (title !== void 0) {
|
|
2389
2690
|
await this.store.setTitle(threadId, title);
|
|
2390
2691
|
}
|
|
2391
2692
|
return;
|
|
2392
2693
|
}
|
|
2393
2694
|
if (this.store.updateThread === void 0) {
|
|
2394
|
-
throw new NotImplementedException2("Setting a thread's defaultAgent or
|
|
2695
|
+
throw new NotImplementedException2("Setting a thread's defaultAgent, model or persona requires an AgentStore that implements updateThread(); the bound store does not support it.");
|
|
2395
2696
|
}
|
|
2396
2697
|
const model = patch.model === void 0 || patch.model === null ? patch.model : await this.assertModelAllowed(actor, patch.defaultAgent ?? await this.resolveAgentName(void 0, threadId), patch.model);
|
|
2698
|
+
if (patch.persona !== void 0 && patch.persona !== null) {
|
|
2699
|
+
this.deps.resolvePersona({
|
|
2700
|
+
agentName: this.deps.resolveAgent(patch.defaultAgent ?? await this.resolveAgentName(void 0, threadId)).agentName,
|
|
2701
|
+
requested: patch.persona
|
|
2702
|
+
});
|
|
2703
|
+
}
|
|
2397
2704
|
await this.store.updateThread(threadId, {
|
|
2398
2705
|
...title !== void 0 ? {
|
|
2399
2706
|
title
|
|
@@ -2403,16 +2710,46 @@ var AgentService = class {
|
|
|
2403
2710
|
} : {},
|
|
2404
2711
|
...model !== void 0 ? {
|
|
2405
2712
|
model
|
|
2713
|
+
} : {},
|
|
2714
|
+
...patch.persona !== void 0 ? {
|
|
2715
|
+
persona: patch.persona
|
|
2716
|
+
} : {}
|
|
2717
|
+
});
|
|
2718
|
+
}
|
|
2719
|
+
/**
|
|
2720
|
+
* The persona this send runs under — see {@link AgentDepsFactory.resolvePersona}. The thread's
|
|
2721
|
+
* pinned persona is read only when the send names none AND the agent has personas to pick from.
|
|
2722
|
+
*/
|
|
2723
|
+
async resolvePersona(agentName, requested, threadId) {
|
|
2724
|
+
const needsThread = requested === void 0 && threadId !== void 0 && this.deps.personaCatalog(agentName).length > 0;
|
|
2725
|
+
return this.deps.resolvePersona({
|
|
2726
|
+
agentName,
|
|
2727
|
+
...requested !== void 0 ? {
|
|
2728
|
+
requested
|
|
2729
|
+
} : {},
|
|
2730
|
+
...needsThread ? {
|
|
2731
|
+
threadPersona: await threadPersona(this.store, threadId)
|
|
2406
2732
|
} : {}
|
|
2407
2733
|
});
|
|
2408
2734
|
}
|
|
2735
|
+
/** Pin `persona` on the thread when it is not already — a no-op on a store that cannot. */
|
|
2736
|
+
async pinThreadPersona(threadId, persona) {
|
|
2737
|
+
if (this.store.updateThread === void 0) {
|
|
2738
|
+
return;
|
|
2739
|
+
}
|
|
2740
|
+
if (await threadPersona(this.store, threadId) !== persona) {
|
|
2741
|
+
await this.store.updateThread(threadId, {
|
|
2742
|
+
persona
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2409
2746
|
validateTitle(title) {
|
|
2410
2747
|
const trimmed = title.trim();
|
|
2411
2748
|
if (trimmed.length === 0) {
|
|
2412
|
-
throw new
|
|
2749
|
+
throw new BadRequestException2("title must not be empty");
|
|
2413
2750
|
}
|
|
2414
2751
|
if (trimmed.length > 200) {
|
|
2415
|
-
throw new
|
|
2752
|
+
throw new BadRequestException2("title must be at most 200 characters");
|
|
2416
2753
|
}
|
|
2417
2754
|
return trimmed;
|
|
2418
2755
|
}
|
|
@@ -2451,6 +2788,7 @@ var AgentService = class {
|
|
|
2451
2788
|
...thread,
|
|
2452
2789
|
defaultAgent: thread.defaultAgent ?? null,
|
|
2453
2790
|
model: thread.model ?? null,
|
|
2791
|
+
persona: thread.persona ?? null,
|
|
2454
2792
|
activeRunId: await this.store.activeRunForThread?.(thread.id) ?? thread.activeRunId ?? null
|
|
2455
2793
|
};
|
|
2456
2794
|
}
|
|
@@ -2515,14 +2853,14 @@ var AgentService = class {
|
|
|
2515
2853
|
*/
|
|
2516
2854
|
async setMessageFeedback(actor, messageId, input) {
|
|
2517
2855
|
if (input.value !== null && input.value !== "up" && input.value !== "down") {
|
|
2518
|
-
throw new
|
|
2856
|
+
throw new BadRequestException2("value must be 'up', 'down' or null");
|
|
2519
2857
|
}
|
|
2520
2858
|
if (input.comment !== void 0 && typeof input.comment !== "string") {
|
|
2521
|
-
throw new
|
|
2859
|
+
throw new BadRequestException2("comment must be a string");
|
|
2522
2860
|
}
|
|
2523
2861
|
const comment = input.comment?.trim();
|
|
2524
2862
|
if (comment !== void 0 && comment.length > 2e3) {
|
|
2525
|
-
throw new
|
|
2863
|
+
throw new BadRequestException2("comment must be at most 2000 characters");
|
|
2526
2864
|
}
|
|
2527
2865
|
if (this.store.threadOfMessage === void 0 || this.store.setMessageFeedback === void 0) {
|
|
2528
2866
|
throw new NotImplementedException2("Message feedback requires an AgentStore that implements threadOfMessage() and setMessageFeedback(); the bound store does not support it.");
|
|
@@ -2647,7 +2985,7 @@ var AgentService = class {
|
|
|
2647
2985
|
const submitted = Object.hasOwn(answers2, question.id) ? answers2[question.id] : void 0;
|
|
2648
2986
|
const problem = validateElicitationAnswer(question, submitted ?? question.defaults ?? []);
|
|
2649
2987
|
if (problem !== null) {
|
|
2650
|
-
throw new
|
|
2988
|
+
throw new BadRequestException2(`answers["${question.id}"] ${problem}`);
|
|
2651
2989
|
}
|
|
2652
2990
|
}
|
|
2653
2991
|
}
|
|
@@ -2721,7 +3059,7 @@ AgentService = _ts_decorate7([
|
|
|
2721
3059
|
Injectable6(),
|
|
2722
3060
|
_ts_param6(0, Inject6(AGENT_RUNNER)),
|
|
2723
3061
|
_ts_param6(1, Inject6(AGENT_STORE5)),
|
|
2724
|
-
_ts_param6(2, Inject6(
|
|
3062
|
+
_ts_param6(2, Inject6(AGENT_DEPS_FACTORY4)),
|
|
2725
3063
|
_ts_param6(3, Optional5()),
|
|
2726
3064
|
_ts_param6(3, Inject6(AGENT_ATTACHMENT_STAGING2)),
|
|
2727
3065
|
_ts_param6(4, Optional5()),
|
|
@@ -2812,7 +3150,7 @@ AgentApprovalPortAdapter = _ts_decorate8([
|
|
|
2812
3150
|
], AgentApprovalPortAdapter);
|
|
2813
3151
|
|
|
2814
3152
|
// src/controller/agents.controller.ts
|
|
2815
|
-
import { AGENT_DEPS_FACTORY as
|
|
3153
|
+
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY5, AGENT_REGISTRY as AGENT_REGISTRY2, AgentRegistry as AgentRegistry3 } from "@dudousxd/nestjs-agent-core";
|
|
2816
3154
|
import { Controller, Get, Inject as Inject7 } from "@nestjs/common";
|
|
2817
3155
|
function _ts_decorate9(decorators, target, key, desc) {
|
|
2818
3156
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -2852,13 +3190,22 @@ var AgentsController = class {
|
|
|
2852
3190
|
}
|
|
2853
3191
|
list() {
|
|
2854
3192
|
const defaultAgentName = this.depsFactory.defaultAgentName();
|
|
2855
|
-
return this.agents.list().map((definition) =>
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
3193
|
+
return this.agents.list().map((definition) => {
|
|
3194
|
+
const personas = this.depsFactory.personaCatalog(definition.name);
|
|
3195
|
+
return {
|
|
3196
|
+
name: definition.name,
|
|
3197
|
+
description: definition.description ?? "",
|
|
3198
|
+
...definition.name === defaultAgentName ? {
|
|
3199
|
+
isDefault: true
|
|
3200
|
+
} : {},
|
|
3201
|
+
...personas.length > 0 ? {
|
|
3202
|
+
personas
|
|
3203
|
+
} : {},
|
|
3204
|
+
...definition.defaultPersona !== void 0 ? {
|
|
3205
|
+
defaultPersona: definition.defaultPersona
|
|
3206
|
+
} : {}
|
|
3207
|
+
};
|
|
3208
|
+
});
|
|
2862
3209
|
}
|
|
2863
3210
|
};
|
|
2864
3211
|
_ts_decorate9([
|
|
@@ -2870,7 +3217,7 @@ _ts_decorate9([
|
|
|
2870
3217
|
AgentsController = _ts_decorate9([
|
|
2871
3218
|
Controller("agents"),
|
|
2872
3219
|
_ts_param7(0, Inject7(AGENT_REGISTRY2)),
|
|
2873
|
-
_ts_param7(1, Inject7(
|
|
3220
|
+
_ts_param7(1, Inject7(AGENT_DEPS_FACTORY5)),
|
|
2874
3221
|
_ts_metadata8("design:type", Function),
|
|
2875
3222
|
_ts_metadata8("design:paramtypes", [
|
|
2876
3223
|
typeof AgentRegistry3 === "undefined" ? Object : AgentRegistry3,
|
|
@@ -2880,7 +3227,7 @@ AgentsController = _ts_decorate9([
|
|
|
2880
3227
|
|
|
2881
3228
|
// src/controller/attachments.controller.ts
|
|
2882
3229
|
import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING3, AGENT_OPTIONS as AGENT_OPTIONS4 } from "@dudousxd/nestjs-agent-core";
|
|
2883
|
-
import { BadRequestException as
|
|
3230
|
+
import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject8, NotImplementedException as NotImplementedException3, Optional as Optional6, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
|
|
2884
3231
|
import { FileInterceptor } from "@nestjs/platform-express";
|
|
2885
3232
|
|
|
2886
3233
|
// src/attachment-limits.ts
|
|
@@ -2971,7 +3318,7 @@ var AttachmentsController = class {
|
|
|
2971
3318
|
throw new NotImplementedException3("Attachment upload is not configured on this server: bind AGENT_ATTACHMENT_STAGING (e.g. import AgentMediaAttachmentsModule).");
|
|
2972
3319
|
}
|
|
2973
3320
|
if (file === void 0) {
|
|
2974
|
-
throw new
|
|
3321
|
+
throw new BadRequestException3('multipart field "file" is required');
|
|
2975
3322
|
}
|
|
2976
3323
|
const { allowedContentTypes, maxBytes } = attachmentLimits(this.options, this.staging);
|
|
2977
3324
|
if (!allowedContentTypes.includes(file.mimetype)) {
|
|
@@ -3032,7 +3379,7 @@ AttachmentsController = _ts_decorate10([
|
|
|
3032
3379
|
|
|
3033
3380
|
// src/controller/chat.controller.ts
|
|
3034
3381
|
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER2, AgentStreamError as AgentStreamError2, streamFailure as streamFailure2 } from "@dudousxd/nestjs-agent-core";
|
|
3035
|
-
import { BadRequestException as
|
|
3382
|
+
import { BadRequestException as BadRequestException4, Body, Controller as Controller3, Get as Get3, Inject as Inject9, Param, Post as Post2, Query, Req as Req2, Res } from "@nestjs/common";
|
|
3036
3383
|
function _ts_decorate11(decorators, target, key, desc) {
|
|
3037
3384
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3038
3385
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -3069,7 +3416,7 @@ function sendMode(body) {
|
|
|
3069
3416
|
if (body.mode === "auto" || body.mode === "queue" || body.mode === "interrupt") {
|
|
3070
3417
|
return body.mode;
|
|
3071
3418
|
}
|
|
3072
|
-
throw new
|
|
3419
|
+
throw new BadRequestException4("mode must be 'auto', 'queue' or 'interrupt'");
|
|
3073
3420
|
}
|
|
3074
3421
|
__name(sendMode, "sendMode");
|
|
3075
3422
|
function attachmentRefs(claimed) {
|
|
@@ -3077,21 +3424,21 @@ function attachmentRefs(claimed) {
|
|
|
3077
3424
|
return [];
|
|
3078
3425
|
}
|
|
3079
3426
|
if (!Array.isArray(claimed)) {
|
|
3080
|
-
throw new
|
|
3427
|
+
throw new BadRequestException4("attachments must be an array of { mediaId }");
|
|
3081
3428
|
}
|
|
3082
3429
|
if (claimed.length > MAX_ATTACHMENTS_PER_MESSAGE) {
|
|
3083
|
-
throw new
|
|
3430
|
+
throw new BadRequestException4(`a message may carry at most ${MAX_ATTACHMENTS_PER_MESSAGE} attachments`);
|
|
3084
3431
|
}
|
|
3085
3432
|
return claimed.map((entry) => {
|
|
3086
3433
|
if (typeof entry !== "object" || entry === null || !("mediaId" in entry)) {
|
|
3087
|
-
throw new
|
|
3434
|
+
throw new BadRequestException4("each attachment must be an object with a mediaId");
|
|
3088
3435
|
}
|
|
3089
3436
|
if (Object.keys(entry).some((key) => key !== "mediaId")) {
|
|
3090
|
-
throw new
|
|
3437
|
+
throw new BadRequestException4("attachments are { mediaId } refs \u2014 send nothing but the id");
|
|
3091
3438
|
}
|
|
3092
3439
|
const { mediaId } = entry;
|
|
3093
3440
|
if (typeof mediaId !== "string" || mediaId.length === 0) {
|
|
3094
|
-
throw new
|
|
3441
|
+
throw new BadRequestException4("each attachment must carry a non-empty string mediaId");
|
|
3095
3442
|
}
|
|
3096
3443
|
return {
|
|
3097
3444
|
mediaId
|
|
@@ -3128,6 +3475,9 @@ var ChatController = class {
|
|
|
3128
3475
|
...body.agent !== void 0 ? {
|
|
3129
3476
|
agentName: body.agent
|
|
3130
3477
|
} : {},
|
|
3478
|
+
...typeof body.persona === "string" && body.persona.length > 0 ? {
|
|
3479
|
+
personaId: body.persona
|
|
3480
|
+
} : {},
|
|
3131
3481
|
...attachments.length > 0 ? {
|
|
3132
3482
|
attachments
|
|
3133
3483
|
} : {},
|
|
@@ -3754,7 +4104,7 @@ ModelsController = _ts_decorate15([
|
|
|
3754
4104
|
|
|
3755
4105
|
// src/controller/queue.controller.ts
|
|
3756
4106
|
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER7 } from "@dudousxd/nestjs-agent-core";
|
|
3757
|
-
import { BadRequestException as
|
|
4107
|
+
import { BadRequestException as BadRequestException5, Body as Body3, Controller as Controller8, Delete as Delete2, Get as Get7, Inject as Inject14, Param as Param4, Patch, Post as Post4, Req as Req7 } from "@nestjs/common";
|
|
3758
4108
|
function _ts_decorate16(decorators, target, key, desc) {
|
|
3759
4109
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3760
4110
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -3804,10 +4154,10 @@ var QueueController = class {
|
|
|
3804
4154
|
async update(req, messageId, body) {
|
|
3805
4155
|
const actor = await this.actorResolver.resolve(req);
|
|
3806
4156
|
if (body.message !== void 0 && typeof body.message !== "string") {
|
|
3807
|
-
throw new
|
|
4157
|
+
throw new BadRequestException5("message must be a string");
|
|
3808
4158
|
}
|
|
3809
4159
|
if (body.position !== void 0 && typeof body.position !== "number") {
|
|
3810
|
-
throw new
|
|
4160
|
+
throw new BadRequestException5("position must be a number");
|
|
3811
4161
|
}
|
|
3812
4162
|
const attachments = body.attachments === void 0 ? void 0 : body.attachments === null ? null : attachmentRefs(body.attachments);
|
|
3813
4163
|
return this.agent.updateQueuedMessage(actor, messageId, {
|
|
@@ -4127,6 +4477,9 @@ var ThreadsController = class {
|
|
|
4127
4477
|
} : {},
|
|
4128
4478
|
..."model" in body ? {
|
|
4129
4479
|
model: body.model ?? null
|
|
4480
|
+
} : {},
|
|
4481
|
+
..."persona" in body ? {
|
|
4482
|
+
persona: body.persona ?? null
|
|
4130
4483
|
} : {}
|
|
4131
4484
|
});
|
|
4132
4485
|
return {
|
|
@@ -4241,7 +4594,7 @@ ThreadsController = _ts_decorate19([
|
|
|
4241
4594
|
|
|
4242
4595
|
// src/controller/tool-call.controller.ts
|
|
4243
4596
|
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11 } from "@dudousxd/nestjs-agent-core";
|
|
4244
|
-
import { BadRequestException as
|
|
4597
|
+
import { BadRequestException as BadRequestException6, Body as Body5, Controller as Controller12, Inject as Inject18, Post as Post6, Req as Req11 } from "@nestjs/common";
|
|
4245
4598
|
function _ts_decorate20(decorators, target, key, desc) {
|
|
4246
4599
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4247
4600
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -4276,7 +4629,7 @@ var MAX_VIA_LENGTH = 64;
|
|
|
4276
4629
|
var DEFAULT_VIA = "web";
|
|
4277
4630
|
function toolCallId(claimed) {
|
|
4278
4631
|
if (typeof claimed !== "string" || claimed.length === 0) {
|
|
4279
|
-
throw new
|
|
4632
|
+
throw new BadRequestException6("toolCallId must be a non-empty string");
|
|
4280
4633
|
}
|
|
4281
4634
|
return claimed;
|
|
4282
4635
|
}
|
|
@@ -4286,10 +4639,10 @@ function rejectReason(claimed) {
|
|
|
4286
4639
|
return void 0;
|
|
4287
4640
|
}
|
|
4288
4641
|
if (typeof claimed !== "string") {
|
|
4289
|
-
throw new
|
|
4642
|
+
throw new BadRequestException6("reason must be a string");
|
|
4290
4643
|
}
|
|
4291
4644
|
if (claimed.length > MAX_REJECT_REASON_LENGTH) {
|
|
4292
|
-
throw new
|
|
4645
|
+
throw new BadRequestException6(`reason must be at most ${MAX_REJECT_REASON_LENGTH} characters`);
|
|
4293
4646
|
}
|
|
4294
4647
|
return claimed;
|
|
4295
4648
|
}
|
|
@@ -4299,7 +4652,7 @@ function remember(claimed) {
|
|
|
4299
4652
|
return false;
|
|
4300
4653
|
}
|
|
4301
4654
|
if (typeof claimed !== "boolean") {
|
|
4302
|
-
throw new
|
|
4655
|
+
throw new BadRequestException6("remember must be a boolean");
|
|
4303
4656
|
}
|
|
4304
4657
|
return claimed;
|
|
4305
4658
|
}
|
|
@@ -4309,7 +4662,7 @@ function via(claimed) {
|
|
|
4309
4662
|
return DEFAULT_VIA;
|
|
4310
4663
|
}
|
|
4311
4664
|
if (typeof claimed !== "string" || claimed.length === 0 || claimed.length > MAX_VIA_LENGTH) {
|
|
4312
|
-
throw new
|
|
4665
|
+
throw new BadRequestException6(`via must be a string of 1-${MAX_VIA_LENGTH} characters`);
|
|
4313
4666
|
}
|
|
4314
4667
|
return claimed;
|
|
4315
4668
|
}
|
|
@@ -4319,26 +4672,26 @@ function answers(claimed) {
|
|
|
4319
4672
|
return void 0;
|
|
4320
4673
|
}
|
|
4321
4674
|
if (typeof claimed !== "object" || claimed === null || Array.isArray(claimed)) {
|
|
4322
|
-
throw new
|
|
4675
|
+
throw new BadRequestException6("answers must be an object of questionId \u2192 chosen values");
|
|
4323
4676
|
}
|
|
4324
4677
|
const entries = Object.entries(claimed);
|
|
4325
4678
|
if (entries.length > MAX_ANSWERED_QUESTIONS) {
|
|
4326
|
-
throw new
|
|
4679
|
+
throw new BadRequestException6(`answers may cover at most ${MAX_ANSWERED_QUESTIONS} questions`);
|
|
4327
4680
|
}
|
|
4328
4681
|
const validated = /* @__PURE__ */ Object.create(null);
|
|
4329
4682
|
for (const [questionId, values] of entries) {
|
|
4330
4683
|
if (!Array.isArray(values)) {
|
|
4331
|
-
throw new
|
|
4684
|
+
throw new BadRequestException6(`answers["${questionId}"] must be an array of chosen values`);
|
|
4332
4685
|
}
|
|
4333
4686
|
if (values.length > MAX_VALUES_PER_QUESTION) {
|
|
4334
|
-
throw new
|
|
4687
|
+
throw new BadRequestException6(`answers["${questionId}"] may carry at most ${MAX_VALUES_PER_QUESTION} values`);
|
|
4335
4688
|
}
|
|
4336
4689
|
for (const value of values) {
|
|
4337
4690
|
if (typeof value !== "string") {
|
|
4338
|
-
throw new
|
|
4691
|
+
throw new BadRequestException6(`answers["${questionId}"] must contain only strings`);
|
|
4339
4692
|
}
|
|
4340
4693
|
if (value.length > MAX_ANSWER_VALUE_LENGTH) {
|
|
4341
|
-
throw new
|
|
4694
|
+
throw new BadRequestException6(`answers["${questionId}"] values must be at most ${MAX_ANSWER_VALUE_LENGTH} characters`);
|
|
4342
4695
|
}
|
|
4343
4696
|
}
|
|
4344
4697
|
validated[questionId] = values;
|
|
@@ -4455,7 +4808,7 @@ ToolCallController = _ts_decorate20([
|
|
|
4455
4808
|
], ToolCallController);
|
|
4456
4809
|
|
|
4457
4810
|
// src/controller/tools.controller.ts
|
|
4458
|
-
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER12, AGENT_DEPS_FACTORY as
|
|
4811
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER12, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY6, AGENT_REGISTRY as AGENT_REGISTRY3, ALL_AGENTS, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
|
|
4459
4812
|
import { Controller as Controller13, Get as Get11, Inject as Inject19, NotFoundException as NotFoundException3, Query as Query5, Req as Req12 } from "@nestjs/common";
|
|
4460
4813
|
function _ts_decorate21(decorators, target, key, desc) {
|
|
4461
4814
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -4540,7 +4893,7 @@ _ts_decorate21([
|
|
|
4540
4893
|
ToolsController = _ts_decorate21([
|
|
4541
4894
|
Controller13("tools"),
|
|
4542
4895
|
_ts_param19(0, Inject19(AGENT_ACTOR_RESOLVER12)),
|
|
4543
|
-
_ts_param19(1, Inject19(
|
|
4896
|
+
_ts_param19(1, Inject19(AGENT_DEPS_FACTORY6)),
|
|
4544
4897
|
_ts_param19(2, Inject19(AGENT_REGISTRY3)),
|
|
4545
4898
|
_ts_metadata20("design:type", Function),
|
|
4546
4899
|
_ts_metadata20("design:paramtypes", [
|
|
@@ -4622,6 +4975,7 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
|
|
|
4622
4975
|
}
|
|
4623
4976
|
this.collectContributors(instance);
|
|
4624
4977
|
}
|
|
4978
|
+
this.assertPersonas(this.registry.list());
|
|
4625
4979
|
}
|
|
4626
4980
|
/** Build the internal {@link AgentDefinition} from an `@Agent` instance and its options. */
|
|
4627
4981
|
definitionFrom(instance, meta) {
|
|
@@ -4665,10 +5019,48 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
|
|
|
4665
5019
|
} : {},
|
|
4666
5020
|
...meta.handoff !== void 0 ? {
|
|
4667
5021
|
delegatesTo: this.handoffEdges(meta)
|
|
5022
|
+
} : {},
|
|
5023
|
+
...meta.personas !== void 0 ? {
|
|
5024
|
+
personas: meta.personas
|
|
5025
|
+
} : {},
|
|
5026
|
+
...meta.defaultPersona !== void 0 ? {
|
|
5027
|
+
defaultPersona: meta.defaultPersona
|
|
4668
5028
|
} : {}
|
|
4669
5029
|
};
|
|
4670
5030
|
}
|
|
4671
5031
|
/**
|
|
5032
|
+
* Refuse to boot on a persona declaration that could only fail later, per request: a default that
|
|
5033
|
+
* names no persona, an id declared twice, an alias two personas claim, or an alias that is a real
|
|
5034
|
+
* agent's name (which would never be reached — a registered agent always wins).
|
|
5035
|
+
*/
|
|
5036
|
+
assertPersonas(definitions) {
|
|
5037
|
+
const agentNames = new Set(definitions.map((definition) => definition.name));
|
|
5038
|
+
const aliasOwner = /* @__PURE__ */ new Map();
|
|
5039
|
+
for (const definition of definitions) {
|
|
5040
|
+
const ids = /* @__PURE__ */ new Set();
|
|
5041
|
+
for (const persona of definition.personas ?? []) {
|
|
5042
|
+
if (ids.has(persona.id)) {
|
|
5043
|
+
throw new Error(`Agent "${definition.name}" declares persona "${persona.id}" twice.`);
|
|
5044
|
+
}
|
|
5045
|
+
ids.add(persona.id);
|
|
5046
|
+
for (const alias of persona.aliases ?? []) {
|
|
5047
|
+
const owner = `${definition.name}/${persona.id}`;
|
|
5048
|
+
if (agentNames.has(alias)) {
|
|
5049
|
+
throw new Error(`Persona ${owner} claims the alias "${alias}", which is a registered agent's name.`);
|
|
5050
|
+
}
|
|
5051
|
+
const previous = aliasOwner.get(alias);
|
|
5052
|
+
if (previous !== void 0) {
|
|
5053
|
+
throw new Error(`Personas ${previous} and ${owner} both claim the alias "${alias}".`);
|
|
5054
|
+
}
|
|
5055
|
+
aliasOwner.set(alias, owner);
|
|
5056
|
+
}
|
|
5057
|
+
}
|
|
5058
|
+
if (definition.defaultPersona !== void 0 && !ids.has(definition.defaultPersona)) {
|
|
5059
|
+
throw new Error(`Agent "${definition.name}" names "${definition.defaultPersona}" as its default persona, but declares no persona with that id.`);
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
}
|
|
5063
|
+
/**
|
|
4672
5064
|
* Resolve each handoff entry to an {@link AgentDelegation} — its target's registered name, plus
|
|
4673
5065
|
* whether that edge detaches (skipping non-agent classes). A bare name is kept for a plain edge
|
|
4674
5066
|
* rather than an always-object form, so a definition an older host built by hand still reads.
|
|
@@ -5100,7 +5492,7 @@ var LedgerQuotaProvider = class {
|
|
|
5100
5492
|
};
|
|
5101
5493
|
|
|
5102
5494
|
// src/runner/inline-agent-runner.ts
|
|
5103
|
-
import { AGENT_DEPS_FACTORY as
|
|
5495
|
+
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY7, AGENT_STORE as AGENT_STORE6, RUN_ENDED_BEFORE_TOOL_CALL as RUN_ENDED_BEFORE_TOOL_CALL2, RunCancelledError as RunCancelledError2, agentFailureCode as agentFailureCode2, encodeStreamEvent as encodeStreamEvent5, publishAgentRunFailed as publishAgentRunFailed2, releaseThreadRun as releaseThreadRun3, runAgentLoop as runAgentLoop2, settleAll as settleAll2, settleUnsettledDelegation as settleUnsettledDelegation3, streamFailure as streamFailure3 } from "@dudousxd/nestjs-agent-core";
|
|
5104
5496
|
import { Inject as Inject23, Injectable as Injectable11, Logger as Logger7, Optional as Optional10 } from "@nestjs/common";
|
|
5105
5497
|
function _ts_decorate25(decorators, target, key, desc) {
|
|
5106
5498
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -5485,7 +5877,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5485
5877
|
}
|
|
5486
5878
|
});
|
|
5487
5879
|
await Promise.resolve(this.store.failUnsettledToolCalls?.(runId, RUN_ENDED_BEFORE_TOOL_CALL2)).catch(() => 0);
|
|
5488
|
-
await
|
|
5880
|
+
await settleUnsettledDelegation3({
|
|
5489
5881
|
store: this.store,
|
|
5490
5882
|
delivery: deliverTo,
|
|
5491
5883
|
agent: agentName,
|
|
@@ -5580,7 +5972,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
5580
5972
|
};
|
|
5581
5973
|
InlineAgentRunner = _ts_decorate25([
|
|
5582
5974
|
Injectable11(),
|
|
5583
|
-
_ts_param23(0, Inject23(
|
|
5975
|
+
_ts_param23(0, Inject23(AGENT_DEPS_FACTORY7)),
|
|
5584
5976
|
_ts_param23(1, Inject23(AGENT_STORE6)),
|
|
5585
5977
|
_ts_param23(2, Optional10()),
|
|
5586
5978
|
_ts_metadata24("design:type", Function),
|
|
@@ -5792,7 +6184,7 @@ function sharedProviders(durable) {
|
|
|
5792
6184
|
},
|
|
5793
6185
|
AgentDepsFactory2,
|
|
5794
6186
|
{
|
|
5795
|
-
provide:
|
|
6187
|
+
provide: AGENT_DEPS_FACTORY8,
|
|
5796
6188
|
useExisting: AgentDepsFactory2
|
|
5797
6189
|
},
|
|
5798
6190
|
// Populates the registry + contributors (onModuleInit) BEFORE AiToolDiscoveryService synthesizes
|
|
@@ -5865,7 +6257,7 @@ function exportsFor() {
|
|
|
5865
6257
|
AGENT_PROMPT_CONTRIBUTORS3,
|
|
5866
6258
|
AGENT_SKILLS3,
|
|
5867
6259
|
AGENT_MEMORY3,
|
|
5868
|
-
|
|
6260
|
+
AGENT_DEPS_FACTORY8,
|
|
5869
6261
|
AgentDepsFactory2,
|
|
5870
6262
|
AgentService,
|
|
5871
6263
|
ChatQueueService2,
|