@dudousxd/nestjs-agent 1.12.1 → 1.14.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
@@ -1,6 +1,6 @@
1
1
  import { DynamicModule, Type, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-pqv_qTmJ.cjs';
3
- export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, k as provideAgentTools, u as utcDay } from './agent-deps.factory-pqv_qTmJ.cjs';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-DkWvoWbD.cjs';
3
+ export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, k as provideAgentTools, u as utcDay } from './agent-deps.factory-DkWvoWbD.cjs';
4
4
  import { AgentRunner, AgentStore, AttachmentStagingStore, ModelCatalog, QuotaProvider, Actor, QuotaReport, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, AgentApprovalPort, ActorResolver, MessageAttachment, AgentAttachmentConfig, AgentClientConfig, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter } from '@dudousxd/nestjs-agent-core';
5
5
  export * from '@dudousxd/nestjs-agent-core';
6
6
  import { Request } from 'express';
@@ -82,7 +82,11 @@ declare class AgentService {
82
82
  * pinned and again at every turn that runs on it (availability can change in between).
83
83
  */
84
84
  private assertModelAllowed;
85
- /** The model a turn runs on: the send's own, else the thread's pinned one, else none. */
85
+ /**
86
+ * The model a turn runs on: the send's own (that turn only — it is never stored on the thread),
87
+ * else the thread's pinned one, else none. An agent the catalog locks to one model runs on it
88
+ * whatever was sent or pinned, and a send naming another model is refused.
89
+ */
86
90
  private resolveModel;
87
91
  private threadModel;
88
92
  chat(params: ChatParams): Promise<{
@@ -134,13 +138,17 @@ declare class AgentService {
134
138
  * "the user picked exactly the defaults" persist as the same answers, and no client has to
135
139
  * re-send what it was shown.
136
140
  */
137
- answer(actor: Actor, toolCallId: string, answers?: Record<string, string[]>): Promise<void>;
141
+ answer(actor: Actor, toolCallId: string, answers?: Record<string, string[]>, opts?: {
142
+ via?: string;
143
+ }): Promise<void>;
138
144
  /**
139
145
  * Decline to answer and let the agent proceed on its own assumptions. NOT the same as confirming
140
146
  * them: the run records this as a rejection, so a reader auditing what the agent was told can
141
147
  * tell a choice the user made from one they refused to make.
142
148
  */
143
- skip(actor: Actor, toolCallId: string): Promise<void>;
149
+ skip(actor: Actor, toolCallId: string, opts?: {
150
+ via?: string;
151
+ }): Promise<void>;
144
152
  /**
145
153
  * The decision core behind approve/reject, WITHOUT an ownership check: resolves the run
146
154
  * currently awaiting `toolCallId` and signals it. `approve`/`reject` above call this after their
@@ -787,7 +795,11 @@ declare class ToolsController {
787
795
  private readonly agents;
788
796
  constructor(actorResolver: ActorResolver, depsFactory: AgentDepsFactory, agents: AgentRegistry);
789
797
  list(req: Request,
790
- /** The agent whose tools to list. Omitted → the default agent, the one a turn naming none uses. */
798
+ /**
799
+ * The agent whose tools to list. Omitted → the default agent, the one a turn naming none uses.
800
+ * `*` → every agent's: the union of what this actor reaches through any of them, each tool once
801
+ * — for a surface that shows several agents' conversations.
802
+ */
791
803
  agent?: string): Promise<ToolCatalogEntry[]>;
792
804
  }
793
805
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { DynamicModule, Type, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-pqv_qTmJ.js';
3
- export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, k as provideAgentTools, u as utcDay } from './agent-deps.factory-pqv_qTmJ.js';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, d as AgentSkillsOptions } from './agent-deps.factory-DkWvoWbD.js';
3
+ export { e as AGENT_TOOL_BRAND, f as AgentAttachmentsOptions, g as AgentDeps, h as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QuotaLimits, i as QuotaWindowLimits, j as delegateToolName, p as provideAgentTool, k as provideAgentTools, u as utcDay } from './agent-deps.factory-DkWvoWbD.js';
4
4
  import { AgentRunner, AgentStore, AttachmentStagingStore, ModelCatalog, QuotaProvider, Actor, QuotaReport, ModelCatalogView, AttachmentRef, PageContext, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, AgentApprovalPort, ActorResolver, MessageAttachment, AgentAttachmentConfig, AgentClientConfig, ToolPresentation, AgentHistoryWindow, AgentIntake, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, TokenStreamSink, SinkWriter } from '@dudousxd/nestjs-agent-core';
5
5
  export * from '@dudousxd/nestjs-agent-core';
6
6
  import { Request } from 'express';
@@ -82,7 +82,11 @@ declare class AgentService {
82
82
  * pinned and again at every turn that runs on it (availability can change in between).
83
83
  */
84
84
  private assertModelAllowed;
85
- /** The model a turn runs on: the send's own, else the thread's pinned one, else none. */
85
+ /**
86
+ * The model a turn runs on: the send's own (that turn only — it is never stored on the thread),
87
+ * else the thread's pinned one, else none. An agent the catalog locks to one model runs on it
88
+ * whatever was sent or pinned, and a send naming another model is refused.
89
+ */
86
90
  private resolveModel;
87
91
  private threadModel;
88
92
  chat(params: ChatParams): Promise<{
@@ -134,13 +138,17 @@ declare class AgentService {
134
138
  * "the user picked exactly the defaults" persist as the same answers, and no client has to
135
139
  * re-send what it was shown.
136
140
  */
137
- answer(actor: Actor, toolCallId: string, answers?: Record<string, string[]>): Promise<void>;
141
+ answer(actor: Actor, toolCallId: string, answers?: Record<string, string[]>, opts?: {
142
+ via?: string;
143
+ }): Promise<void>;
138
144
  /**
139
145
  * Decline to answer and let the agent proceed on its own assumptions. NOT the same as confirming
140
146
  * them: the run records this as a rejection, so a reader auditing what the agent was told can
141
147
  * tell a choice the user made from one they refused to make.
142
148
  */
143
- skip(actor: Actor, toolCallId: string): Promise<void>;
149
+ skip(actor: Actor, toolCallId: string, opts?: {
150
+ via?: string;
151
+ }): Promise<void>;
144
152
  /**
145
153
  * The decision core behind approve/reject, WITHOUT an ownership check: resolves the run
146
154
  * currently awaiting `toolCallId` and signals it. `approve`/`reject` above call this after their
@@ -787,7 +795,11 @@ declare class ToolsController {
787
795
  private readonly agents;
788
796
  constructor(actorResolver: ActorResolver, depsFactory: AgentDepsFactory, agents: AgentRegistry);
789
797
  list(req: Request,
790
- /** The agent whose tools to list. Omitted → the default agent, the one a turn naming none uses. */
798
+ /**
799
+ * The agent whose tools to list. Omitted → the default agent, the one a turn naming none uses.
800
+ * `*` → every agent's: the union of what this actor reaches through any of them, each tool once
801
+ * — for a surface that shows several agents' conversations.
802
+ */
791
803
  agent?: string): Promise<ToolCatalogEntry[]>;
792
804
  }
793
805
 
package/dist/index.js CHANGED
@@ -411,8 +411,22 @@ var AgentService = class {
411
411
  }
412
412
  return entry.id;
413
413
  }
414
- /** The model a turn runs on: the send's own, else the thread's pinned one, else none. */
414
+ /**
415
+ * The model a turn runs on: the send's own (that turn only — it is never stored on the thread),
416
+ * else the thread's pinned one, else none. An agent the catalog locks to one model runs on it
417
+ * whatever was sent or pinned, and a send naming another model is refused.
418
+ */
415
419
  async resolveModel(actor, agent, requested, threadId) {
420
+ const locked = this.models !== void 0 ? (await this.models.list({
421
+ actor,
422
+ agent
423
+ })).locked : void 0;
424
+ if (locked !== void 0) {
425
+ if (requested !== void 0 && requested !== locked.model) {
426
+ throw new BadRequestException(`model "${requested}" cannot be selected: ${locked.reason ?? `this agent always uses "${locked.model}"`}`);
427
+ }
428
+ return locked.model;
429
+ }
416
430
  const model = requested ?? (threadId !== void 0 ? await this.threadModel(threadId) : null);
417
431
  if (model === null || model === void 0) {
418
432
  return void 0;
@@ -561,12 +575,15 @@ var AgentService = class {
561
575
  * "the user picked exactly the defaults" persist as the same answers, and no client has to
562
576
  * re-send what it was shown.
563
577
  */
564
- async answer(actor, toolCallId2, answers2 = {}) {
578
+ async answer(actor, toolCallId2, answers2 = {}, opts = {}) {
565
579
  await this.assertOwnsToolCall(actor, toolCallId2);
566
580
  await this.assertAnswersFit(toolCallId2, answers2);
567
581
  const reply = {
568
582
  answers: answers2,
569
- answeredByRef: actor.id
583
+ answeredByRef: actor.id,
584
+ ...opts.via !== void 0 ? {
585
+ answeredVia: opts.via
586
+ } : {}
570
587
  };
571
588
  return this.signalToolCall(toolCallId2, reply);
572
589
  }
@@ -575,12 +592,15 @@ var AgentService = class {
575
592
  * them: the run records this as a rejection, so a reader auditing what the agent was told can
576
593
  * tell a choice the user made from one they refused to make.
577
594
  */
578
- async skip(actor, toolCallId2) {
595
+ async skip(actor, toolCallId2, opts = {}) {
579
596
  await this.assertOwnsToolCall(actor, toolCallId2);
580
597
  const reply = {
581
598
  answers: {},
582
599
  skipped: true,
583
- answeredByRef: actor.id
600
+ answeredByRef: actor.id,
601
+ ...opts.via !== void 0 ? {
602
+ answeredVia: opts.via
603
+ } : {}
584
604
  };
585
605
  return this.signalToolCall(toolCallId2, reply);
586
606
  }
@@ -2442,7 +2462,9 @@ var ToolCallController = class {
2442
2462
  */
2443
2463
  async answer(req, body) {
2444
2464
  const actor = await this.actorResolver.resolve(req);
2445
- await this.agent.answer(actor, toolCallId(body.toolCallId), answers(body.answers));
2465
+ await this.agent.answer(actor, toolCallId(body.toolCallId), answers(body.answers), {
2466
+ via: via(body.via)
2467
+ });
2446
2468
  return {
2447
2469
  ok: true
2448
2470
  };
@@ -2450,7 +2472,9 @@ var ToolCallController = class {
2450
2472
  /** Decline to answer and let the agent proceed on the answers it pre-picked. */
2451
2473
  async skip(req, body) {
2452
2474
  const actor = await this.actorResolver.resolve(req);
2453
- await this.agent.skip(actor, toolCallId(body.toolCallId));
2475
+ await this.agent.skip(actor, toolCallId(body.toolCallId), {
2476
+ via: via(body.via)
2477
+ });
2454
2478
  return {
2455
2479
  ok: true
2456
2480
  };
@@ -2511,7 +2535,7 @@ ToolCallController = _ts_decorate14([
2511
2535
  ], ToolCallController);
2512
2536
 
2513
2537
  // src/controller/tools.controller.ts
2514
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_REGISTRY as AGENT_REGISTRY3, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
2538
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_REGISTRY as AGENT_REGISTRY3, ALL_AGENTS, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
2515
2539
  import { Controller as Controller12, Get as Get10, Inject as Inject14, NotFoundException as NotFoundException3, Query as Query5, Req as Req11 } from "@nestjs/common";
2516
2540
  function _ts_decorate15(decorators, target, key, desc) {
2517
2541
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2552,19 +2576,34 @@ var ToolsController = class {
2552
2576
  this.agents = agents;
2553
2577
  }
2554
2578
  async list(req, agent) {
2555
- if (agent !== void 0 && this.agents.get(agent) === void 0) {
2579
+ if (agent !== void 0 && agent !== ALL_AGENTS && this.agents.get(agent) === void 0) {
2556
2580
  throw new NotFoundException3(`No agent named "${agent}"`);
2557
2581
  }
2558
2582
  const actor = await this.actorResolver.resolve(req);
2559
- const deps = this.depsFactory.forAgent(agent);
2560
- const specs = await deps.registry.visibleSpecs(actor, deps.rolesPolicy, deps.toolAllowList);
2561
- return specs.map((spec) => ({
2562
- name: spec.name,
2563
- kind: spec.kind,
2564
- ...spec.presentation !== void 0 ? {
2565
- presentation: spec.presentation
2566
- } : {}
2567
- }));
2583
+ const names = agent === ALL_AGENTS ? [
2584
+ void 0,
2585
+ ...this.agents.list().map((definition) => definition.name)
2586
+ ] : [
2587
+ agent
2588
+ ];
2589
+ const entries = /* @__PURE__ */ new Map();
2590
+ for (const name of names) {
2591
+ const deps = this.depsFactory.forAgent(name);
2592
+ const specs = await deps.registry.visibleSpecs(actor, deps.rolesPolicy, deps.toolAllowList);
2593
+ for (const spec of specs) {
2594
+ if (entries.has(spec.name)) continue;
2595
+ entries.set(spec.name, {
2596
+ name: spec.name,
2597
+ kind: spec.kind,
2598
+ ...spec.presentation !== void 0 ? {
2599
+ presentation: spec.presentation
2600
+ } : {}
2601
+ });
2602
+ }
2603
+ }
2604
+ return [
2605
+ ...entries.values()
2606
+ ];
2568
2607
  }
2569
2608
  };
2570
2609
  _ts_decorate15([
@@ -3222,16 +3261,18 @@ var InProcessTokenStreamSink = class {
3222
3261
  };
3223
3262
 
3224
3263
  // src/ledger-quota-provider.ts
3225
- import { exhaustedWindow, quotaPeriodRange } from "@dudousxd/nestjs-agent-core";
3264
+ import { exhaustedWindow, quotaPeriodRange, quotaWarning } from "@dudousxd/nestjs-agent-core";
3226
3265
  var LedgerQuotaProvider = class {
3227
3266
  static {
3228
3267
  __name(this, "LedgerQuotaProvider");
3229
3268
  }
3230
3269
  store;
3231
3270
  limits;
3232
- constructor(store, limits = {}) {
3271
+ options;
3272
+ constructor(store, limits = {}, options = {}) {
3233
3273
  this.store = store;
3234
3274
  this.limits = limits;
3275
+ this.options = options;
3235
3276
  }
3236
3277
  async report(query) {
3237
3278
  const now = query.now ?? /* @__PURE__ */ new Date();
@@ -3245,10 +3286,14 @@ var LedgerQuotaProvider = class {
3245
3286
  windows.push(this.window("month", used.usedTokens, used.costUsd, range.resetsAt));
3246
3287
  }
3247
3288
  const blocked = exhaustedWindow(windows);
3289
+ const warning = quotaWarning(windows);
3248
3290
  return {
3249
3291
  windows,
3250
3292
  ...blocked !== void 0 ? {
3251
3293
  blocked
3294
+ } : {},
3295
+ ...warning !== void 0 ? {
3296
+ warning
3252
3297
  } : {}
3253
3298
  };
3254
3299
  }
@@ -3269,7 +3314,10 @@ var LedgerQuotaProvider = class {
3269
3314
  ...limits.usd !== void 0 ? {
3270
3315
  limitUsd: limits.usd
3271
3316
  } : {},
3272
- resetsAt
3317
+ resetsAt,
3318
+ ...this.options.warnAt !== void 0 && (limits.tokens !== void 0 || limits.usd !== void 0) ? {
3319
+ warnAt: this.options.warnAt
3320
+ } : {}
3273
3321
  };
3274
3322
  }
3275
3323
  };
@@ -3874,7 +3922,9 @@ function sharedProviders(durable) {
3874
3922
  // `quota` is either a provider of the host's own or ceilings for the built-in ledger one;
3875
3923
  // omitted, the ledger provider still reports usage, with no ceiling to block on.
3876
3924
  provide: AGENT_QUOTA_PROVIDER2,
3877
- useFactory: /* @__PURE__ */ __name((o, store) => isQuotaProvider(o.quota) ? o.quota : new LedgerQuotaProvider(store, o.quota?.limits), "useFactory"),
3925
+ useFactory: /* @__PURE__ */ __name((o, store) => isQuotaProvider(o.quota) ? o.quota : new LedgerQuotaProvider(store, o.quota?.limits, o.quota?.warnAt !== void 0 ? {
3926
+ warnAt: o.quota.warnAt
3927
+ } : {}), "useFactory"),
3878
3928
  inject: [
3879
3929
  AGENT_OPTIONS6,
3880
3930
  AGENT_STORE4