@dudousxd/nestjs-agent 1.3.0 → 1.4.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/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
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
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