@dudousxd/nestjs-agent 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/durable/index.cjs +40 -3
- package/dist/durable/index.cjs.map +1 -1
- package/dist/durable/index.d.cts +7 -0
- package/dist/durable/index.d.ts +7 -0
- package/dist/durable/index.js +46 -9
- package/dist/durable/index.js.map +1 -1
- package/dist/index.cjs +25 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -204,6 +204,15 @@ declare class AgentService {
|
|
|
204
204
|
* adapter can resolve+signal a decision WITHOUT this check — it is authorized upstream instead.
|
|
205
205
|
*/
|
|
206
206
|
private assertOwnsToolCall;
|
|
207
|
+
/**
|
|
208
|
+
* Check a reply against the questions it answers before it is signalled: every submitted value a
|
|
209
|
+
* question's own rules accept (a typed input's type, bounds and pattern; a pick from the offered
|
|
210
|
+
* options), and every `required` question answered — by the reply, or by the defaults an omitted
|
|
211
|
+
* question falls back to. A reply the loop would have to drop parts of is refused here instead, so
|
|
212
|
+
* the person who typed it hears why. Needs the store to hand back the call's recorded questions;
|
|
213
|
+
* without that seam the loop's own filtering is the only check.
|
|
214
|
+
*/
|
|
215
|
+
private assertAnswersFit;
|
|
207
216
|
/**
|
|
208
217
|
* Authorization seam for approve/reject. The call's recorded approver decides who may settle it:
|
|
209
218
|
* the requester (the default, and every call recorded before approvers existed) is the thread's
|
|
@@ -359,6 +368,11 @@ interface AiToolOptions {
|
|
|
359
368
|
* ```
|
|
360
369
|
*/
|
|
361
370
|
presentation?: ToolPresentation;
|
|
371
|
+
/**
|
|
372
|
+
* The turn ends once a call to this tool succeeds — no model call afterwards to narrate what the
|
|
373
|
+
* tool already showed (a composed UI answer, a hand-off). See `ToolSpec.terminal`.
|
|
374
|
+
*/
|
|
375
|
+
terminal?: boolean;
|
|
362
376
|
}
|
|
363
377
|
/**
|
|
364
378
|
* Marks a provider class as an AI tool. The class must implement `execute(input, ctx)`.
|
package/dist/index.d.ts
CHANGED
|
@@ -204,6 +204,15 @@ declare class AgentService {
|
|
|
204
204
|
* adapter can resolve+signal a decision WITHOUT this check — it is authorized upstream instead.
|
|
205
205
|
*/
|
|
206
206
|
private assertOwnsToolCall;
|
|
207
|
+
/**
|
|
208
|
+
* Check a reply against the questions it answers before it is signalled: every submitted value a
|
|
209
|
+
* question's own rules accept (a typed input's type, bounds and pattern; a pick from the offered
|
|
210
|
+
* options), and every `required` question answered — by the reply, or by the defaults an omitted
|
|
211
|
+
* question falls back to. A reply the loop would have to drop parts of is refused here instead, so
|
|
212
|
+
* the person who typed it hears why. Needs the store to hand back the call's recorded questions;
|
|
213
|
+
* without that seam the loop's own filtering is the only check.
|
|
214
|
+
*/
|
|
215
|
+
private assertAnswersFit;
|
|
207
216
|
/**
|
|
208
217
|
* Authorization seam for approve/reject. The call's recorded approver decides who may settle it:
|
|
209
218
|
* the requester (the default, and every call recorded before approvers existed) is the thread's
|
|
@@ -359,6 +368,11 @@ interface AiToolOptions {
|
|
|
359
368
|
* ```
|
|
360
369
|
*/
|
|
361
370
|
presentation?: ToolPresentation;
|
|
371
|
+
/**
|
|
372
|
+
* The turn ends once a call to this tool succeeds — no model call afterwards to narrate what the
|
|
373
|
+
* tool already showed (a composed UI answer, a hand-off). See `ToolSpec.terminal`.
|
|
374
|
+
*/
|
|
375
|
+
terminal?: boolean;
|
|
362
376
|
}
|
|
363
377
|
/**
|
|
364
378
|
* Marks a provider class as an AI tool. The class must implement `execute(input, ctx)`.
|
package/dist/index.js
CHANGED
|
@@ -272,7 +272,7 @@ AgentDepsFactory2 = _ts_decorate([
|
|
|
272
272
|
], AgentDepsFactory2);
|
|
273
273
|
|
|
274
274
|
// src/agent.service.ts
|
|
275
|
-
import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2, REQUESTER_APPROVER, mayDecideApproval } from "@dudousxd/nestjs-agent-core";
|
|
275
|
+
import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY, AGENT_QUOTA_STORE as AGENT_QUOTA_STORE2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE2, REQUESTER_APPROVER, mayDecideApproval, readElicitationQuestions, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
|
|
276
276
|
import { BadRequestException, ForbiddenException, GoneException, Inject as Inject2, Injectable as Injectable2, NotFoundException, NotImplementedException, Optional as Optional2 } from "@nestjs/common";
|
|
277
277
|
|
|
278
278
|
// src/agent-deps.ts
|
|
@@ -466,6 +466,7 @@ var AgentService = class {
|
|
|
466
466
|
*/
|
|
467
467
|
async answer(actor, toolCallId2, answers2 = {}) {
|
|
468
468
|
await this.assertOwnsToolCall(actor, toolCallId2);
|
|
469
|
+
await this.assertAnswersFit(toolCallId2, answers2);
|
|
469
470
|
const reply = {
|
|
470
471
|
answers: answers2,
|
|
471
472
|
answeredByRef: actor.id
|
|
@@ -734,6 +735,27 @@ var AgentService = class {
|
|
|
734
735
|
}
|
|
735
736
|
}
|
|
736
737
|
/**
|
|
738
|
+
* Check a reply against the questions it answers before it is signalled: every submitted value a
|
|
739
|
+
* question's own rules accept (a typed input's type, bounds and pattern; a pick from the offered
|
|
740
|
+
* options), and every `required` question answered — by the reply, or by the defaults an omitted
|
|
741
|
+
* question falls back to. A reply the loop would have to drop parts of is refused here instead, so
|
|
742
|
+
* the person who typed it hears why. Needs the store to hand back the call's recorded questions;
|
|
743
|
+
* without that seam the loop's own filtering is the only check.
|
|
744
|
+
*/
|
|
745
|
+
async assertAnswersFit(toolCallId2, answers2) {
|
|
746
|
+
if (this.store.toolCallInput === void 0) {
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
const questions = readElicitationQuestions(await this.store.toolCallInput(toolCallId2));
|
|
750
|
+
for (const question of questions) {
|
|
751
|
+
const submitted = Object.hasOwn(answers2, question.id) ? answers2[question.id] : void 0;
|
|
752
|
+
const problem = validateElicitationAnswer(question, submitted ?? question.defaults ?? []);
|
|
753
|
+
if (problem !== null) {
|
|
754
|
+
throw new BadRequestException(`answers["${question.id}"] ${problem}`);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
737
759
|
* Authorization seam for approve/reject. The call's recorded approver decides who may settle it:
|
|
738
760
|
* the requester (the default, and every call recorded before approvers existed) is the thread's
|
|
739
761
|
* own actor — the ownership check this always was; any other approver goes through the policy's
|
|
@@ -2385,6 +2407,9 @@ var AiToolDiscoveryService = class _AiToolDiscoveryService {
|
|
|
2385
2407
|
} : {},
|
|
2386
2408
|
...meta.presentation !== void 0 ? {
|
|
2387
2409
|
presentation: meta.presentation
|
|
2410
|
+
} : {},
|
|
2411
|
+
...meta.terminal === true ? {
|
|
2412
|
+
terminal: true
|
|
2388
2413
|
} : {}
|
|
2389
2414
|
}, {
|
|
2390
2415
|
execute: /* @__PURE__ */ __name((input, ctx) => instance.execute(input, ctx), "execute"),
|