@dudousxd/nestjs-agent 0.11.1 → 0.13.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 +60 -0
- package/dist/{agent-deps.factory-D7GdhqdK.d.cts → agent-deps.factory-y2hvoQ6U.d.cts} +200 -16
- package/dist/{agent-deps.factory-D7GdhqdK.d.ts → agent-deps.factory-y2hvoQ6U.d.ts} +200 -16
- package/dist/durable/index.cjs +1735 -499
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +84 -38
- package/dist/durable/index.d.ts +84 -38
- package/dist/durable/index.js +1675 -439
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +1349 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +415 -26
- package/dist/index.d.ts +415 -26
- package/dist/index.js +1289 -234
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -2,12 +2,12 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
4
|
// src/agent.module.ts
|
|
5
|
-
import { AGENT_ACTOR_RESOLVER as
|
|
5
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER8, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_DURABLE_RUNNER, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE3, AGENT_REGISTRY as AGENT_REGISTRY5, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE4, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry5, DefaultRolesPolicy, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
|
|
6
6
|
import { Global, Module } from "@nestjs/common";
|
|
7
7
|
import { DiscoveryModule, RouterModule } from "@nestjs/core";
|
|
8
8
|
|
|
9
9
|
// src/agent-deps.factory.ts
|
|
10
|
-
import { AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK, AGENT_STORE, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2 } from "@dudousxd/nestjs-agent-core";
|
|
10
|
+
import { AGENT_MEMORY, AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_QUOTA_STORE, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK, AGENT_SKILLS, AGENT_STORE, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2, normalizeDelegation, summarizeWithModel, windowHistory } from "@dudousxd/nestjs-agent-core";
|
|
11
11
|
import { AGENT_OPTIONS } from "@dudousxd/nestjs-agent-core";
|
|
12
12
|
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
13
13
|
function _ts_decorate(decorators, target, key, desc) {
|
|
@@ -27,8 +27,9 @@ function _ts_param(paramIndex, decorator) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
__name(_ts_param, "_ts_param");
|
|
30
|
-
function delegateToolName(
|
|
31
|
-
|
|
30
|
+
function delegateToolName(args) {
|
|
31
|
+
const slug = args.target.replace(/[^a-zA-Z0-9]+/g, "_");
|
|
32
|
+
return args.detached === true ? `start_${slug}` : `ask_${slug}`;
|
|
32
33
|
}
|
|
33
34
|
__name(delegateToolName, "delegateToolName");
|
|
34
35
|
var AgentDepsFactory2 = class {
|
|
@@ -45,7 +46,9 @@ var AgentDepsFactory2 = class {
|
|
|
45
46
|
promptContributors;
|
|
46
47
|
quota;
|
|
47
48
|
pricingStore;
|
|
48
|
-
|
|
49
|
+
skills;
|
|
50
|
+
memory;
|
|
51
|
+
constructor(options, model, store, sink, rolesPolicy, registry, agents, promptContributors, quota, pricingStore, skills, memory) {
|
|
49
52
|
this.options = options;
|
|
50
53
|
this.model = model;
|
|
51
54
|
this.store = store;
|
|
@@ -56,6 +59,16 @@ var AgentDepsFactory2 = class {
|
|
|
56
59
|
this.promptContributors = promptContributors;
|
|
57
60
|
this.quota = quota;
|
|
58
61
|
this.pricingStore = pricingStore;
|
|
62
|
+
this.skills = skills;
|
|
63
|
+
this.memory = memory;
|
|
64
|
+
}
|
|
65
|
+
/** The turn's memory seam, shared with the read-back endpoint. Undefined → memory is not configured. */
|
|
66
|
+
memoryConfig() {
|
|
67
|
+
return this.memory;
|
|
68
|
+
}
|
|
69
|
+
/** The turn's skills seam, shared with the listing endpoint. Undefined → skills are not configured. */
|
|
70
|
+
skillsConfig() {
|
|
71
|
+
return this.skills;
|
|
59
72
|
}
|
|
60
73
|
/**
|
|
61
74
|
* The agent a turn uses when the caller names none: the explicit `defaultAgent` option, else the
|
|
@@ -72,7 +85,13 @@ var AgentDepsFactory2 = class {
|
|
|
72
85
|
if (definition === void 0) {
|
|
73
86
|
return void 0;
|
|
74
87
|
}
|
|
75
|
-
const delegated = (definition.delegatesTo ?? []).map(
|
|
88
|
+
const delegated = (definition.delegatesTo ?? []).map((edge) => {
|
|
89
|
+
const { agent, detached } = normalizeDelegation(edge);
|
|
90
|
+
return delegateToolName({
|
|
91
|
+
target: agent,
|
|
92
|
+
detached
|
|
93
|
+
});
|
|
94
|
+
});
|
|
76
95
|
if (definition.tools === void 0 && delegated.length === 0) {
|
|
77
96
|
return void 0;
|
|
78
97
|
}
|
|
@@ -87,6 +106,8 @@ var AgentDepsFactory2 = class {
|
|
|
87
106
|
const toolAllowList = this.effectiveTools(definition);
|
|
88
107
|
const followUpsCount = this.followUpsCount();
|
|
89
108
|
const retrieval = this.options.retrieval;
|
|
109
|
+
const historyPolicy = this.historyPolicy(definition);
|
|
110
|
+
const ask = definition?.ask ?? this.options.ask;
|
|
90
111
|
return {
|
|
91
112
|
model: this.model,
|
|
92
113
|
store: this.store,
|
|
@@ -96,6 +117,12 @@ var AgentDepsFactory2 = class {
|
|
|
96
117
|
promptContributors: this.promptContributors,
|
|
97
118
|
systemPrompt: definition?.systemPrompt ?? "You are a helpful assistant.",
|
|
98
119
|
maxSteps: definition?.maxSteps ?? 8,
|
|
120
|
+
...definition?.maxDelegationDepth !== void 0 ? {
|
|
121
|
+
maxDelegationDepth: definition.maxDelegationDepth
|
|
122
|
+
} : {},
|
|
123
|
+
...definition?.maxAgentAppearances !== void 0 ? {
|
|
124
|
+
maxAgentAppearances: definition.maxAgentAppearances
|
|
125
|
+
} : {},
|
|
99
126
|
...definition?.modelId !== void 0 ? {
|
|
100
127
|
modelId: definition.modelId
|
|
101
128
|
} : {},
|
|
@@ -105,6 +132,37 @@ var AgentDepsFactory2 = class {
|
|
|
105
132
|
...this.pricingStore !== void 0 ? {
|
|
106
133
|
pricingStore: this.pricingStore
|
|
107
134
|
} : {},
|
|
135
|
+
...historyPolicy !== void 0 ? {
|
|
136
|
+
historyPolicy
|
|
137
|
+
} : {},
|
|
138
|
+
inputProcessors: this.options.inputProcessors ?? [],
|
|
139
|
+
outputProcessors: this.options.outputProcessors ?? [],
|
|
140
|
+
...definition?.outputSchema !== void 0 ? {
|
|
141
|
+
outputSchema: definition.outputSchema
|
|
142
|
+
} : {},
|
|
143
|
+
...definition?.outputRepairAttempts !== void 0 ? {
|
|
144
|
+
outputRepairAttempts: definition.outputRepairAttempts
|
|
145
|
+
} : {},
|
|
146
|
+
...definition?.intake !== void 0 ? {
|
|
147
|
+
intake: definition.intake
|
|
148
|
+
} : {},
|
|
149
|
+
// Most specific wins, exactly as `historyPolicy` resolves: the agent's own `@Agent({ ask })`,
|
|
150
|
+
// else the module-wide flag. Both are module config, so every process of a deployment agrees.
|
|
151
|
+
...ask === true ? {
|
|
152
|
+
ask: true
|
|
153
|
+
} : {},
|
|
154
|
+
// Module-wide, never per-agent: a skill is a procedure, not a persona, and an agent that could
|
|
155
|
+
// opt out of one would make the catalog depend on which agent a turn happened to select — a
|
|
156
|
+
// per-turn fact the worker re-deriving the tool list cannot see.
|
|
157
|
+
...this.skills !== void 0 ? {
|
|
158
|
+
skills: this.skills
|
|
159
|
+
} : {},
|
|
160
|
+
// Module-wide, never per-agent, for the same reason skills are: which memories a turn carries
|
|
161
|
+
// cannot depend on which persona answered it, or the worker re-deriving a dispatched turn's
|
|
162
|
+
// tool list would disagree with the loop about whether `remember` was offered.
|
|
163
|
+
...this.memory !== void 0 ? {
|
|
164
|
+
memory: this.memory
|
|
165
|
+
} : {},
|
|
108
166
|
...toolAllowList !== void 0 ? {
|
|
109
167
|
toolAllowList
|
|
110
168
|
} : {},
|
|
@@ -125,6 +183,36 @@ var AgentDepsFactory2 = class {
|
|
|
125
183
|
} : {}
|
|
126
184
|
};
|
|
127
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* The ceiling on how much of a thread this agent's turns carry, most specific wins: the agent's
|
|
188
|
+
* own `@Agent({ history })`, else a module-wide custom `historyPolicy`, else the module-wide
|
|
189
|
+
* `history` window. Undefined → unbounded, the behaviour of a module that configures none.
|
|
190
|
+
*/
|
|
191
|
+
historyPolicy(definition) {
|
|
192
|
+
if (definition?.history !== void 0) {
|
|
193
|
+
return this.window(definition.history);
|
|
194
|
+
}
|
|
195
|
+
if (this.options.historyPolicy !== void 0) {
|
|
196
|
+
return this.options.historyPolicy;
|
|
197
|
+
}
|
|
198
|
+
return this.options.history === void 0 ? void 0 : this.window(this.options.history);
|
|
199
|
+
}
|
|
200
|
+
/** Build the built-in window policy from the declarative `{ maxMessages, maxTokens, summarize }`. */
|
|
201
|
+
window(config) {
|
|
202
|
+
return windowHistory({
|
|
203
|
+
...config.maxMessages !== void 0 ? {
|
|
204
|
+
maxMessages: config.maxMessages
|
|
205
|
+
} : {},
|
|
206
|
+
...config.maxTokens !== void 0 ? {
|
|
207
|
+
maxTokens: config.maxTokens
|
|
208
|
+
} : {},
|
|
209
|
+
// The shared module model, not a per-agent one: an agent's `modelId` is an accounting label,
|
|
210
|
+
// and only one provider is ever bound.
|
|
211
|
+
...config.summarize === true ? {
|
|
212
|
+
summarize: summarizeWithModel(this.model)
|
|
213
|
+
} : {}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
128
216
|
/** Normalize the `followUps` option (`true` → 3, `{ count }` → count) to a number, or undefined. */
|
|
129
217
|
followUpsCount() {
|
|
130
218
|
const followUps = this.options.followUps;
|
|
@@ -150,6 +238,10 @@ AgentDepsFactory2 = _ts_decorate([
|
|
|
150
238
|
_ts_param(8, Inject(AGENT_QUOTA_STORE)),
|
|
151
239
|
_ts_param(9, Optional()),
|
|
152
240
|
_ts_param(9, Inject(AGENT_PRICING_STORE)),
|
|
241
|
+
_ts_param(10, Optional()),
|
|
242
|
+
_ts_param(10, Inject(AGENT_SKILLS)),
|
|
243
|
+
_ts_param(11, Optional()),
|
|
244
|
+
_ts_param(11, Inject(AGENT_MEMORY)),
|
|
153
245
|
_ts_metadata("design:type", Function),
|
|
154
246
|
_ts_metadata("design:paramtypes", [
|
|
155
247
|
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
@@ -161,13 +253,15 @@ AgentDepsFactory2 = _ts_decorate([
|
|
|
161
253
|
typeof AgentRegistry2 === "undefined" ? Object : AgentRegistry2,
|
|
162
254
|
Array,
|
|
163
255
|
Object,
|
|
256
|
+
Object,
|
|
257
|
+
Object,
|
|
164
258
|
Object
|
|
165
259
|
])
|
|
166
260
|
], AgentDepsFactory2);
|
|
167
261
|
|
|
168
262
|
// src/agent.service.ts
|
|
169
|
-
import { AGENT_DEPS_FACTORY, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2 } from "@dudousxd/nestjs-agent-core";
|
|
170
|
-
import { BadRequestException, ForbiddenException, Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException } from "@nestjs/common";
|
|
263
|
+
import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2 } from "@dudousxd/nestjs-agent-core";
|
|
264
|
+
import { BadRequestException, ForbiddenException, Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
|
|
171
265
|
|
|
172
266
|
// src/agent-deps.ts
|
|
173
267
|
function utcDay(date = /* @__PURE__ */ new Date()) {
|
|
@@ -211,14 +305,17 @@ var AgentService = class {
|
|
|
211
305
|
store;
|
|
212
306
|
deps;
|
|
213
307
|
quota;
|
|
214
|
-
|
|
308
|
+
staging;
|
|
309
|
+
constructor(runner, store, deps, quota, staging) {
|
|
215
310
|
this.runner = runner;
|
|
216
311
|
this.store = store;
|
|
217
312
|
this.deps = deps;
|
|
218
313
|
this.quota = quota;
|
|
314
|
+
this.staging = staging;
|
|
219
315
|
}
|
|
220
316
|
async chat(params) {
|
|
221
317
|
const agentName = await this.resolveAgentName(params.agentName, params.threadId);
|
|
318
|
+
const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
|
|
222
319
|
let threadId = params.threadId;
|
|
223
320
|
if (threadId === void 0) {
|
|
224
321
|
if (params.regenerate === true) {
|
|
@@ -243,8 +340,8 @@ var AgentService = class {
|
|
|
243
340
|
...params.regenerate === true ? {
|
|
244
341
|
regenerate: true
|
|
245
342
|
} : {},
|
|
246
|
-
...
|
|
247
|
-
attachments
|
|
343
|
+
...attachments.length > 0 ? {
|
|
344
|
+
attachments
|
|
248
345
|
} : {},
|
|
249
346
|
...params.pageContext !== void 0 ? {
|
|
250
347
|
pageContext: params.pageContext
|
|
@@ -257,18 +354,66 @@ var AgentService = class {
|
|
|
257
354
|
threadId
|
|
258
355
|
};
|
|
259
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* Rebuild this turn's attachments from the staging store, keyed by the ids the caller claimed.
|
|
359
|
+
* The model provider fetches {@link MessageAttachment.url} verbatim, so that url is only ever
|
|
360
|
+
* allowed to come from the host's own store — a caller that could name it could point the server
|
|
361
|
+
* at anything it can reach (cloud metadata, internal services) and read the response back out of
|
|
362
|
+
* the model's answer.
|
|
363
|
+
*
|
|
364
|
+
* No store bound means no way to tell an id the actor owns from one they don't, so a turn simply
|
|
365
|
+
* cannot carry attachments: 501 rather than trusting the request.
|
|
366
|
+
*/
|
|
367
|
+
async resolveAttachments(actor, refs) {
|
|
368
|
+
if (refs.length === 0) {
|
|
369
|
+
return [];
|
|
370
|
+
}
|
|
371
|
+
const staging = this.staging;
|
|
372
|
+
if (staging === void 0 || typeof staging.resolve !== "function") {
|
|
373
|
+
throw new NotImplementedException("Message attachments require an AGENT_ATTACHMENT_STAGING provider implementing resolve(); attachment urls are never taken from the request.");
|
|
374
|
+
}
|
|
375
|
+
const resolved = [];
|
|
376
|
+
for (const ref of refs) {
|
|
377
|
+
const attachment = await staging.resolve({
|
|
378
|
+
mediaId: ref.mediaId,
|
|
379
|
+
actor
|
|
380
|
+
});
|
|
381
|
+
if (attachment === null) {
|
|
382
|
+
throw new ForbiddenException(`attachment ${ref.mediaId} is not available to this actor`);
|
|
383
|
+
}
|
|
384
|
+
resolved.push(attachment);
|
|
385
|
+
}
|
|
386
|
+
return resolved;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The run's live token stream, WITHOUT an ownership check — for in-process callers that are
|
|
390
|
+
* already authorized (the MCP bridge, a host's own job code), the same split as
|
|
391
|
+
* {@link signalToolCall} vs {@link approve}. Anything reachable from a request must go through
|
|
392
|
+
* {@link subscribeAs} instead: a runId is the only thing standing between a caller and another
|
|
393
|
+
* actor's answer, tool arguments and tool results.
|
|
394
|
+
*/
|
|
260
395
|
subscribe(runId) {
|
|
261
396
|
return this.deps.forAgent().sink.subscribe(runId);
|
|
262
397
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
398
|
+
/**
|
|
399
|
+
* {@link subscribe}, gated the way {@link cancel} is: only the actor whose thread is currently
|
|
400
|
+
* streaming this run may read it. A run that has already finished is reported missing rather than
|
|
401
|
+
* replayed — the runner clears the thread's active stream as the run ends, and that field is what
|
|
402
|
+
* ownership is derived from.
|
|
403
|
+
*/
|
|
404
|
+
async subscribeAs(actor, runId) {
|
|
405
|
+
await this.assertOwnsActiveStream(actor, runId);
|
|
406
|
+
return this.subscribe(runId);
|
|
407
|
+
}
|
|
408
|
+
async approve(actor, toolCallId2) {
|
|
409
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
410
|
+
return this.signalToolCall(toolCallId2, {
|
|
266
411
|
approved: true
|
|
267
412
|
});
|
|
268
413
|
}
|
|
269
|
-
async reject(actor,
|
|
270
|
-
await this.assertOwnsToolCall(actor,
|
|
271
|
-
return this.signalToolCall(
|
|
414
|
+
async reject(actor, toolCallId2, reason) {
|
|
415
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
416
|
+
return this.signalToolCall(toolCallId2, {
|
|
272
417
|
approved: false,
|
|
273
418
|
...reason !== void 0 ? {
|
|
274
419
|
reason
|
|
@@ -276,6 +421,34 @@ var AgentService = class {
|
|
|
276
421
|
});
|
|
277
422
|
}
|
|
278
423
|
/**
|
|
424
|
+
* Answer a parked question set. An omitted question takes the request's own pre-picked default —
|
|
425
|
+
* resolved by the LOOP against the request it already holds, so "the user just submitted" and
|
|
426
|
+
* "the user picked exactly the defaults" persist as the same answers, and no client has to
|
|
427
|
+
* re-send what it was shown.
|
|
428
|
+
*/
|
|
429
|
+
async answer(actor, toolCallId2, answers2 = {}) {
|
|
430
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
431
|
+
const reply = {
|
|
432
|
+
answers: answers2,
|
|
433
|
+
answeredByRef: actor.id
|
|
434
|
+
};
|
|
435
|
+
return this.signalToolCall(toolCallId2, reply);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Decline to answer and let the agent proceed on its own assumptions. NOT the same as confirming
|
|
439
|
+
* them: the run records this as a rejection, so a reader auditing what the agent was told can
|
|
440
|
+
* tell a choice the user made from one they refused to make.
|
|
441
|
+
*/
|
|
442
|
+
async skip(actor, toolCallId2) {
|
|
443
|
+
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
444
|
+
const reply = {
|
|
445
|
+
answers: {},
|
|
446
|
+
skipped: true,
|
|
447
|
+
answeredByRef: actor.id
|
|
448
|
+
};
|
|
449
|
+
return this.signalToolCall(toolCallId2, reply);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
279
452
|
* The decision core behind approve/reject, WITHOUT an ownership check: resolves the run
|
|
280
453
|
* currently awaiting `toolCallId` and signals it. `approve`/`reject` above call this after their
|
|
281
454
|
* own `assertOwnsToolCall` gate; the console `AgentApprovalPort` adapter (bound by `AgentModule`)
|
|
@@ -283,9 +456,9 @@ var AgentService = class {
|
|
|
283
456
|
* re-deriving thread ownership here would reject a legitimate operator decision (an operator is
|
|
284
457
|
* not the thread's own actor).
|
|
285
458
|
*/
|
|
286
|
-
async signalToolCall(
|
|
287
|
-
const runId = await this.resolveRunForToolCall(
|
|
288
|
-
return this.runner.signal(runId,
|
|
459
|
+
async signalToolCall(toolCallId2, reply) {
|
|
460
|
+
const runId = await this.resolveRunForToolCall(toolCallId2);
|
|
461
|
+
return this.runner.signal(runId, toolCallId2, reply);
|
|
289
462
|
}
|
|
290
463
|
async cancel(actor, runId) {
|
|
291
464
|
await this.assertOwnsActiveStream(actor, runId);
|
|
@@ -352,20 +525,33 @@ var AgentService = class {
|
|
|
352
525
|
/**
|
|
353
526
|
* Agent-selection precedence for a `chat()` call with no explicit `agentName`: the thread's own
|
|
354
527
|
* `defaultAgent` (if the thread exists and one is set) wins over the module's configured default.
|
|
355
|
-
* Skips the
|
|
528
|
+
* Skips the store entirely when the caller already named an agent or there's no thread yet.
|
|
529
|
+
*
|
|
530
|
+
* What this needs is one nullable scalar, so it asks for one. `getThread` returns the entire
|
|
531
|
+
* transcript — every message, every persisted tool output — and this discards all of it; on a
|
|
532
|
+
* long thread with large tool results that is hundreds of kilobytes read per turn, outside the
|
|
533
|
+
* workflow, for a string. A store predating {@link ThreadDefaultAgentReader} still answers, via
|
|
534
|
+
* the full read.
|
|
356
535
|
*/
|
|
357
536
|
async resolveAgentName(agentName, threadId) {
|
|
358
537
|
if (agentName !== void 0) {
|
|
359
538
|
return agentName;
|
|
360
539
|
}
|
|
361
540
|
if (threadId !== void 0) {
|
|
362
|
-
const
|
|
363
|
-
if (
|
|
364
|
-
return
|
|
541
|
+
const threadDefault = await this.threadDefaultAgent(threadId);
|
|
542
|
+
if (threadDefault !== null) {
|
|
543
|
+
return threadDefault;
|
|
365
544
|
}
|
|
366
545
|
}
|
|
367
546
|
return this.deps.defaultAgentName();
|
|
368
547
|
}
|
|
548
|
+
async threadDefaultAgent(threadId) {
|
|
549
|
+
const projecting = this.store;
|
|
550
|
+
if (typeof projecting.defaultAgentForThread === "function") {
|
|
551
|
+
return projecting.defaultAgentForThread(threadId);
|
|
552
|
+
}
|
|
553
|
+
return (await this.store.getThread(threadId))?.defaultAgent ?? null;
|
|
554
|
+
}
|
|
369
555
|
async toSummaryView(thread) {
|
|
370
556
|
return {
|
|
371
557
|
...thread,
|
|
@@ -397,6 +583,67 @@ var AgentService = class {
|
|
|
397
583
|
return this.store.truncateFrom(threadId, messageId);
|
|
398
584
|
}
|
|
399
585
|
/**
|
|
586
|
+
* Every file this actor has staged, newest first — across threads, including uploads that were
|
|
587
|
+
* never sent, which nothing else on this surface can see.
|
|
588
|
+
*
|
|
589
|
+
* Metadata only. A url is minted per turn by `resolve` so it can be short-lived, and handing one
|
|
590
|
+
* back per entry would undo that for the price of rendering a list.
|
|
591
|
+
*/
|
|
592
|
+
async listAttachments(actor, options = {}) {
|
|
593
|
+
const list = this.attachmentInventory();
|
|
594
|
+
return list({
|
|
595
|
+
actor,
|
|
596
|
+
...options.limit !== void 0 ? {
|
|
597
|
+
limit: options.limit
|
|
598
|
+
} : {}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* This actor's staged media that no live message references and that is old enough not to be an
|
|
603
|
+
* upload in flight — the candidate set for a sweep. Returns them; never deletes them. The bytes
|
|
604
|
+
* are the host's, and so is the decision.
|
|
605
|
+
*
|
|
606
|
+
* `olderThan` is required and has no default. How long a composer may sit open with a file
|
|
607
|
+
* attached is the host's knowledge, and a library-chosen grace period would eventually delete a
|
|
608
|
+
* file someone was about to send. The staging store is asked to apply it, and the result is
|
|
609
|
+
* filtered again here: a store that ignores the hint would otherwise turn this into exactly that
|
|
610
|
+
* bug, silently.
|
|
611
|
+
*
|
|
612
|
+
* Both halves must be answerable or this refuses. An unanswerable reference query means "cannot
|
|
613
|
+
* tell", and treating it as "nothing is referenced" would hand back every attachment the actor
|
|
614
|
+
* ever sent, marked safe to delete.
|
|
615
|
+
*/
|
|
616
|
+
async collectableAttachments(actor, options) {
|
|
617
|
+
const list = this.attachmentInventory();
|
|
618
|
+
const referencedMediaIds = this.store.referencedMediaIds?.bind(this.store);
|
|
619
|
+
if (referencedMediaIds === void 0) {
|
|
620
|
+
throw new NotImplementedException("Collecting attachments requires an AgentStore that implements referencedMediaIds(); the bound store cannot say which media a message still references, and guessing would delete files that are in use.");
|
|
621
|
+
}
|
|
622
|
+
const stagedBefore = options.olderThan.toISOString();
|
|
623
|
+
const inventory = await list({
|
|
624
|
+
actor,
|
|
625
|
+
stagedBefore,
|
|
626
|
+
...options.limit !== void 0 ? {
|
|
627
|
+
limit: options.limit
|
|
628
|
+
} : {}
|
|
629
|
+
});
|
|
630
|
+
const aged = inventory.filter((entry) => entry.createdAt < stagedBefore);
|
|
631
|
+
const referenced = new Set(await referencedMediaIds(actor.id, aged.map((entry) => entry.mediaId)));
|
|
632
|
+
return aged.filter((entry) => !referenced.has(entry.mediaId));
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* The bound staging store's `list`, or a refusal. Absence is never answered with an empty list:
|
|
636
|
+
* "this host keeps no inventory" and "this actor has no files" are opposite facts that would
|
|
637
|
+
* otherwise render identically — as a clean file list, and as a sweep that collects nothing.
|
|
638
|
+
*/
|
|
639
|
+
attachmentInventory() {
|
|
640
|
+
const list = this.staging?.list?.bind(this.staging);
|
|
641
|
+
if (list === void 0) {
|
|
642
|
+
throw new NotImplementedException("Listing attachments requires an AGENT_ATTACHMENT_STAGING provider implementing list(); the host owns the staged bytes, so only it can enumerate them.");
|
|
643
|
+
}
|
|
644
|
+
return list;
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
400
647
|
* The day's usage for the badge: tokens + summed USD cost from the store, and the configured
|
|
401
648
|
* limit from the quota store (null → unlimited). `withinLimit` comes from the quota store so it
|
|
402
649
|
* can never drift from what enforcement uses.
|
|
@@ -438,24 +685,26 @@ var AgentService = class {
|
|
|
438
685
|
* out from run resolution (see {@link resolveRunForToolCall}) so the console `AgentApprovalPort`
|
|
439
686
|
* adapter can resolve+signal a decision WITHOUT this check — it is authorized upstream instead.
|
|
440
687
|
*/
|
|
441
|
-
async assertOwnsToolCall(actor,
|
|
442
|
-
const owner = await this.store.ownerOfToolCall(
|
|
688
|
+
async assertOwnsToolCall(actor, toolCallId2) {
|
|
689
|
+
const owner = await this.store.ownerOfToolCall(toolCallId2);
|
|
443
690
|
if (owner === null) {
|
|
444
|
-
throw new NotFoundException(`tool call ${
|
|
691
|
+
throw new NotFoundException(`tool call ${toolCallId2} not found`);
|
|
445
692
|
}
|
|
446
693
|
if (owner !== actor.id) {
|
|
447
694
|
throw new ForbiddenException("tool call belongs to another actor");
|
|
448
695
|
}
|
|
449
696
|
}
|
|
450
697
|
/**
|
|
451
|
-
* Resolve the run
|
|
452
|
-
* sub-agent's own child run when the pending
|
|
453
|
-
*
|
|
698
|
+
* Resolve the run awaiting `toolCallId`. Derived server-side from the tool call alone — the client
|
|
699
|
+
* never knows or supplies a runId, and that run is the sub-agent's own child run when the pending
|
|
700
|
+
* call belongs to a delegated agent. The store answers from the CALL'S OWN `runId` where it has
|
|
701
|
+
* one; see `AgentStore.runForToolCall` for why that matters once a thread can hold more than one
|
|
702
|
+
* live run.
|
|
454
703
|
*/
|
|
455
|
-
async resolveRunForToolCall(
|
|
456
|
-
const runId = await this.store.runForToolCall(
|
|
704
|
+
async resolveRunForToolCall(toolCallId2) {
|
|
705
|
+
const runId = await this.store.runForToolCall(toolCallId2);
|
|
457
706
|
if (runId === null) {
|
|
458
|
-
throw new NotFoundException(`tool call ${
|
|
707
|
+
throw new NotFoundException(`tool call ${toolCallId2} has no active run to signal`);
|
|
459
708
|
}
|
|
460
709
|
return runId;
|
|
461
710
|
}
|
|
@@ -476,12 +725,15 @@ AgentService = _ts_decorate2([
|
|
|
476
725
|
_ts_param2(1, Inject2(AGENT_STORE2)),
|
|
477
726
|
_ts_param2(2, Inject2(AGENT_DEPS_FACTORY)),
|
|
478
727
|
_ts_param2(3, Inject2(AGENT_QUOTA_STORE2)),
|
|
728
|
+
_ts_param2(4, Optional2()),
|
|
729
|
+
_ts_param2(4, Inject2(AGENT_ATTACHMENT_STAGING)),
|
|
479
730
|
_ts_metadata2("design:type", Function),
|
|
480
731
|
_ts_metadata2("design:paramtypes", [
|
|
481
732
|
typeof AgentRunner === "undefined" ? Object : AgentRunner,
|
|
482
733
|
typeof AgentStore === "undefined" ? Object : AgentStore,
|
|
483
734
|
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
484
|
-
Object
|
|
735
|
+
Object,
|
|
736
|
+
typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
|
|
485
737
|
])
|
|
486
738
|
], AgentService);
|
|
487
739
|
|
|
@@ -506,16 +758,16 @@ var AgentApprovalPortAdapter = class {
|
|
|
506
758
|
constructor(agent) {
|
|
507
759
|
this.agent = agent;
|
|
508
760
|
}
|
|
509
|
-
async approve(
|
|
510
|
-
await this.agent.signalToolCall(
|
|
761
|
+
async approve(toolCallId2, opts) {
|
|
762
|
+
await this.agent.signalToolCall(toolCallId2, {
|
|
511
763
|
approved: true,
|
|
512
764
|
...opts?.executedByRef !== void 0 ? {
|
|
513
765
|
executedByRef: opts.executedByRef
|
|
514
766
|
} : {}
|
|
515
767
|
});
|
|
516
768
|
}
|
|
517
|
-
async reject(
|
|
518
|
-
await this.agent.signalToolCall(
|
|
769
|
+
async reject(toolCallId2, opts) {
|
|
770
|
+
await this.agent.signalToolCall(toolCallId2, {
|
|
519
771
|
approved: false,
|
|
520
772
|
...opts?.executedByRef !== void 0 ? {
|
|
521
773
|
executedByRef: opts.executedByRef
|
|
@@ -593,8 +845,8 @@ AgentsController = _ts_decorate4([
|
|
|
593
845
|
], AgentsController);
|
|
594
846
|
|
|
595
847
|
// src/controller/attachments.controller.ts
|
|
596
|
-
import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING, AGENT_OPTIONS as AGENT_OPTIONS2 } from "@dudousxd/nestjs-agent-core";
|
|
597
|
-
import { BadRequestException as BadRequestException2, Controller as Controller2, Inject as Inject4, NotImplementedException as NotImplementedException2, Optional as
|
|
848
|
+
import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_OPTIONS as AGENT_OPTIONS2 } from "@dudousxd/nestjs-agent-core";
|
|
849
|
+
import { BadRequestException as BadRequestException2, Controller as Controller2, Get as Get2, Inject as Inject4, NotImplementedException as NotImplementedException2, Optional as Optional3, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
|
|
598
850
|
import { FileInterceptor } from "@nestjs/platform-express";
|
|
599
851
|
function _ts_decorate5(decorators, target, key, desc) {
|
|
600
852
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -614,6 +866,8 @@ function _ts_param4(paramIndex, decorator) {
|
|
|
614
866
|
}
|
|
615
867
|
__name(_ts_param4, "_ts_param");
|
|
616
868
|
var DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
|
|
869
|
+
var HARD_MAX_ATTACHMENT_BYTES = 32 * 1024 * 1024;
|
|
870
|
+
var ATTACHMENT_PAGE_SIZE = 50;
|
|
617
871
|
var DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES = [
|
|
618
872
|
"image/png",
|
|
619
873
|
"image/jpeg",
|
|
@@ -629,10 +883,12 @@ var AttachmentsController = class {
|
|
|
629
883
|
}
|
|
630
884
|
options;
|
|
631
885
|
actorResolver;
|
|
886
|
+
agents;
|
|
632
887
|
staging;
|
|
633
|
-
constructor(options, actorResolver, staging) {
|
|
888
|
+
constructor(options, actorResolver, agents, staging) {
|
|
634
889
|
this.options = options;
|
|
635
890
|
this.actorResolver = actorResolver;
|
|
891
|
+
this.agents = agents;
|
|
636
892
|
this.staging = staging;
|
|
637
893
|
}
|
|
638
894
|
/**
|
|
@@ -646,6 +902,21 @@ var AttachmentsController = class {
|
|
|
646
902
|
throw new Error("AgentModule: attachments.upload is true but no AGENT_ATTACHMENT_STAGING provider is bound. Bind one (e.g. `{ provide: AGENT_ATTACHMENT_STAGING, useClass: MyStagingStore }`) in a module imported alongside AgentModule, or set attachments.upload to false.");
|
|
647
903
|
}
|
|
648
904
|
}
|
|
905
|
+
/**
|
|
906
|
+
* The caller's own staged files, newest first — the one question `GET /agent/threads/:id` cannot
|
|
907
|
+
* answer, since an upload that was never sent belongs to no thread.
|
|
908
|
+
*
|
|
909
|
+
* Scoped by the RESOLVED actor and nothing else. There is deliberately no `threadId` filter: a
|
|
910
|
+
* thread's attachments already ride on its messages in the thread payload, and re-serving them
|
|
911
|
+
* from here would add a second ownership path to get wrong for information the client already
|
|
912
|
+
* holds. Metadata only — see {@link StagedAttachment}.
|
|
913
|
+
*/
|
|
914
|
+
async list(req) {
|
|
915
|
+
const actor = await this.actorResolver.resolve(req);
|
|
916
|
+
return this.agents.listAttachments(actor, {
|
|
917
|
+
limit: ATTACHMENT_PAGE_SIZE
|
|
918
|
+
});
|
|
919
|
+
}
|
|
649
920
|
async upload(req, file) {
|
|
650
921
|
if (this.staging === void 0) {
|
|
651
922
|
throw new NotImplementedException2("Attachment upload is not configured on this server.");
|
|
@@ -671,9 +942,22 @@ var AttachmentsController = class {
|
|
|
671
942
|
});
|
|
672
943
|
}
|
|
673
944
|
};
|
|
945
|
+
_ts_decorate5([
|
|
946
|
+
Get2(),
|
|
947
|
+
_ts_param4(0, Req()),
|
|
948
|
+
_ts_metadata5("design:type", Function),
|
|
949
|
+
_ts_metadata5("design:paramtypes", [
|
|
950
|
+
typeof Request === "undefined" ? Object : Request
|
|
951
|
+
]),
|
|
952
|
+
_ts_metadata5("design:returntype", Promise)
|
|
953
|
+
], AttachmentsController.prototype, "list", null);
|
|
674
954
|
_ts_decorate5([
|
|
675
955
|
Post(),
|
|
676
|
-
UseInterceptors(FileInterceptor("file"
|
|
956
|
+
UseInterceptors(FileInterceptor("file", {
|
|
957
|
+
limits: {
|
|
958
|
+
fileSize: HARD_MAX_ATTACHMENT_BYTES
|
|
959
|
+
}
|
|
960
|
+
})),
|
|
677
961
|
_ts_param4(0, Req()),
|
|
678
962
|
_ts_param4(1, UploadedFile()),
|
|
679
963
|
_ts_metadata5("design:type", Function),
|
|
@@ -687,19 +971,20 @@ AttachmentsController = _ts_decorate5([
|
|
|
687
971
|
Controller2("attachments"),
|
|
688
972
|
_ts_param4(0, Inject4(AGENT_OPTIONS2)),
|
|
689
973
|
_ts_param4(1, Inject4(AGENT_ACTOR_RESOLVER)),
|
|
690
|
-
_ts_param4(
|
|
691
|
-
_ts_param4(
|
|
974
|
+
_ts_param4(3, Optional3()),
|
|
975
|
+
_ts_param4(3, Inject4(AGENT_ATTACHMENT_STAGING2)),
|
|
692
976
|
_ts_metadata5("design:type", Function),
|
|
693
977
|
_ts_metadata5("design:paramtypes", [
|
|
694
978
|
typeof AgentModuleOptions === "undefined" ? Object : AgentModuleOptions,
|
|
695
979
|
typeof ActorResolver === "undefined" ? Object : ActorResolver,
|
|
980
|
+
typeof AgentService === "undefined" ? Object : AgentService,
|
|
696
981
|
Object
|
|
697
982
|
])
|
|
698
983
|
], AttachmentsController);
|
|
699
984
|
|
|
700
985
|
// src/controller/chat.controller.ts
|
|
701
986
|
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER2, AgentStreamError } from "@dudousxd/nestjs-agent-core";
|
|
702
|
-
import { Body, Controller as Controller3, Get as
|
|
987
|
+
import { BadRequestException as BadRequestException3, Body, Controller as Controller3, Get as Get3, Inject as Inject5, Param, Post as Post2, Req as Req2, Res } from "@nestjs/common";
|
|
703
988
|
function _ts_decorate6(decorators, target, key, desc) {
|
|
704
989
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
705
990
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -717,6 +1002,31 @@ function _ts_param5(paramIndex, decorator) {
|
|
|
717
1002
|
};
|
|
718
1003
|
}
|
|
719
1004
|
__name(_ts_param5, "_ts_param");
|
|
1005
|
+
var MAX_ATTACHMENTS_PER_MESSAGE = 10;
|
|
1006
|
+
function attachmentRefs(claimed) {
|
|
1007
|
+
if (claimed === void 0) {
|
|
1008
|
+
return [];
|
|
1009
|
+
}
|
|
1010
|
+
if (!Array.isArray(claimed)) {
|
|
1011
|
+
throw new BadRequestException3("attachments must be an array of { mediaId }");
|
|
1012
|
+
}
|
|
1013
|
+
if (claimed.length > MAX_ATTACHMENTS_PER_MESSAGE) {
|
|
1014
|
+
throw new BadRequestException3(`a message may carry at most ${MAX_ATTACHMENTS_PER_MESSAGE} attachments`);
|
|
1015
|
+
}
|
|
1016
|
+
return claimed.map((entry) => {
|
|
1017
|
+
if (typeof entry !== "object" || entry === null || !("mediaId" in entry)) {
|
|
1018
|
+
throw new BadRequestException3("each attachment must be an object with a mediaId");
|
|
1019
|
+
}
|
|
1020
|
+
const { mediaId } = entry;
|
|
1021
|
+
if (typeof mediaId !== "string" || mediaId.length === 0) {
|
|
1022
|
+
throw new BadRequestException3("each attachment must carry a non-empty string mediaId");
|
|
1023
|
+
}
|
|
1024
|
+
return {
|
|
1025
|
+
mediaId
|
|
1026
|
+
};
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
__name(attachmentRefs, "attachmentRefs");
|
|
720
1030
|
var ChatController = class {
|
|
721
1031
|
static {
|
|
722
1032
|
__name(this, "ChatController");
|
|
@@ -729,6 +1039,7 @@ var ChatController = class {
|
|
|
729
1039
|
}
|
|
730
1040
|
async chat(req, res, body) {
|
|
731
1041
|
const actor = await this.actorResolver.resolve(req);
|
|
1042
|
+
const attachments = attachmentRefs(body.attachments);
|
|
732
1043
|
const { runId, threadId } = await this.agent.chat({
|
|
733
1044
|
actor,
|
|
734
1045
|
message: body.message,
|
|
@@ -738,8 +1049,8 @@ var ChatController = class {
|
|
|
738
1049
|
...body.agent !== void 0 ? {
|
|
739
1050
|
agentName: body.agent
|
|
740
1051
|
} : {},
|
|
741
|
-
...
|
|
742
|
-
attachments
|
|
1052
|
+
...attachments.length > 0 ? {
|
|
1053
|
+
attachments
|
|
743
1054
|
} : {},
|
|
744
1055
|
...body.pageContext !== void 0 ? {
|
|
745
1056
|
pageContext: body.pageContext
|
|
@@ -751,10 +1062,11 @@ var ChatController = class {
|
|
|
751
1062
|
transient: true
|
|
752
1063
|
} : {}
|
|
753
1064
|
});
|
|
754
|
-
await this.pipe(res, runId, threadId);
|
|
1065
|
+
await this.pipe(res, runId, this.agent.subscribe(runId), threadId);
|
|
755
1066
|
}
|
|
756
|
-
async stream(runId, res) {
|
|
757
|
-
await this.
|
|
1067
|
+
async stream(req, runId, res) {
|
|
1068
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1069
|
+
await this.pipe(res, runId, await this.agent.subscribeAs(actor, runId));
|
|
758
1070
|
}
|
|
759
1071
|
async cancel(req, runId) {
|
|
760
1072
|
const actor = await this.actorResolver.resolve(req);
|
|
@@ -763,7 +1075,7 @@ var ChatController = class {
|
|
|
763
1075
|
aborted: true
|
|
764
1076
|
};
|
|
765
1077
|
}
|
|
766
|
-
async pipe(res, runId, threadId) {
|
|
1078
|
+
async pipe(res, runId, events, threadId) {
|
|
767
1079
|
res.setHeader("Content-Type", "text/event-stream");
|
|
768
1080
|
res.setHeader("Cache-Control", "no-cache");
|
|
769
1081
|
res.setHeader("Connection", "keep-alive");
|
|
@@ -781,7 +1093,7 @@ data: ${JSON.stringify({
|
|
|
781
1093
|
const decoder = new TextDecoder();
|
|
782
1094
|
let buffer = "";
|
|
783
1095
|
try {
|
|
784
|
-
for await (const chunk of
|
|
1096
|
+
for await (const chunk of events) {
|
|
785
1097
|
buffer += decoder.decode(chunk, {
|
|
786
1098
|
stream: true
|
|
787
1099
|
});
|
|
@@ -833,11 +1145,13 @@ _ts_decorate6([
|
|
|
833
1145
|
_ts_metadata6("design:returntype", Promise)
|
|
834
1146
|
], ChatController.prototype, "chat", null);
|
|
835
1147
|
_ts_decorate6([
|
|
836
|
-
|
|
837
|
-
_ts_param5(0,
|
|
838
|
-
_ts_param5(1,
|
|
1148
|
+
Get3("chat/:runId/stream"),
|
|
1149
|
+
_ts_param5(0, Req2()),
|
|
1150
|
+
_ts_param5(1, Param("runId")),
|
|
1151
|
+
_ts_param5(2, Res()),
|
|
839
1152
|
_ts_metadata6("design:type", Function),
|
|
840
1153
|
_ts_metadata6("design:paramtypes", [
|
|
1154
|
+
typeof Request === "undefined" ? Object : Request,
|
|
841
1155
|
String,
|
|
842
1156
|
typeof Response === "undefined" ? Object : Response
|
|
843
1157
|
]),
|
|
@@ -864,9 +1178,9 @@ ChatController = _ts_decorate6([
|
|
|
864
1178
|
])
|
|
865
1179
|
], ChatController);
|
|
866
1180
|
|
|
867
|
-
// src/controller/
|
|
868
|
-
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER3 } from "@dudousxd/nestjs-agent-core";
|
|
869
|
-
import { Controller as Controller4, Get as
|
|
1181
|
+
// src/controller/memories.controller.ts
|
|
1182
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER3, AGENT_MEMORY as AGENT_MEMORY2, memoryForgetVerdict, offerMemories } from "@dudousxd/nestjs-agent-core";
|
|
1183
|
+
import { Controller as Controller4, Delete, ForbiddenException as ForbiddenException2, Get as Get4, Inject as Inject6, NotFoundException as NotFoundException2, Optional as Optional4, Param as Param2, Query, Req as Req3 } from "@nestjs/common";
|
|
870
1184
|
function _ts_decorate7(decorators, target, key, desc) {
|
|
871
1185
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
872
1186
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -884,43 +1198,115 @@ function _ts_param6(paramIndex, decorator) {
|
|
|
884
1198
|
};
|
|
885
1199
|
}
|
|
886
1200
|
__name(_ts_param6, "_ts_param");
|
|
887
|
-
var
|
|
1201
|
+
var MemoriesController = class {
|
|
888
1202
|
static {
|
|
889
|
-
__name(this, "
|
|
1203
|
+
__name(this, "MemoriesController");
|
|
890
1204
|
}
|
|
891
|
-
agent;
|
|
892
1205
|
actorResolver;
|
|
893
|
-
|
|
894
|
-
|
|
1206
|
+
memory;
|
|
1207
|
+
constructor(actorResolver, memory) {
|
|
895
1208
|
this.actorResolver = actorResolver;
|
|
1209
|
+
this.memory = memory;
|
|
896
1210
|
}
|
|
897
|
-
|
|
1211
|
+
/**
|
|
1212
|
+
* Every memory this actor can reach, most specific first, each carrying its origin and whatever
|
|
1213
|
+
* wider value it outranks.
|
|
1214
|
+
*
|
|
1215
|
+
* DELIBERATELY IGNORES `maxMemories`. That ceiling is a budget on what one TURN carries; applying
|
|
1216
|
+
* it here would mean a person could not see — and so could not delete — a belief the assistant is
|
|
1217
|
+
* one write away from acting on again. Showing someone more than the model sees is harmless;
|
|
1218
|
+
* showing them less is the failure this endpoint exists to prevent.
|
|
1219
|
+
*/
|
|
1220
|
+
async list(req, threadId) {
|
|
1221
|
+
if (this.memory === void 0) {
|
|
1222
|
+
return [];
|
|
1223
|
+
}
|
|
898
1224
|
const actor = await this.actorResolver.resolve(req);
|
|
899
|
-
return this.
|
|
1225
|
+
return (await this.unbounded(threadId ?? "", actor)).entries;
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Forget one. Authorized against the actor's OWN resolved list, the same way a `skill` load is
|
|
1229
|
+
* authorized against the turn's catalog: an id this actor cannot see is answered as missing rather
|
|
1230
|
+
* than refused, so the endpoint cannot be used to find out which memories exist about other people.
|
|
1231
|
+
*/
|
|
1232
|
+
async forget(req, id) {
|
|
1233
|
+
if (this.memory === void 0) {
|
|
1234
|
+
throw new NotFoundException2("No memory is configured in this deployment.");
|
|
1235
|
+
}
|
|
1236
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1237
|
+
const digest = await this.unbounded("", actor);
|
|
1238
|
+
const entry = digest.entries.find((candidate) => candidate.id === id);
|
|
1239
|
+
if (entry === void 0) {
|
|
1240
|
+
throw new NotFoundException2(`No memory with id "${id}".`);
|
|
1241
|
+
}
|
|
1242
|
+
const verdict = memoryForgetVerdict({
|
|
1243
|
+
record: entry,
|
|
1244
|
+
actor
|
|
1245
|
+
});
|
|
1246
|
+
if (!verdict.allowed) {
|
|
1247
|
+
throw new ForbiddenException2(verdict.reason);
|
|
1248
|
+
}
|
|
1249
|
+
return {
|
|
1250
|
+
forgotten: await this.memory.provider.forget({
|
|
1251
|
+
id: entry.id,
|
|
1252
|
+
ctx: {
|
|
1253
|
+
actor,
|
|
1254
|
+
threadId: ""
|
|
1255
|
+
}
|
|
1256
|
+
})
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
async unbounded(threadId, actor) {
|
|
1260
|
+
const config = this.memory;
|
|
1261
|
+
return await offerMemories({
|
|
1262
|
+
config: {
|
|
1263
|
+
...config,
|
|
1264
|
+
maxMemories: Number.POSITIVE_INFINITY
|
|
1265
|
+
},
|
|
1266
|
+
ctx: {
|
|
1267
|
+
actor,
|
|
1268
|
+
threadId
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
900
1271
|
}
|
|
901
1272
|
};
|
|
902
1273
|
_ts_decorate7([
|
|
903
|
-
|
|
1274
|
+
Get4(),
|
|
1275
|
+
_ts_param6(0, Req3()),
|
|
1276
|
+
_ts_param6(1, Query("threadId")),
|
|
1277
|
+
_ts_metadata7("design:type", Function),
|
|
1278
|
+
_ts_metadata7("design:paramtypes", [
|
|
1279
|
+
typeof Request === "undefined" ? Object : Request,
|
|
1280
|
+
String
|
|
1281
|
+
]),
|
|
1282
|
+
_ts_metadata7("design:returntype", Promise)
|
|
1283
|
+
], MemoriesController.prototype, "list", null);
|
|
1284
|
+
_ts_decorate7([
|
|
1285
|
+
Delete(":id"),
|
|
904
1286
|
_ts_param6(0, Req3()),
|
|
1287
|
+
_ts_param6(1, Param2("id")),
|
|
905
1288
|
_ts_metadata7("design:type", Function),
|
|
906
1289
|
_ts_metadata7("design:paramtypes", [
|
|
907
|
-
typeof Request === "undefined" ? Object : Request
|
|
1290
|
+
typeof Request === "undefined" ? Object : Request,
|
|
1291
|
+
String
|
|
908
1292
|
]),
|
|
909
1293
|
_ts_metadata7("design:returntype", Promise)
|
|
910
|
-
],
|
|
911
|
-
|
|
912
|
-
Controller4("
|
|
913
|
-
_ts_param6(
|
|
1294
|
+
], MemoriesController.prototype, "forget", null);
|
|
1295
|
+
MemoriesController = _ts_decorate7([
|
|
1296
|
+
Controller4("memories"),
|
|
1297
|
+
_ts_param6(0, Inject6(AGENT_ACTOR_RESOLVER3)),
|
|
1298
|
+
_ts_param6(1, Optional4()),
|
|
1299
|
+
_ts_param6(1, Inject6(AGENT_MEMORY2)),
|
|
914
1300
|
_ts_metadata7("design:type", Function),
|
|
915
1301
|
_ts_metadata7("design:paramtypes", [
|
|
916
|
-
typeof
|
|
917
|
-
|
|
1302
|
+
typeof ActorResolver === "undefined" ? Object : ActorResolver,
|
|
1303
|
+
Object
|
|
918
1304
|
])
|
|
919
|
-
],
|
|
1305
|
+
], MemoriesController);
|
|
920
1306
|
|
|
921
|
-
// src/controller/
|
|
1307
|
+
// src/controller/quota.controller.ts
|
|
922
1308
|
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER4 } from "@dudousxd/nestjs-agent-core";
|
|
923
|
-
import {
|
|
1309
|
+
import { Controller as Controller5, Get as Get5, Inject as Inject7, Req as Req4 } from "@nestjs/common";
|
|
924
1310
|
function _ts_decorate8(decorators, target, key, desc) {
|
|
925
1311
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
926
1312
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -938,6 +1324,125 @@ function _ts_param7(paramIndex, decorator) {
|
|
|
938
1324
|
};
|
|
939
1325
|
}
|
|
940
1326
|
__name(_ts_param7, "_ts_param");
|
|
1327
|
+
var QuotaController = class {
|
|
1328
|
+
static {
|
|
1329
|
+
__name(this, "QuotaController");
|
|
1330
|
+
}
|
|
1331
|
+
agent;
|
|
1332
|
+
actorResolver;
|
|
1333
|
+
constructor(agent, actorResolver) {
|
|
1334
|
+
this.agent = agent;
|
|
1335
|
+
this.actorResolver = actorResolver;
|
|
1336
|
+
}
|
|
1337
|
+
async today(req) {
|
|
1338
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1339
|
+
return this.agent.quotaToday(actor.id);
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
_ts_decorate8([
|
|
1343
|
+
Get5("today"),
|
|
1344
|
+
_ts_param7(0, Req4()),
|
|
1345
|
+
_ts_metadata8("design:type", Function),
|
|
1346
|
+
_ts_metadata8("design:paramtypes", [
|
|
1347
|
+
typeof Request === "undefined" ? Object : Request
|
|
1348
|
+
]),
|
|
1349
|
+
_ts_metadata8("design:returntype", Promise)
|
|
1350
|
+
], QuotaController.prototype, "today", null);
|
|
1351
|
+
QuotaController = _ts_decorate8([
|
|
1352
|
+
Controller5("quota"),
|
|
1353
|
+
_ts_param7(1, Inject7(AGENT_ACTOR_RESOLVER4)),
|
|
1354
|
+
_ts_metadata8("design:type", Function),
|
|
1355
|
+
_ts_metadata8("design:paramtypes", [
|
|
1356
|
+
typeof AgentService === "undefined" ? Object : AgentService,
|
|
1357
|
+
typeof ActorResolver === "undefined" ? Object : ActorResolver
|
|
1358
|
+
])
|
|
1359
|
+
], QuotaController);
|
|
1360
|
+
|
|
1361
|
+
// src/controller/skills.controller.ts
|
|
1362
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER5, AGENT_SKILLS as AGENT_SKILLS2, offerSkills } from "@dudousxd/nestjs-agent-core";
|
|
1363
|
+
import { Controller as Controller6, Get as Get6, Inject as Inject8, Optional as Optional5, Query as Query2, Req as Req5 } from "@nestjs/common";
|
|
1364
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
1365
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1366
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1367
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1368
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1369
|
+
}
|
|
1370
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
1371
|
+
function _ts_metadata9(k, v) {
|
|
1372
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1373
|
+
}
|
|
1374
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
1375
|
+
function _ts_param8(paramIndex, decorator) {
|
|
1376
|
+
return function(target, key) {
|
|
1377
|
+
decorator(target, key, paramIndex);
|
|
1378
|
+
};
|
|
1379
|
+
}
|
|
1380
|
+
__name(_ts_param8, "_ts_param");
|
|
1381
|
+
var SkillsController = class {
|
|
1382
|
+
static {
|
|
1383
|
+
__name(this, "SkillsController");
|
|
1384
|
+
}
|
|
1385
|
+
actorResolver;
|
|
1386
|
+
skills;
|
|
1387
|
+
constructor(actorResolver, skills) {
|
|
1388
|
+
this.actorResolver = actorResolver;
|
|
1389
|
+
this.skills = skills;
|
|
1390
|
+
}
|
|
1391
|
+
async list(req, threadId) {
|
|
1392
|
+
if (this.skills === void 0) {
|
|
1393
|
+
return [];
|
|
1394
|
+
}
|
|
1395
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1396
|
+
const offer = await offerSkills(this.skills, {
|
|
1397
|
+
actor,
|
|
1398
|
+
threadId: threadId ?? ""
|
|
1399
|
+
});
|
|
1400
|
+
return offer.entries;
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
_ts_decorate9([
|
|
1404
|
+
Get6(),
|
|
1405
|
+
_ts_param8(0, Req5()),
|
|
1406
|
+
_ts_param8(1, Query2("threadId")),
|
|
1407
|
+
_ts_metadata9("design:type", Function),
|
|
1408
|
+
_ts_metadata9("design:paramtypes", [
|
|
1409
|
+
typeof Request === "undefined" ? Object : Request,
|
|
1410
|
+
String
|
|
1411
|
+
]),
|
|
1412
|
+
_ts_metadata9("design:returntype", Promise)
|
|
1413
|
+
], SkillsController.prototype, "list", null);
|
|
1414
|
+
SkillsController = _ts_decorate9([
|
|
1415
|
+
Controller6("skills"),
|
|
1416
|
+
_ts_param8(0, Inject8(AGENT_ACTOR_RESOLVER5)),
|
|
1417
|
+
_ts_param8(1, Optional5()),
|
|
1418
|
+
_ts_param8(1, Inject8(AGENT_SKILLS2)),
|
|
1419
|
+
_ts_metadata9("design:type", Function),
|
|
1420
|
+
_ts_metadata9("design:paramtypes", [
|
|
1421
|
+
typeof ActorResolver === "undefined" ? Object : ActorResolver,
|
|
1422
|
+
Object
|
|
1423
|
+
])
|
|
1424
|
+
], SkillsController);
|
|
1425
|
+
|
|
1426
|
+
// src/controller/threads.controller.ts
|
|
1427
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER6 } from "@dudousxd/nestjs-agent-core";
|
|
1428
|
+
import { Body as Body2, Controller as Controller7, Delete as Delete2, Get as Get7, Inject as Inject9, Param as Param3, Patch, Post as Post3, Req as Req6 } from "@nestjs/common";
|
|
1429
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
1430
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1431
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1432
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1433
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1434
|
+
}
|
|
1435
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
1436
|
+
function _ts_metadata10(k, v) {
|
|
1437
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1438
|
+
}
|
|
1439
|
+
__name(_ts_metadata10, "_ts_metadata");
|
|
1440
|
+
function _ts_param9(paramIndex, decorator) {
|
|
1441
|
+
return function(target, key) {
|
|
1442
|
+
decorator(target, key, paramIndex);
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
__name(_ts_param9, "_ts_param");
|
|
941
1446
|
var ThreadsController = class {
|
|
942
1447
|
static {
|
|
943
1448
|
__name(this, "ThreadsController");
|
|
@@ -1001,117 +1506,173 @@ var ThreadsController = class {
|
|
|
1001
1506
|
};
|
|
1002
1507
|
}
|
|
1003
1508
|
};
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1509
|
+
_ts_decorate10([
|
|
1510
|
+
Get7(),
|
|
1511
|
+
_ts_param9(0, Req6()),
|
|
1512
|
+
_ts_metadata10("design:type", Function),
|
|
1513
|
+
_ts_metadata10("design:paramtypes", [
|
|
1009
1514
|
typeof Request === "undefined" ? Object : Request
|
|
1010
1515
|
]),
|
|
1011
|
-
|
|
1516
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1012
1517
|
], ThreadsController.prototype, "list", null);
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1518
|
+
_ts_decorate10([
|
|
1519
|
+
Get7(":id"),
|
|
1520
|
+
_ts_param9(0, Req6()),
|
|
1521
|
+
_ts_param9(1, Param3("id")),
|
|
1522
|
+
_ts_metadata10("design:type", Function),
|
|
1523
|
+
_ts_metadata10("design:paramtypes", [
|
|
1019
1524
|
typeof Request === "undefined" ? Object : Request,
|
|
1020
1525
|
String
|
|
1021
1526
|
]),
|
|
1022
|
-
|
|
1527
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1023
1528
|
], ThreadsController.prototype, "detail", null);
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1529
|
+
_ts_decorate10([
|
|
1530
|
+
Delete2(":id"),
|
|
1531
|
+
_ts_param9(0, Req6()),
|
|
1532
|
+
_ts_param9(1, Param3("id")),
|
|
1533
|
+
_ts_metadata10("design:type", Function),
|
|
1534
|
+
_ts_metadata10("design:paramtypes", [
|
|
1030
1535
|
typeof Request === "undefined" ? Object : Request,
|
|
1031
1536
|
String
|
|
1032
1537
|
]),
|
|
1033
|
-
|
|
1538
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1034
1539
|
], ThreadsController.prototype, "remove", null);
|
|
1035
|
-
|
|
1540
|
+
_ts_decorate10([
|
|
1036
1541
|
Post3(":id/fork-from/:messageId"),
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1542
|
+
_ts_param9(0, Req6()),
|
|
1543
|
+
_ts_param9(1, Param3("id")),
|
|
1544
|
+
_ts_param9(2, Param3("messageId")),
|
|
1545
|
+
_ts_metadata10("design:type", Function),
|
|
1546
|
+
_ts_metadata10("design:paramtypes", [
|
|
1042
1547
|
typeof Request === "undefined" ? Object : Request,
|
|
1043
1548
|
String,
|
|
1044
1549
|
String
|
|
1045
1550
|
]),
|
|
1046
|
-
|
|
1551
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1047
1552
|
], ThreadsController.prototype, "fork", null);
|
|
1048
|
-
|
|
1553
|
+
_ts_decorate10([
|
|
1049
1554
|
Patch(":id"),
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1555
|
+
_ts_param9(0, Req6()),
|
|
1556
|
+
_ts_param9(1, Param3("id")),
|
|
1557
|
+
_ts_param9(2, Body2()),
|
|
1558
|
+
_ts_metadata10("design:type", Function),
|
|
1559
|
+
_ts_metadata10("design:paramtypes", [
|
|
1055
1560
|
typeof Request === "undefined" ? Object : Request,
|
|
1056
1561
|
String,
|
|
1057
1562
|
typeof UpdateThreadBody === "undefined" ? Object : UpdateThreadBody
|
|
1058
1563
|
]),
|
|
1059
|
-
|
|
1564
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1060
1565
|
], ThreadsController.prototype, "update", null);
|
|
1061
|
-
|
|
1566
|
+
_ts_decorate10([
|
|
1062
1567
|
Post3(":id/promote"),
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1568
|
+
_ts_param9(0, Req6()),
|
|
1569
|
+
_ts_param9(1, Param3("id")),
|
|
1570
|
+
_ts_metadata10("design:type", Function),
|
|
1571
|
+
_ts_metadata10("design:paramtypes", [
|
|
1067
1572
|
typeof Request === "undefined" ? Object : Request,
|
|
1068
1573
|
String
|
|
1069
1574
|
]),
|
|
1070
|
-
|
|
1575
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1071
1576
|
], ThreadsController.prototype, "promote", null);
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1577
|
+
_ts_decorate10([
|
|
1578
|
+
Delete2(":id/from/:messageId"),
|
|
1579
|
+
_ts_param9(0, Req6()),
|
|
1580
|
+
_ts_param9(1, Param3("id")),
|
|
1581
|
+
_ts_param9(2, Param3("messageId")),
|
|
1582
|
+
_ts_metadata10("design:type", Function),
|
|
1583
|
+
_ts_metadata10("design:paramtypes", [
|
|
1079
1584
|
typeof Request === "undefined" ? Object : Request,
|
|
1080
1585
|
String,
|
|
1081
1586
|
String
|
|
1082
1587
|
]),
|
|
1083
|
-
|
|
1588
|
+
_ts_metadata10("design:returntype", Promise)
|
|
1084
1589
|
], ThreadsController.prototype, "truncateFrom", null);
|
|
1085
|
-
ThreadsController =
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1590
|
+
ThreadsController = _ts_decorate10([
|
|
1591
|
+
Controller7("threads"),
|
|
1592
|
+
_ts_param9(1, Inject9(AGENT_ACTOR_RESOLVER6)),
|
|
1593
|
+
_ts_metadata10("design:type", Function),
|
|
1594
|
+
_ts_metadata10("design:paramtypes", [
|
|
1090
1595
|
typeof AgentService === "undefined" ? Object : AgentService,
|
|
1091
1596
|
typeof ActorResolver === "undefined" ? Object : ActorResolver
|
|
1092
1597
|
])
|
|
1093
1598
|
], ThreadsController);
|
|
1094
1599
|
|
|
1095
1600
|
// src/controller/tool-call.controller.ts
|
|
1096
|
-
import { AGENT_ACTOR_RESOLVER as
|
|
1097
|
-
import { Body as Body3, Controller as
|
|
1098
|
-
function
|
|
1601
|
+
import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER7 } from "@dudousxd/nestjs-agent-core";
|
|
1602
|
+
import { BadRequestException as BadRequestException4, Body as Body3, Controller as Controller8, Inject as Inject10, Post as Post4, Req as Req7 } from "@nestjs/common";
|
|
1603
|
+
function _ts_decorate11(decorators, target, key, desc) {
|
|
1099
1604
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1100
1605
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1101
1606
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1102
1607
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1103
1608
|
}
|
|
1104
|
-
__name(
|
|
1105
|
-
function
|
|
1609
|
+
__name(_ts_decorate11, "_ts_decorate");
|
|
1610
|
+
function _ts_metadata11(k, v) {
|
|
1106
1611
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1107
1612
|
}
|
|
1108
|
-
__name(
|
|
1109
|
-
function
|
|
1613
|
+
__name(_ts_metadata11, "_ts_metadata");
|
|
1614
|
+
function _ts_param10(paramIndex, decorator) {
|
|
1110
1615
|
return function(target, key) {
|
|
1111
1616
|
decorator(target, key, paramIndex);
|
|
1112
1617
|
};
|
|
1113
1618
|
}
|
|
1114
|
-
__name(
|
|
1619
|
+
__name(_ts_param10, "_ts_param");
|
|
1620
|
+
var MAX_ANSWERED_QUESTIONS = 100;
|
|
1621
|
+
var MAX_VALUES_PER_QUESTION = 100;
|
|
1622
|
+
var MAX_ANSWER_VALUE_LENGTH = 4096;
|
|
1623
|
+
var MAX_REJECT_REASON_LENGTH = 4096;
|
|
1624
|
+
function toolCallId(claimed) {
|
|
1625
|
+
if (typeof claimed !== "string" || claimed.length === 0) {
|
|
1626
|
+
throw new BadRequestException4("toolCallId must be a non-empty string");
|
|
1627
|
+
}
|
|
1628
|
+
return claimed;
|
|
1629
|
+
}
|
|
1630
|
+
__name(toolCallId, "toolCallId");
|
|
1631
|
+
function rejectReason(claimed) {
|
|
1632
|
+
if (claimed === void 0) {
|
|
1633
|
+
return void 0;
|
|
1634
|
+
}
|
|
1635
|
+
if (typeof claimed !== "string") {
|
|
1636
|
+
throw new BadRequestException4("reason must be a string");
|
|
1637
|
+
}
|
|
1638
|
+
if (claimed.length > MAX_REJECT_REASON_LENGTH) {
|
|
1639
|
+
throw new BadRequestException4(`reason must be at most ${MAX_REJECT_REASON_LENGTH} characters`);
|
|
1640
|
+
}
|
|
1641
|
+
return claimed;
|
|
1642
|
+
}
|
|
1643
|
+
__name(rejectReason, "rejectReason");
|
|
1644
|
+
function answers(claimed) {
|
|
1645
|
+
if (claimed === void 0) {
|
|
1646
|
+
return void 0;
|
|
1647
|
+
}
|
|
1648
|
+
if (typeof claimed !== "object" || claimed === null || Array.isArray(claimed)) {
|
|
1649
|
+
throw new BadRequestException4("answers must be an object of questionId \u2192 chosen values");
|
|
1650
|
+
}
|
|
1651
|
+
const entries = Object.entries(claimed);
|
|
1652
|
+
if (entries.length > MAX_ANSWERED_QUESTIONS) {
|
|
1653
|
+
throw new BadRequestException4(`answers may cover at most ${MAX_ANSWERED_QUESTIONS} questions`);
|
|
1654
|
+
}
|
|
1655
|
+
const validated = /* @__PURE__ */ Object.create(null);
|
|
1656
|
+
for (const [questionId, values] of entries) {
|
|
1657
|
+
if (!Array.isArray(values)) {
|
|
1658
|
+
throw new BadRequestException4(`answers["${questionId}"] must be an array of chosen values`);
|
|
1659
|
+
}
|
|
1660
|
+
if (values.length > MAX_VALUES_PER_QUESTION) {
|
|
1661
|
+
throw new BadRequestException4(`answers["${questionId}"] may carry at most ${MAX_VALUES_PER_QUESTION} values`);
|
|
1662
|
+
}
|
|
1663
|
+
for (const value of values) {
|
|
1664
|
+
if (typeof value !== "string") {
|
|
1665
|
+
throw new BadRequestException4(`answers["${questionId}"] must contain only strings`);
|
|
1666
|
+
}
|
|
1667
|
+
if (value.length > MAX_ANSWER_VALUE_LENGTH) {
|
|
1668
|
+
throw new BadRequestException4(`answers["${questionId}"] values must be at most ${MAX_ANSWER_VALUE_LENGTH} characters`);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
validated[questionId] = values;
|
|
1672
|
+
}
|
|
1673
|
+
return validated;
|
|
1674
|
+
}
|
|
1675
|
+
__name(answers, "answers");
|
|
1115
1676
|
var ToolCallController = class {
|
|
1116
1677
|
static {
|
|
1117
1678
|
__name(this, "ToolCallController");
|
|
@@ -1124,46 +1685,88 @@ var ToolCallController = class {
|
|
|
1124
1685
|
}
|
|
1125
1686
|
async approve(req, body) {
|
|
1126
1687
|
const actor = await this.actorResolver.resolve(req);
|
|
1127
|
-
await this.agent.approve(actor, body.toolCallId);
|
|
1688
|
+
await this.agent.approve(actor, toolCallId(body.toolCallId));
|
|
1128
1689
|
return {
|
|
1129
1690
|
ok: true
|
|
1130
1691
|
};
|
|
1131
1692
|
}
|
|
1132
1693
|
async reject(req, body) {
|
|
1133
1694
|
const actor = await this.actorResolver.resolve(req);
|
|
1134
|
-
await this.agent.reject(actor, body.toolCallId, body.reason);
|
|
1695
|
+
await this.agent.reject(actor, toolCallId(body.toolCallId), rejectReason(body.reason));
|
|
1696
|
+
return {
|
|
1697
|
+
ok: true
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
* Settle a parked question set. Alongside `approve`/`reject` rather than under a surface of its
|
|
1702
|
+
* own: an elicitation IS a parked tool call, gated by the same ownership check and delivered
|
|
1703
|
+
* through the same signal.
|
|
1704
|
+
*/
|
|
1705
|
+
async answer(req, body) {
|
|
1706
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1707
|
+
await this.agent.answer(actor, toolCallId(body.toolCallId), answers(body.answers));
|
|
1708
|
+
return {
|
|
1709
|
+
ok: true
|
|
1710
|
+
};
|
|
1711
|
+
}
|
|
1712
|
+
/** Decline to answer and let the agent proceed on the answers it pre-picked. */
|
|
1713
|
+
async skip(req, body) {
|
|
1714
|
+
const actor = await this.actorResolver.resolve(req);
|
|
1715
|
+
await this.agent.skip(actor, toolCallId(body.toolCallId));
|
|
1135
1716
|
return {
|
|
1136
1717
|
ok: true
|
|
1137
1718
|
};
|
|
1138
1719
|
}
|
|
1139
1720
|
};
|
|
1140
|
-
|
|
1721
|
+
_ts_decorate11([
|
|
1141
1722
|
Post4("approve"),
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1723
|
+
_ts_param10(0, Req7()),
|
|
1724
|
+
_ts_param10(1, Body3()),
|
|
1725
|
+
_ts_metadata11("design:type", Function),
|
|
1726
|
+
_ts_metadata11("design:paramtypes", [
|
|
1146
1727
|
typeof Request === "undefined" ? Object : Request,
|
|
1147
1728
|
typeof ApproveBody === "undefined" ? Object : ApproveBody
|
|
1148
1729
|
]),
|
|
1149
|
-
|
|
1730
|
+
_ts_metadata11("design:returntype", Promise)
|
|
1150
1731
|
], ToolCallController.prototype, "approve", null);
|
|
1151
|
-
|
|
1732
|
+
_ts_decorate11([
|
|
1152
1733
|
Post4("reject"),
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1734
|
+
_ts_param10(0, Req7()),
|
|
1735
|
+
_ts_param10(1, Body3()),
|
|
1736
|
+
_ts_metadata11("design:type", Function),
|
|
1737
|
+
_ts_metadata11("design:paramtypes", [
|
|
1157
1738
|
typeof Request === "undefined" ? Object : Request,
|
|
1158
1739
|
typeof RejectBody === "undefined" ? Object : RejectBody
|
|
1159
1740
|
]),
|
|
1160
|
-
|
|
1741
|
+
_ts_metadata11("design:returntype", Promise)
|
|
1161
1742
|
], ToolCallController.prototype, "reject", null);
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1743
|
+
_ts_decorate11([
|
|
1744
|
+
Post4("answer"),
|
|
1745
|
+
_ts_param10(0, Req7()),
|
|
1746
|
+
_ts_param10(1, Body3()),
|
|
1747
|
+
_ts_metadata11("design:type", Function),
|
|
1748
|
+
_ts_metadata11("design:paramtypes", [
|
|
1749
|
+
typeof Request === "undefined" ? Object : Request,
|
|
1750
|
+
typeof AnswerBody === "undefined" ? Object : AnswerBody
|
|
1751
|
+
]),
|
|
1752
|
+
_ts_metadata11("design:returntype", Promise)
|
|
1753
|
+
], ToolCallController.prototype, "answer", null);
|
|
1754
|
+
_ts_decorate11([
|
|
1755
|
+
Post4("skip"),
|
|
1756
|
+
_ts_param10(0, Req7()),
|
|
1757
|
+
_ts_param10(1, Body3()),
|
|
1758
|
+
_ts_metadata11("design:type", Function),
|
|
1759
|
+
_ts_metadata11("design:paramtypes", [
|
|
1760
|
+
typeof Request === "undefined" ? Object : Request,
|
|
1761
|
+
typeof ApproveBody === "undefined" ? Object : ApproveBody
|
|
1762
|
+
]),
|
|
1763
|
+
_ts_metadata11("design:returntype", Promise)
|
|
1764
|
+
], ToolCallController.prototype, "skip", null);
|
|
1765
|
+
ToolCallController = _ts_decorate11([
|
|
1766
|
+
Controller8("tool-call"),
|
|
1767
|
+
_ts_param10(1, Inject10(AGENT_ACTOR_RESOLVER7)),
|
|
1768
|
+
_ts_metadata11("design:type", Function),
|
|
1769
|
+
_ts_metadata11("design:paramtypes", [
|
|
1167
1770
|
typeof AgentService === "undefined" ? Object : AgentService,
|
|
1168
1771
|
typeof ActorResolver === "undefined" ? Object : ActorResolver
|
|
1169
1772
|
])
|
|
@@ -1171,7 +1774,7 @@ ToolCallController = _ts_decorate9([
|
|
|
1171
1774
|
|
|
1172
1775
|
// src/discovery/agent-discovery.service.ts
|
|
1173
1776
|
import { AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS2, AGENT_REGISTRY as AGENT_REGISTRY3, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
|
|
1174
|
-
import { Inject as
|
|
1777
|
+
import { Inject as Inject11, Injectable as Injectable4, Logger } from "@nestjs/common";
|
|
1175
1778
|
import { DiscoveryService, MetadataScanner } from "@nestjs/core";
|
|
1176
1779
|
|
|
1177
1780
|
// src/decorator/agent.decorator.ts
|
|
@@ -1206,23 +1809,23 @@ function SystemPromptContributor() {
|
|
|
1206
1809
|
__name(SystemPromptContributor, "SystemPromptContributor");
|
|
1207
1810
|
|
|
1208
1811
|
// src/discovery/agent-discovery.service.ts
|
|
1209
|
-
function
|
|
1812
|
+
function _ts_decorate12(decorators, target, key, desc) {
|
|
1210
1813
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1211
1814
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1212
1815
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1213
1816
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1214
1817
|
}
|
|
1215
|
-
__name(
|
|
1216
|
-
function
|
|
1818
|
+
__name(_ts_decorate12, "_ts_decorate");
|
|
1819
|
+
function _ts_metadata12(k, v) {
|
|
1217
1820
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1218
1821
|
}
|
|
1219
|
-
__name(
|
|
1220
|
-
function
|
|
1822
|
+
__name(_ts_metadata12, "_ts_metadata");
|
|
1823
|
+
function _ts_param11(paramIndex, decorator) {
|
|
1221
1824
|
return function(target, key) {
|
|
1222
1825
|
decorator(target, key, paramIndex);
|
|
1223
1826
|
};
|
|
1224
1827
|
}
|
|
1225
|
-
__name(
|
|
1828
|
+
__name(_ts_param11, "_ts_param");
|
|
1226
1829
|
var AgentDiscoveryService = class _AgentDiscoveryService {
|
|
1227
1830
|
static {
|
|
1228
1831
|
__name(this, "AgentDiscoveryService");
|
|
@@ -1270,23 +1873,53 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
|
|
|
1270
1873
|
...meta.maxSteps !== void 0 ? {
|
|
1271
1874
|
maxSteps: meta.maxSteps
|
|
1272
1875
|
} : {},
|
|
1876
|
+
...meta.maxDelegationDepth !== void 0 ? {
|
|
1877
|
+
maxDelegationDepth: meta.maxDelegationDepth
|
|
1878
|
+
} : {},
|
|
1879
|
+
...meta.maxAgentAppearances !== void 0 ? {
|
|
1880
|
+
maxAgentAppearances: meta.maxAgentAppearances
|
|
1881
|
+
} : {},
|
|
1882
|
+
...meta.history !== void 0 ? {
|
|
1883
|
+
history: meta.history
|
|
1884
|
+
} : {},
|
|
1885
|
+
...meta.outputSchema !== void 0 ? {
|
|
1886
|
+
outputSchema: meta.outputSchema
|
|
1887
|
+
} : {},
|
|
1888
|
+
...meta.intake !== void 0 ? {
|
|
1889
|
+
intake: meta.intake
|
|
1890
|
+
} : {},
|
|
1891
|
+
...meta.ask !== void 0 ? {
|
|
1892
|
+
ask: meta.ask
|
|
1893
|
+
} : {},
|
|
1894
|
+
...meta.outputRepairAttempts !== void 0 ? {
|
|
1895
|
+
outputRepairAttempts: meta.outputRepairAttempts
|
|
1896
|
+
} : {},
|
|
1273
1897
|
...meta.handoff !== void 0 ? {
|
|
1274
|
-
delegatesTo: this.
|
|
1898
|
+
delegatesTo: this.handoffEdges(meta)
|
|
1275
1899
|
} : {}
|
|
1276
1900
|
};
|
|
1277
1901
|
}
|
|
1278
|
-
/**
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1902
|
+
/**
|
|
1903
|
+
* Resolve each handoff entry to an {@link AgentDelegation} — its target's registered name, plus
|
|
1904
|
+
* whether that edge detaches (skipping non-agent classes). A bare name is kept for a plain edge
|
|
1905
|
+
* rather than an always-object form, so a definition an older host built by hand still reads.
|
|
1906
|
+
*/
|
|
1907
|
+
handoffEdges(meta) {
|
|
1908
|
+
const edges = [];
|
|
1909
|
+
for (const entry of meta.handoff ?? []) {
|
|
1910
|
+
const target = typeof entry === "function" ? entry : entry.agent;
|
|
1911
|
+
const detached = typeof entry === "function" ? false : entry.detached === true;
|
|
1282
1912
|
const targetMeta = readAgentMetadata(target);
|
|
1283
1913
|
if (targetMeta === void 0) {
|
|
1284
1914
|
this.logger.warn(`Agent "${meta.name}" hands off to ${target.name}, which is not an @Agent \u2014 skipped.`);
|
|
1285
1915
|
continue;
|
|
1286
1916
|
}
|
|
1287
|
-
|
|
1917
|
+
edges.push(detached ? {
|
|
1918
|
+
agent: targetMeta.name,
|
|
1919
|
+
detached: true
|
|
1920
|
+
} : targetMeta.name);
|
|
1288
1921
|
}
|
|
1289
|
-
return
|
|
1922
|
+
return edges;
|
|
1290
1923
|
}
|
|
1291
1924
|
/** Push every `@SystemPromptContributor()` method on `instance` (bound) into the contributor list. */
|
|
1292
1925
|
collectContributors(instance) {
|
|
@@ -1319,12 +1952,12 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
|
|
|
1319
1952
|
return (ctx) => candidate.call(instance, ctx);
|
|
1320
1953
|
}
|
|
1321
1954
|
};
|
|
1322
|
-
AgentDiscoveryService =
|
|
1955
|
+
AgentDiscoveryService = _ts_decorate12([
|
|
1323
1956
|
Injectable4(),
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1957
|
+
_ts_param11(2, Inject11(AGENT_REGISTRY3)),
|
|
1958
|
+
_ts_param11(3, Inject11(AGENT_PROMPT_CONTRIBUTORS2)),
|
|
1959
|
+
_ts_metadata12("design:type", Function),
|
|
1960
|
+
_ts_metadata12("design:paramtypes", [
|
|
1328
1961
|
typeof DiscoveryService === "undefined" ? Object : DiscoveryService,
|
|
1329
1962
|
typeof MetadataScanner === "undefined" ? Object : MetadataScanner,
|
|
1330
1963
|
typeof AgentRegistry4 === "undefined" ? Object : AgentRegistry4,
|
|
@@ -1333,8 +1966,8 @@ AgentDiscoveryService = _ts_decorate10([
|
|
|
1333
1966
|
], AgentDiscoveryService);
|
|
1334
1967
|
|
|
1335
1968
|
// src/discovery/ai-tool-discovery.service.ts
|
|
1336
|
-
import { AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_REGISTRY as AGENT_REGISTRY4, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY2 } from "@dudousxd/nestjs-agent-core";
|
|
1337
|
-
import { Inject as
|
|
1969
|
+
import { AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_REGISTRY as AGENT_REGISTRY4, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY2, normalizeDelegation as normalizeDelegation2 } from "@dudousxd/nestjs-agent-core";
|
|
1970
|
+
import { Inject as Inject12, Injectable as Injectable5, Logger as Logger2 } from "@nestjs/common";
|
|
1338
1971
|
import { DiscoveryService as DiscoveryService2 } from "@nestjs/core";
|
|
1339
1972
|
import { z } from "zod";
|
|
1340
1973
|
|
|
@@ -1383,23 +2016,23 @@ function provideAgentTool(factoryOrTool, inject) {
|
|
|
1383
2016
|
__name(provideAgentTool, "provideAgentTool");
|
|
1384
2017
|
|
|
1385
2018
|
// src/discovery/ai-tool-discovery.service.ts
|
|
1386
|
-
function
|
|
2019
|
+
function _ts_decorate13(decorators, target, key, desc) {
|
|
1387
2020
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1388
2021
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1389
2022
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1390
2023
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1391
2024
|
}
|
|
1392
|
-
__name(
|
|
1393
|
-
function
|
|
2025
|
+
__name(_ts_decorate13, "_ts_decorate");
|
|
2026
|
+
function _ts_metadata13(k, v) {
|
|
1394
2027
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1395
2028
|
}
|
|
1396
|
-
__name(
|
|
1397
|
-
function
|
|
2029
|
+
__name(_ts_metadata13, "_ts_metadata");
|
|
2030
|
+
function _ts_param12(paramIndex, decorator) {
|
|
1398
2031
|
return function(target, key) {
|
|
1399
2032
|
decorator(target, key, paramIndex);
|
|
1400
2033
|
};
|
|
1401
2034
|
}
|
|
1402
|
-
__name(
|
|
2035
|
+
__name(_ts_param12, "_ts_param");
|
|
1403
2036
|
var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
1404
2037
|
static {
|
|
1405
2038
|
__name(this, "AiToolDiscoveryService");
|
|
@@ -1475,22 +2108,30 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
|
1475
2108
|
}
|
|
1476
2109
|
let delegates = 0;
|
|
1477
2110
|
for (const definition of this.agents.list()) {
|
|
1478
|
-
for (const
|
|
2111
|
+
for (const edge of definition.delegatesTo ?? []) {
|
|
2112
|
+
const { agent: target, detached } = normalizeDelegation2(edge);
|
|
1479
2113
|
const targetDefinition = this.agents.get(target);
|
|
1480
2114
|
if (targetDefinition === void 0) {
|
|
1481
2115
|
throw new Error(`Agent "${definition.name}" hands off to "${target}", which is not a registered @Agent. Declare it as an @Agent provider or fix the reference.`);
|
|
1482
2116
|
}
|
|
1483
|
-
const name = delegateToolName(
|
|
2117
|
+
const name = delegateToolName({
|
|
2118
|
+
target,
|
|
2119
|
+
detached
|
|
2120
|
+
});
|
|
1484
2121
|
if (this.registry.has(name)) {
|
|
1485
2122
|
continue;
|
|
1486
2123
|
}
|
|
1487
2124
|
const targetBlurb = typeof targetDefinition.systemPrompt === "string" ? ` It is: ${targetDefinition.systemPrompt}` : "";
|
|
2125
|
+
const description = detached ? `Start the "${target}" agent working on a task in the BACKGROUND. Returns immediately with a receipt, NOT an answer \u2014 the answer is delivered to this conversation as a separate message later. Use it for work the user does not need to sit and wait for.${targetBlurb}` : `Delegate a task to the "${target}" agent and get its answer.${targetBlurb}`;
|
|
1488
2126
|
this.registry.register(
|
|
1489
2127
|
{
|
|
1490
2128
|
name,
|
|
1491
2129
|
kind: "agent",
|
|
1492
2130
|
targetAgent: target,
|
|
1493
|
-
|
|
2131
|
+
...detached ? {
|
|
2132
|
+
detached: true
|
|
2133
|
+
} : {},
|
|
2134
|
+
description,
|
|
1494
2135
|
inputSchema: z.object({
|
|
1495
2136
|
task: z.string()
|
|
1496
2137
|
})
|
|
@@ -1518,13 +2159,13 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
|
1518
2159
|
return true;
|
|
1519
2160
|
}
|
|
1520
2161
|
};
|
|
1521
|
-
AiToolDiscoveryService =
|
|
2162
|
+
AiToolDiscoveryService = _ts_decorate13([
|
|
1522
2163
|
Injectable5(),
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
2164
|
+
_ts_param12(1, Inject12(AGENT_TOOL_REGISTRY2)),
|
|
2165
|
+
_ts_param12(2, Inject12(AGENT_REGISTRY4)),
|
|
2166
|
+
_ts_param12(3, Inject12(AGENT_OPTIONS3)),
|
|
2167
|
+
_ts_metadata13("design:type", Function),
|
|
2168
|
+
_ts_metadata13("design:paramtypes", [
|
|
1528
2169
|
typeof DiscoveryService2 === "undefined" ? Object : DiscoveryService2,
|
|
1529
2170
|
typeof ToolRegistry === "undefined" ? Object : ToolRegistry,
|
|
1530
2171
|
typeof AgentRegistry === "undefined" ? Object : AgentRegistry,
|
|
@@ -1532,6 +2173,101 @@ AiToolDiscoveryService = _ts_decorate11([
|
|
|
1532
2173
|
])
|
|
1533
2174
|
], AiToolDiscoveryService);
|
|
1534
2175
|
|
|
2176
|
+
// src/discovery/skill-discovery.service.ts
|
|
2177
|
+
import { AGENT_SKILL_SOURCES } from "@dudousxd/nestjs-agent-core";
|
|
2178
|
+
import { Inject as Inject13, Injectable as Injectable6, Logger as Logger3 } from "@nestjs/common";
|
|
2179
|
+
import { DiscoveryService as DiscoveryService3 } from "@nestjs/core";
|
|
2180
|
+
|
|
2181
|
+
// src/decorator/skill.decorator.ts
|
|
2182
|
+
import "reflect-metadata";
|
|
2183
|
+
import { GLOBAL_SCOPE } from "@dudousxd/nestjs-agent-core";
|
|
2184
|
+
var SKILL_METADATA = Symbol.for("@dudousxd/nestjs-agent:skill-metadata");
|
|
2185
|
+
function Skill(options) {
|
|
2186
|
+
return (target) => {
|
|
2187
|
+
Reflect.defineMetadata(SKILL_METADATA, options, target);
|
|
2188
|
+
};
|
|
2189
|
+
}
|
|
2190
|
+
__name(Skill, "Skill");
|
|
2191
|
+
function readSkillMetadata(target) {
|
|
2192
|
+
return Reflect.getMetadata(SKILL_METADATA, target);
|
|
2193
|
+
}
|
|
2194
|
+
__name(readSkillMetadata, "readSkillMetadata");
|
|
2195
|
+
function skillScope(options) {
|
|
2196
|
+
return options.scope ?? GLOBAL_SCOPE;
|
|
2197
|
+
}
|
|
2198
|
+
__name(skillScope, "skillScope");
|
|
2199
|
+
|
|
2200
|
+
// src/discovery/skill-discovery.service.ts
|
|
2201
|
+
function _ts_decorate14(decorators, target, key, desc) {
|
|
2202
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2203
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2204
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2205
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2206
|
+
}
|
|
2207
|
+
__name(_ts_decorate14, "_ts_decorate");
|
|
2208
|
+
function _ts_metadata14(k, v) {
|
|
2209
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2210
|
+
}
|
|
2211
|
+
__name(_ts_metadata14, "_ts_metadata");
|
|
2212
|
+
function _ts_param13(paramIndex, decorator) {
|
|
2213
|
+
return function(target, key) {
|
|
2214
|
+
decorator(target, key, paramIndex);
|
|
2215
|
+
};
|
|
2216
|
+
}
|
|
2217
|
+
__name(_ts_param13, "_ts_param");
|
|
2218
|
+
var SkillDiscoveryService = class _SkillDiscoveryService {
|
|
2219
|
+
static {
|
|
2220
|
+
__name(this, "SkillDiscoveryService");
|
|
2221
|
+
}
|
|
2222
|
+
discovery;
|
|
2223
|
+
declared;
|
|
2224
|
+
logger = new Logger3(_SkillDiscoveryService.name);
|
|
2225
|
+
constructor(discovery, declared) {
|
|
2226
|
+
this.discovery = discovery;
|
|
2227
|
+
this.declared = declared;
|
|
2228
|
+
}
|
|
2229
|
+
onModuleInit() {
|
|
2230
|
+
for (const wrapper of this.discovery.getProviders()) {
|
|
2231
|
+
const instance = wrapper.instance;
|
|
2232
|
+
if (instance === null || typeof instance !== "object") {
|
|
2233
|
+
continue;
|
|
2234
|
+
}
|
|
2235
|
+
const meta = readSkillMetadata(instance.constructor);
|
|
2236
|
+
if (meta === void 0) {
|
|
2237
|
+
continue;
|
|
2238
|
+
}
|
|
2239
|
+
const body = this.bodyOf(instance, meta.body);
|
|
2240
|
+
if (body === void 0) {
|
|
2241
|
+
this.logger.warn(`Skill "${meta.name}" declares no body \u2014 add a \`body()\` method or \`@Skill({ body })\`. Skipped.`);
|
|
2242
|
+
continue;
|
|
2243
|
+
}
|
|
2244
|
+
this.declared.push({
|
|
2245
|
+
name: meta.name,
|
|
2246
|
+
description: meta.description,
|
|
2247
|
+
scope: skillScope(meta),
|
|
2248
|
+
body
|
|
2249
|
+
});
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
/** The instance's `body()` method (bound), else the flat string, else nothing to offer. */
|
|
2253
|
+
bodyOf(instance, flat) {
|
|
2254
|
+
const candidate = instance.body;
|
|
2255
|
+
if (typeof candidate === "function") {
|
|
2256
|
+
return (ctx) => candidate.call(instance, ctx);
|
|
2257
|
+
}
|
|
2258
|
+
return flat === void 0 ? void 0 : () => flat;
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
SkillDiscoveryService = _ts_decorate14([
|
|
2262
|
+
Injectable6(),
|
|
2263
|
+
_ts_param13(1, Inject13(AGENT_SKILL_SOURCES)),
|
|
2264
|
+
_ts_metadata14("design:type", Function),
|
|
2265
|
+
_ts_metadata14("design:paramtypes", [
|
|
2266
|
+
typeof DiscoveryService3 === "undefined" ? Object : DiscoveryService3,
|
|
2267
|
+
Array
|
|
2268
|
+
])
|
|
2269
|
+
], SkillDiscoveryService);
|
|
2270
|
+
|
|
1535
2271
|
// src/in-process-sink.ts
|
|
1536
2272
|
import { AgentStreamError as AgentStreamError2 } from "@dudousxd/nestjs-agent-core";
|
|
1537
2273
|
var InProcessTokenStreamSink = class {
|
|
@@ -1619,38 +2355,44 @@ var LedgerQuotaStore = class {
|
|
|
1619
2355
|
withinLimit: usedTokens < this.limitTokens
|
|
1620
2356
|
};
|
|
1621
2357
|
}
|
|
1622
|
-
async bump() {
|
|
2358
|
+
async bump(_actorRef, _day, _tokens) {
|
|
1623
2359
|
}
|
|
1624
2360
|
};
|
|
1625
2361
|
|
|
1626
2362
|
// src/runner/inline-agent-runner.ts
|
|
1627
|
-
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_STORE as AGENT_STORE3,
|
|
1628
|
-
import { Inject as
|
|
1629
|
-
function
|
|
2363
|
+
import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_STORE as AGENT_STORE3, RunCancelledError, agentFailureCode, encodeStreamEvent, publishAgentRunFailed, runAgentLoop, settleAll, settleUnsettledDelegation } from "@dudousxd/nestjs-agent-core";
|
|
2364
|
+
import { Inject as Inject14, Injectable as Injectable7, Logger as Logger4 } from "@nestjs/common";
|
|
2365
|
+
function _ts_decorate15(decorators, target, key, desc) {
|
|
1630
2366
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1631
2367
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1632
2368
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1633
2369
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1634
2370
|
}
|
|
1635
|
-
__name(
|
|
1636
|
-
function
|
|
2371
|
+
__name(_ts_decorate15, "_ts_decorate");
|
|
2372
|
+
function _ts_metadata15(k, v) {
|
|
1637
2373
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1638
2374
|
}
|
|
1639
|
-
__name(
|
|
1640
|
-
function
|
|
2375
|
+
__name(_ts_metadata15, "_ts_metadata");
|
|
2376
|
+
function _ts_param14(paramIndex, decorator) {
|
|
1641
2377
|
return function(target, key) {
|
|
1642
2378
|
decorator(target, key, paramIndex);
|
|
1643
2379
|
};
|
|
1644
2380
|
}
|
|
1645
|
-
__name(
|
|
2381
|
+
__name(_ts_param14, "_ts_param");
|
|
1646
2382
|
var InlineAgentRunner = class _InlineAgentRunner {
|
|
1647
2383
|
static {
|
|
1648
2384
|
__name(this, "InlineAgentRunner");
|
|
1649
2385
|
}
|
|
1650
2386
|
factory;
|
|
1651
2387
|
store;
|
|
1652
|
-
logger = new
|
|
2388
|
+
logger = new Logger4(_InlineAgentRunner.name);
|
|
1653
2389
|
pending = /* @__PURE__ */ new Map();
|
|
2390
|
+
/**
|
|
2391
|
+
* Runs someone has asked to stop. In-process, like `pending`, and for the same reason: this runner
|
|
2392
|
+
* is single-replica by construction, so the request is readable by the only loop that could be
|
|
2393
|
+
* running it. A cancelled id is dropped once the run settles, so the set tracks live runs only.
|
|
2394
|
+
*/
|
|
2395
|
+
cancelled = /* @__PURE__ */ new Set();
|
|
1654
2396
|
constructor(factory, store) {
|
|
1655
2397
|
this.factory = factory;
|
|
1656
2398
|
this.store = store;
|
|
@@ -1659,13 +2401,29 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1659
2401
|
const runId = crypto.randomUUID();
|
|
1660
2402
|
const day = input.day ?? utcDay();
|
|
1661
2403
|
const deps = this.factory.forAgent(input.agentName);
|
|
1662
|
-
const hooks = this.topLevelHooks(
|
|
2404
|
+
const hooks = this.topLevelHooks({
|
|
2405
|
+
runId,
|
|
2406
|
+
deps,
|
|
2407
|
+
actor: input.actor,
|
|
2408
|
+
day,
|
|
2409
|
+
threadId: input.threadId,
|
|
2410
|
+
chainBelow: [
|
|
2411
|
+
...input.delegationPath ?? [],
|
|
2412
|
+
...input.agentName !== void 0 ? [
|
|
2413
|
+
input.agentName
|
|
2414
|
+
] : []
|
|
2415
|
+
]
|
|
2416
|
+
});
|
|
1663
2417
|
void runAgentLoop({
|
|
1664
2418
|
...deps,
|
|
1665
2419
|
day
|
|
1666
2420
|
}, input, hooks).then(() => this.store.setActiveStream(input.threadId, null)).catch(async (error) => {
|
|
2421
|
+
if (error instanceof RunCancelledError) {
|
|
2422
|
+
await this.settleCancelled(runId, input.threadId, deps);
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
1667
2425
|
const message = error instanceof Error ? error.message : String(error);
|
|
1668
|
-
const code = error
|
|
2426
|
+
const code = agentFailureCode(error);
|
|
1669
2427
|
this.logger.error(`agent run ${runId} failed (${code}): ${message}`);
|
|
1670
2428
|
publishAgentRunFailed({
|
|
1671
2429
|
runId,
|
|
@@ -1684,33 +2442,216 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1684
2442
|
code,
|
|
1685
2443
|
message
|
|
1686
2444
|
});
|
|
1687
|
-
});
|
|
2445
|
+
}).finally(() => this.cancelled.delete(runId));
|
|
1688
2446
|
return {
|
|
1689
2447
|
runId
|
|
1690
2448
|
};
|
|
1691
2449
|
}
|
|
1692
|
-
async signal(runId,
|
|
1693
|
-
const key = `${runId}:${
|
|
1694
|
-
const
|
|
1695
|
-
if (
|
|
2450
|
+
async signal(runId, toolCallId2, reply) {
|
|
2451
|
+
const key = `${runId}:${toolCallId2}`;
|
|
2452
|
+
const waiter = this.pending.get(key);
|
|
2453
|
+
if (waiter !== void 0) {
|
|
1696
2454
|
this.pending.delete(key);
|
|
1697
|
-
resolve(
|
|
2455
|
+
waiter.resolve(reply);
|
|
1698
2456
|
}
|
|
1699
2457
|
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Ask a run to stop, and settle whatever it was parked on.
|
|
2460
|
+
*
|
|
2461
|
+
* The loop observes the request at its next safe point (between steps, before the turn's tools) and
|
|
2462
|
+
* unwinds from there — so a tool already executing is left to finish, and its result is recorded
|
|
2463
|
+
* exactly as it would have been. What this cannot wait for is a turn parked on a human: that wait
|
|
2464
|
+
* is a promise nobody is going to resolve, so it is REJECTED here with the same
|
|
2465
|
+
* {@link RunCancelledError} the loop would have thrown, and the run unwinds through the identical
|
|
2466
|
+
* path.
|
|
2467
|
+
*
|
|
2468
|
+
* Settlement — the run row, the thread's active stream, the stream's terminal — belongs to the
|
|
2469
|
+
* `RunCancelledError` catch in `start`, so a cancel and an ordinary failure settle in one place
|
|
2470
|
+
* each and can never both write.
|
|
2471
|
+
*/
|
|
1700
2472
|
async cancel(runId) {
|
|
1701
|
-
|
|
2473
|
+
this.cancelled.add(runId);
|
|
2474
|
+
for (const [key, waiter] of this.pending) {
|
|
2475
|
+
if (key.startsWith(`${runId}:`)) {
|
|
2476
|
+
this.pending.delete(key);
|
|
2477
|
+
waiter.reject(new RunCancelledError());
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
await Promise.resolve();
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* The single place a cancelled run's state is settled: recorded as its own terminal (never
|
|
2484
|
+
* `failed` — a user pressing Stop must not land in someone's error rate), the thread released, and
|
|
2485
|
+
* the stream ENDED after a `cancelled` frame rather than failed, so a client that retries failed
|
|
2486
|
+
* streams does not retry this one.
|
|
2487
|
+
*/
|
|
2488
|
+
async settleCancelled(runId, threadId, deps) {
|
|
2489
|
+
this.logger.log(`agent run ${runId} cancelled`);
|
|
2490
|
+
await this.store.setActiveStream(threadId, null);
|
|
1702
2491
|
const writer = await deps.sink.open(runId);
|
|
2492
|
+
await writer.write(encodeStreamEvent({
|
|
2493
|
+
kind: "cancelled"
|
|
2494
|
+
}));
|
|
1703
2495
|
await writer.end();
|
|
2496
|
+
await this.store.recordRunEnd?.({
|
|
2497
|
+
runId,
|
|
2498
|
+
status: "cancelled"
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Park a run on a human, keyed by run + tool call. One map for approvals and for question-set
|
|
2503
|
+
* answers alike: both wait on the same key, and `signal` cannot tell (or need to tell) which
|
|
2504
|
+
* shape it is delivering — the loop asked for one and only ever gets what the caller sent. A
|
|
2505
|
+
* cancel settles the wait too, by rejecting it.
|
|
2506
|
+
*/
|
|
2507
|
+
park(runId, toolCallId2) {
|
|
2508
|
+
return new Promise((resolve, reject) => {
|
|
2509
|
+
this.pending.set(`${runId}:${toolCallId2}`, {
|
|
2510
|
+
resolve,
|
|
2511
|
+
reject
|
|
2512
|
+
});
|
|
2513
|
+
});
|
|
1704
2514
|
}
|
|
1705
|
-
topLevelHooks(
|
|
2515
|
+
topLevelHooks(args) {
|
|
2516
|
+
const { runId, deps, actor, day, threadId, chainBelow } = args;
|
|
1706
2517
|
return {
|
|
1707
2518
|
runId,
|
|
1708
2519
|
openSink: /* @__PURE__ */ __name(() => deps.sink.open(runId), "openSink"),
|
|
1709
|
-
awaitApproval: /* @__PURE__ */ __name((call) =>
|
|
1710
|
-
|
|
1711
|
-
}), "awaitApproval"),
|
|
2520
|
+
awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
|
|
2521
|
+
awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
|
|
1712
2522
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
1713
|
-
|
|
2523
|
+
parallel: settleAll,
|
|
2524
|
+
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
2525
|
+
runAgent: /* @__PURE__ */ __name((agentName, task) => this.runNested({
|
|
2526
|
+
agentName,
|
|
2527
|
+
task,
|
|
2528
|
+
actor,
|
|
2529
|
+
day,
|
|
2530
|
+
depth: 1,
|
|
2531
|
+
path: chainBelow,
|
|
2532
|
+
sinkRunId: runId,
|
|
2533
|
+
parentRunId: runId
|
|
2534
|
+
}), "runAgent"),
|
|
2535
|
+
startAgent: /* @__PURE__ */ __name(({ agentName, task, toolCallId: toolCallId2 }) => this.startDetached({
|
|
2536
|
+
agentName,
|
|
2537
|
+
task,
|
|
2538
|
+
actor,
|
|
2539
|
+
day,
|
|
2540
|
+
depth: 1,
|
|
2541
|
+
path: chainBelow,
|
|
2542
|
+
parentRunId: runId,
|
|
2543
|
+
deliverTo: {
|
|
2544
|
+
threadId,
|
|
2545
|
+
toolCallId: toolCallId2
|
|
2546
|
+
}
|
|
2547
|
+
}), "startAgent")
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
/**
|
|
2551
|
+
* Delegate WITHOUT waiting: a nested loop nobody awaits, on its own thread and its own sink, which
|
|
2552
|
+
* posts its answer back into the delegating thread when it lands (`deliverTo`, settled by the
|
|
2553
|
+
* loop). The calling turn gets the run id straight back and finishes.
|
|
2554
|
+
*
|
|
2555
|
+
* No `sinkRunId`, unlike {@link runNested}: forwarding into the stream the human is watching would
|
|
2556
|
+
* write into a turn that has already ended. Its own approvals resolve through the shared pending
|
|
2557
|
+
* map keyed by its own runId — which is what the pending-approvals surface routes to.
|
|
2558
|
+
*/
|
|
2559
|
+
async startDetached(args) {
|
|
2560
|
+
const { agentName, task, actor, day, depth, path, parentRunId, deliverTo } = args;
|
|
2561
|
+
const subThread = await this.store.createThread({
|
|
2562
|
+
actor,
|
|
2563
|
+
transient: true
|
|
2564
|
+
});
|
|
2565
|
+
const runId = crypto.randomUUID();
|
|
2566
|
+
await this.store.setActiveStream(subThread.id, runId);
|
|
2567
|
+
const deps = this.factory.forAgent(agentName);
|
|
2568
|
+
const hooks = {
|
|
2569
|
+
runId,
|
|
2570
|
+
openSink: /* @__PURE__ */ __name(() => deps.sink.open(runId), "openSink"),
|
|
2571
|
+
awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
|
|
2572
|
+
awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
|
|
2573
|
+
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
2574
|
+
parallel: settleAll,
|
|
2575
|
+
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId), "cancelled"),
|
|
2576
|
+
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
2577
|
+
agentName: childName,
|
|
2578
|
+
task: childTask,
|
|
2579
|
+
actor,
|
|
2580
|
+
day,
|
|
2581
|
+
depth: depth + 1,
|
|
2582
|
+
path: [
|
|
2583
|
+
...path,
|
|
2584
|
+
agentName
|
|
2585
|
+
],
|
|
2586
|
+
// A detached run owns a stream of its own, so ITS sub-agents forward into that one.
|
|
2587
|
+
sinkRunId: runId,
|
|
2588
|
+
parentRunId: runId
|
|
2589
|
+
}), "runAgent"),
|
|
2590
|
+
startAgent: /* @__PURE__ */ __name(({ agentName: childName, task: childTask, toolCallId: toolCallId2 }) => this.startDetached({
|
|
2591
|
+
agentName: childName,
|
|
2592
|
+
task: childTask,
|
|
2593
|
+
actor,
|
|
2594
|
+
day,
|
|
2595
|
+
depth: depth + 1,
|
|
2596
|
+
path: [
|
|
2597
|
+
...path,
|
|
2598
|
+
agentName
|
|
2599
|
+
],
|
|
2600
|
+
parentRunId: runId,
|
|
2601
|
+
deliverTo: {
|
|
2602
|
+
threadId: subThread.id,
|
|
2603
|
+
toolCallId: toolCallId2
|
|
2604
|
+
}
|
|
2605
|
+
}), "startAgent")
|
|
2606
|
+
};
|
|
2607
|
+
void runAgentLoop({
|
|
2608
|
+
...deps,
|
|
2609
|
+
day
|
|
2610
|
+
}, {
|
|
2611
|
+
threadId: subThread.id,
|
|
2612
|
+
actor,
|
|
2613
|
+
userText: task,
|
|
2614
|
+
agentName,
|
|
2615
|
+
day,
|
|
2616
|
+
delegationDepth: depth,
|
|
2617
|
+
delegationPath: path,
|
|
2618
|
+
parentRunId,
|
|
2619
|
+
deliverTo
|
|
2620
|
+
}, hooks).catch(async (error) => {
|
|
2621
|
+
const cancelled = error instanceof RunCancelledError;
|
|
2622
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2623
|
+
if (!cancelled) {
|
|
2624
|
+
this.logger.error(`detached agent run ${runId} failed: ${message}`);
|
|
2625
|
+
publishAgentRunFailed({
|
|
2626
|
+
runId,
|
|
2627
|
+
code: agentFailureCode(error),
|
|
2628
|
+
message
|
|
2629
|
+
});
|
|
2630
|
+
}
|
|
2631
|
+
await this.store.recordRunEnd?.({
|
|
2632
|
+
runId,
|
|
2633
|
+
status: cancelled ? "cancelled" : "failed",
|
|
2634
|
+
...cancelled ? {} : {
|
|
2635
|
+
errorCode: agentFailureCode(error),
|
|
2636
|
+
errorMessage: message
|
|
2637
|
+
}
|
|
2638
|
+
});
|
|
2639
|
+
await settleUnsettledDelegation({
|
|
2640
|
+
store: this.store,
|
|
2641
|
+
delivery: deliverTo,
|
|
2642
|
+
agent: agentName,
|
|
2643
|
+
runId,
|
|
2644
|
+
status: cancelled ? "cancelled" : "failed",
|
|
2645
|
+
...cancelled ? {} : {
|
|
2646
|
+
error: message
|
|
2647
|
+
}
|
|
2648
|
+
});
|
|
2649
|
+
}).finally(async () => {
|
|
2650
|
+
this.cancelled.delete(runId);
|
|
2651
|
+
await this.store.setActiveStream(subThread.id, null);
|
|
2652
|
+
});
|
|
2653
|
+
return {
|
|
2654
|
+
runId
|
|
1714
2655
|
};
|
|
1715
2656
|
}
|
|
1716
2657
|
/**
|
|
@@ -1718,7 +2659,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1718
2659
|
* (the top-level run the human is watching) so its output and any pending action tool are visible,
|
|
1719
2660
|
* and its own approvals resolve through the shared pending map keyed by its own runId.
|
|
1720
2661
|
*/
|
|
1721
|
-
async runNested(
|
|
2662
|
+
async runNested(args) {
|
|
2663
|
+
const { agentName, task, actor, day, depth, path, sinkRunId, parentRunId } = args;
|
|
1722
2664
|
const subThread = await this.store.createThread({
|
|
1723
2665
|
actor,
|
|
1724
2666
|
transient: true
|
|
@@ -1730,11 +2672,42 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1730
2672
|
runId,
|
|
1731
2673
|
// Forward into the top-level stream; the top-level run owns end/fail on that shared sink.
|
|
1732
2674
|
openSink: /* @__PURE__ */ __name(async () => childSinkWriter(await deps.sink.open(sinkRunId)), "openSink"),
|
|
1733
|
-
awaitApproval: /* @__PURE__ */ __name((call) =>
|
|
1734
|
-
|
|
1735
|
-
}), "awaitApproval"),
|
|
2675
|
+
awaitApproval: /* @__PURE__ */ __name((call) => this.park(runId, call.id), "awaitApproval"),
|
|
2676
|
+
awaitAnswers: /* @__PURE__ */ __name((request) => this.park(runId, request.id), "awaitAnswers"),
|
|
1736
2677
|
step: /* @__PURE__ */ __name((_name, fn) => fn(), "step"),
|
|
1737
|
-
|
|
2678
|
+
parallel: settleAll,
|
|
2679
|
+
// A child stops when it is cancelled OR when the run a human is actually watching is: the
|
|
2680
|
+
// canceller names the top-level run, which is the only id that ever left the server.
|
|
2681
|
+
cancelled: /* @__PURE__ */ __name(async () => this.cancelled.has(runId) || this.cancelled.has(sinkRunId), "cancelled"),
|
|
2682
|
+
runAgent: /* @__PURE__ */ __name((childName, childTask) => this.runNested({
|
|
2683
|
+
agentName: childName,
|
|
2684
|
+
task: childTask,
|
|
2685
|
+
actor,
|
|
2686
|
+
day,
|
|
2687
|
+
depth: depth + 1,
|
|
2688
|
+
path: [
|
|
2689
|
+
...path,
|
|
2690
|
+
agentName
|
|
2691
|
+
],
|
|
2692
|
+
sinkRunId,
|
|
2693
|
+
parentRunId: runId
|
|
2694
|
+
}), "runAgent"),
|
|
2695
|
+
startAgent: /* @__PURE__ */ __name(({ agentName: childName, task: childTask, toolCallId: toolCallId2 }) => this.startDetached({
|
|
2696
|
+
agentName: childName,
|
|
2697
|
+
task: childTask,
|
|
2698
|
+
actor,
|
|
2699
|
+
day,
|
|
2700
|
+
depth: depth + 1,
|
|
2701
|
+
path: [
|
|
2702
|
+
...path,
|
|
2703
|
+
agentName
|
|
2704
|
+
],
|
|
2705
|
+
parentRunId: runId,
|
|
2706
|
+
deliverTo: {
|
|
2707
|
+
threadId: subThread.id,
|
|
2708
|
+
toolCallId: toolCallId2
|
|
2709
|
+
}
|
|
2710
|
+
}), "startAgent")
|
|
1738
2711
|
};
|
|
1739
2712
|
try {
|
|
1740
2713
|
return await runAgentLoop({
|
|
@@ -1747,6 +2720,8 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1747
2720
|
agentName,
|
|
1748
2721
|
day,
|
|
1749
2722
|
delegationDepth: depth,
|
|
2723
|
+
delegationPath: path,
|
|
2724
|
+
parentRunId,
|
|
1750
2725
|
sinkRunId
|
|
1751
2726
|
}, hooks);
|
|
1752
2727
|
} finally {
|
|
@@ -1754,25 +2729,63 @@ var InlineAgentRunner = class _InlineAgentRunner {
|
|
|
1754
2729
|
}
|
|
1755
2730
|
}
|
|
1756
2731
|
};
|
|
1757
|
-
InlineAgentRunner =
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
2732
|
+
InlineAgentRunner = _ts_decorate15([
|
|
2733
|
+
Injectable7(),
|
|
2734
|
+
_ts_param14(0, Inject14(AGENT_DEPS_FACTORY3)),
|
|
2735
|
+
_ts_param14(1, Inject14(AGENT_STORE3)),
|
|
2736
|
+
_ts_metadata15("design:type", Function),
|
|
2737
|
+
_ts_metadata15("design:paramtypes", [
|
|
1763
2738
|
typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
|
|
1764
2739
|
typeof AgentStore === "undefined" ? Object : AgentStore
|
|
1765
2740
|
])
|
|
1766
2741
|
], InlineAgentRunner);
|
|
1767
2742
|
|
|
2743
|
+
// src/skills-config.ts
|
|
2744
|
+
import { compositeSkillProvider } from "@dudousxd/nestjs-agent-core";
|
|
2745
|
+
function declaredSkillProvider(declared) {
|
|
2746
|
+
return {
|
|
2747
|
+
list: /* @__PURE__ */ __name(({ scopes }) => declared.filter((skill) => scopes.includes(skill.scope)).map(({ name, description, scope }) => ({
|
|
2748
|
+
name,
|
|
2749
|
+
description,
|
|
2750
|
+
scope
|
|
2751
|
+
})), "list"),
|
|
2752
|
+
load: /* @__PURE__ */ __name(async ({ name, scope, ctx }) => {
|
|
2753
|
+
const match = declared.find((skill) => skill.name === name && skill.scope === scope);
|
|
2754
|
+
return match === void 0 ? null : await match.body(ctx);
|
|
2755
|
+
}, "load")
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
__name(declaredSkillProvider, "declaredSkillProvider");
|
|
2759
|
+
function resolveSkillsConfig(options, declared) {
|
|
2760
|
+
if (options === void 0) {
|
|
2761
|
+
return void 0;
|
|
2762
|
+
}
|
|
2763
|
+
const providers = options.provider === void 0 ? [
|
|
2764
|
+
declaredSkillProvider(declared)
|
|
2765
|
+
] : [
|
|
2766
|
+
options.provider,
|
|
2767
|
+
declaredSkillProvider(declared)
|
|
2768
|
+
];
|
|
2769
|
+
return {
|
|
2770
|
+
provider: providers.length === 1 ? providers[0] : compositeSkillProvider(providers),
|
|
2771
|
+
...options.scopes !== void 0 ? {
|
|
2772
|
+
scopes: options.scopes
|
|
2773
|
+
} : {},
|
|
2774
|
+
...options.maxSkills !== void 0 ? {
|
|
2775
|
+
maxSkills: options.maxSkills
|
|
2776
|
+
} : {}
|
|
2777
|
+
};
|
|
2778
|
+
}
|
|
2779
|
+
__name(resolveSkillsConfig, "resolveSkillsConfig");
|
|
2780
|
+
|
|
1768
2781
|
// src/agent.module.ts
|
|
1769
|
-
function
|
|
2782
|
+
function _ts_decorate16(decorators, target, key, desc) {
|
|
1770
2783
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1771
2784
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1772
2785
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1773
2786
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1774
2787
|
}
|
|
1775
|
-
__name(
|
|
2788
|
+
__name(_ts_decorate16, "_ts_decorate");
|
|
1776
2789
|
var DEFAULT_PATH = "agent";
|
|
1777
2790
|
function sharedProviders(durable, includeStore) {
|
|
1778
2791
|
const providers = [
|
|
@@ -1790,6 +2803,32 @@ function sharedProviders(durable, includeStore) {
|
|
|
1790
2803
|
provide: AGENT_PROMPT_CONTRIBUTORS3,
|
|
1791
2804
|
useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
|
|
1792
2805
|
},
|
|
2806
|
+
// Likewise for `@Skill`-decorated providers — filled by SkillDiscoveryService at onModuleInit,
|
|
2807
|
+
// read lazily by the AGENT_SKILLS provider below (which DI builds before discovery has run).
|
|
2808
|
+
{
|
|
2809
|
+
provide: AGENT_SKILL_SOURCES2,
|
|
2810
|
+
useFactory: /* @__PURE__ */ __name(() => [], "useFactory")
|
|
2811
|
+
},
|
|
2812
|
+
{
|
|
2813
|
+
// One resolution, shared by the loop's deps and the listing endpoint: a second one would
|
|
2814
|
+
// drift, and a user would be offered a skill the agent cannot reach. `undefined` when the
|
|
2815
|
+
// host configured none — which is what keeps the turn's checkpoint sequence unchanged.
|
|
2816
|
+
provide: AGENT_SKILLS3,
|
|
2817
|
+
useFactory: /* @__PURE__ */ __name((options, declared) => resolveSkillsConfig(options.skills, declared), "useFactory"),
|
|
2818
|
+
inject: [
|
|
2819
|
+
AGENT_OPTIONS4,
|
|
2820
|
+
AGENT_SKILL_SOURCES2
|
|
2821
|
+
]
|
|
2822
|
+
},
|
|
2823
|
+
{
|
|
2824
|
+
// One resolution, shared by the loop's deps and the read-back endpoint: a person has to be
|
|
2825
|
+
// shown what the model was shown, and two resolutions would eventually disagree about that.
|
|
2826
|
+
provide: AGENT_MEMORY3,
|
|
2827
|
+
useFactory: /* @__PURE__ */ __name((options) => options.memory, "useFactory"),
|
|
2828
|
+
inject: [
|
|
2829
|
+
AGENT_OPTIONS4
|
|
2830
|
+
]
|
|
2831
|
+
},
|
|
1793
2832
|
{
|
|
1794
2833
|
provide: AGENT_SINK2,
|
|
1795
2834
|
useFactory: /* @__PURE__ */ __name((options) => options.sink ?? new InProcessTokenStreamSink(), "useFactory"),
|
|
@@ -1805,7 +2844,7 @@ function sharedProviders(durable, includeStore) {
|
|
|
1805
2844
|
]
|
|
1806
2845
|
},
|
|
1807
2846
|
{
|
|
1808
|
-
provide:
|
|
2847
|
+
provide: AGENT_ACTOR_RESOLVER8,
|
|
1809
2848
|
useFactory: /* @__PURE__ */ __name((options) => options.actorResolver, "useFactory"),
|
|
1810
2849
|
inject: [
|
|
1811
2850
|
AGENT_OPTIONS4
|
|
@@ -1838,6 +2877,7 @@ function sharedProviders(durable, includeStore) {
|
|
|
1838
2877
|
// handoff tools (onApplicationBootstrap) reads the registry.
|
|
1839
2878
|
AgentDiscoveryService,
|
|
1840
2879
|
AiToolDiscoveryService,
|
|
2880
|
+
SkillDiscoveryService,
|
|
1841
2881
|
InlineAgentRunner,
|
|
1842
2882
|
AgentService,
|
|
1843
2883
|
// Bound ALWAYS (durable or inline) — the console's cross-thread approvals inbox routes decisions
|
|
@@ -1889,13 +2929,15 @@ function exportsFor(includeStore) {
|
|
|
1889
2929
|
AGENT_REGISTRY5,
|
|
1890
2930
|
AGENT_SINK2,
|
|
1891
2931
|
AGENT_ROLES_POLICY2,
|
|
1892
|
-
|
|
2932
|
+
AGENT_ACTOR_RESOLVER8,
|
|
1893
2933
|
AGENT_MODEL2,
|
|
1894
2934
|
...includeStore ? [
|
|
1895
2935
|
AGENT_STORE4
|
|
1896
2936
|
] : [],
|
|
1897
2937
|
AGENT_QUOTA_STORE3,
|
|
1898
2938
|
AGENT_PROMPT_CONTRIBUTORS3,
|
|
2939
|
+
AGENT_SKILLS3,
|
|
2940
|
+
AGENT_MEMORY3,
|
|
1899
2941
|
AGENT_DEPS_FACTORY4,
|
|
1900
2942
|
AgentDepsFactory2,
|
|
1901
2943
|
AgentService,
|
|
@@ -1909,7 +2951,9 @@ var BASE_CONTROLLERS = [
|
|
|
1909
2951
|
ThreadsController,
|
|
1910
2952
|
ToolCallController,
|
|
1911
2953
|
QuotaController,
|
|
1912
|
-
AgentsController
|
|
2954
|
+
AgentsController,
|
|
2955
|
+
SkillsController,
|
|
2956
|
+
MemoriesController
|
|
1913
2957
|
];
|
|
1914
2958
|
var GUARDABLE_CONTROLLERS = [
|
|
1915
2959
|
...BASE_CONTROLLERS,
|
|
@@ -2024,12 +3068,13 @@ var AgentModule = class _AgentModule {
|
|
|
2024
3068
|
};
|
|
2025
3069
|
}
|
|
2026
3070
|
};
|
|
2027
|
-
AgentModule =
|
|
3071
|
+
AgentModule = _ts_decorate16([
|
|
2028
3072
|
Global(),
|
|
2029
3073
|
Module({})
|
|
2030
3074
|
], AgentModule);
|
|
2031
3075
|
|
|
2032
3076
|
// src/resolver/header-actor-resolver.ts
|
|
3077
|
+
import { UnauthorizedException } from "@nestjs/common";
|
|
2033
3078
|
function readHeader(req, name) {
|
|
2034
3079
|
if (typeof req !== "object" || req === null || !("headers" in req)) return void 0;
|
|
2035
3080
|
const { headers } = req;
|
|
@@ -2045,7 +3090,7 @@ var HeaderActorResolver = class {
|
|
|
2045
3090
|
resolve(req) {
|
|
2046
3091
|
const id = readHeader(req, "x-actor-id");
|
|
2047
3092
|
if (id === void 0 || id.length === 0) {
|
|
2048
|
-
throw new
|
|
3093
|
+
throw new UnauthorizedException("HeaderActorResolver: missing x-actor-id header. No default actor is fabricated. Send x-actor-id from a trusted gateway, or configure AgentModule.forRoot({ actorResolver }) with a resolver that reads your authenticated principal.");
|
|
2049
3094
|
}
|
|
2050
3095
|
const roles = (readHeader(req, "x-actor-role") ?? "").split(",").map((role) => role.trim()).filter((role) => role.length > 0);
|
|
2051
3096
|
const tenantRef = readHeader(req, "x-tenant-ref");
|
|
@@ -2065,6 +3110,7 @@ export {
|
|
|
2065
3110
|
AGENT_METADATA,
|
|
2066
3111
|
AGENT_TOOL_BRAND,
|
|
2067
3112
|
AI_TOOL_METADATA,
|
|
3113
|
+
ATTACHMENT_PAGE_SIZE,
|
|
2068
3114
|
Agent,
|
|
2069
3115
|
AgentApprovalPortAdapter,
|
|
2070
3116
|
AgentDepsFactory2 as AgentDepsFactory,
|
|
@@ -2080,14 +3126,23 @@ export {
|
|
|
2080
3126
|
InProcessTokenStreamSink,
|
|
2081
3127
|
InlineAgentRunner,
|
|
2082
3128
|
LedgerQuotaStore,
|
|
3129
|
+
MemoriesController,
|
|
3130
|
+
SKILL_METADATA,
|
|
2083
3131
|
SYSTEM_PROMPT_CONTRIBUTOR_METADATA,
|
|
2084
3132
|
SYSTEM_PROMPT_METADATA,
|
|
3133
|
+
Skill,
|
|
3134
|
+
SkillDiscoveryService,
|
|
3135
|
+
SkillsController,
|
|
2085
3136
|
SystemPrompt,
|
|
2086
3137
|
SystemPromptContributor,
|
|
3138
|
+
declaredSkillProvider,
|
|
2087
3139
|
delegateToolName,
|
|
2088
3140
|
provideAgentTool,
|
|
2089
3141
|
readAgentMetadata,
|
|
2090
3142
|
readAiToolMetadata,
|
|
3143
|
+
readSkillMetadata,
|
|
3144
|
+
resolveSkillsConfig,
|
|
3145
|
+
skillScope,
|
|
2091
3146
|
utcDay
|
|
2092
3147
|
};
|
|
2093
3148
|
//# sourceMappingURL=index.js.map
|