@dudousxd/nestjs-agent 2.0.2 → 2.1.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.
@@ -1,7 +1,7 @@
1
1
  import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, ToolStepEnvelope, BufferedModelTurnResult, AgentRunner, TokenStreamSink, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
2
2
  import { WorkflowService } from '@dudousxd/nestjs-durable';
3
3
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
4
- import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-C49HIuEV.cjs';
4
+ import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-OY6mUgB9.cjs';
5
5
  import { DynamicModule } from '@nestjs/common';
6
6
  import '@dudousxd/nestjs-agent-core/genui';
7
7
  import '@standard-schema/spec';
@@ -1,7 +1,7 @@
1
1
  import { AgentStore, AgentRunInput, AgentLoopResult, LlmStepEnvelope, ToolStepEnvelope, BufferedModelTurnResult, AgentRunner, TokenStreamSink, AgentRunStartOptions, HumanReply } from '@dudousxd/nestjs-agent-core';
2
2
  import { WorkflowService } from '@dudousxd/nestjs-durable';
3
3
  import { RunGateway, WorkflowCtx } from '@dudousxd/nestjs-durable-core';
4
- import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-BjPCw4Pf.js';
4
+ import { A as AgentDepsFactory, C as ChatQueueService, a as AgentSurface, b as AgentModuleOptions } from '../chat-queue.service-MYNBAY3P.js';
5
5
  import { DynamicModule } from '@nestjs/common';
6
6
  import '@dudousxd/nestjs-agent-core/genui';
7
7
  import '@standard-schema/spec';
@@ -12493,7 +12493,7 @@ AgentDurableModule = _ts_decorate4([
12493
12493
  ], AgentDurableModule);
12494
12494
 
12495
12495
  // src/agent.module.ts
12496
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER14, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY9, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL3, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS11, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK4, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE9, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AGENT_WORKFLOWS_RUNNER, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3, personalAgentGate, personalAgentScopes, withControllerDecorators } from "@dudousxd/nestjs-agent-core";
12496
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER14, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY9, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL3, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS11, AGENT_PROMPT_CONTRIBUTORS as AGENT_PROMPT_CONTRIBUTORS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER3, AGENT_REGISTRY as AGENT_REGISTRY6, AGENT_ROLES_POLICY as AGENT_ROLES_POLICY2, AGENT_RUNNER as AGENT_RUNNER2, AGENT_SINK as AGENT_SINK4, AGENT_SKILLS as AGENT_SKILLS3, AGENT_SKILL_SOURCES as AGENT_SKILL_SOURCES2, AGENT_STORE as AGENT_STORE9, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AGENT_WORKFLOWS_RUNNER, AgentRegistry as AgentRegistry6, CONTEXT_ACCESSOR as CONTEXT_ACCESSOR3, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3, personalAgentGate, personalAgentScopes, withControllerDecorators } from "@dudousxd/nestjs-agent-core";
12497
12497
  import { Global as Global2, Logger as Logger13, Module as Module3 } from "@nestjs/common";
12498
12498
  import { DiscoveryModule, ModulesContainer, RouterModule } from "@nestjs/core";
12499
12499
 
@@ -13223,8 +13223,8 @@ function durableEngineOf(durable) {
13223
13223
  __name(durableEngineOf, "durableEngineOf");
13224
13224
 
13225
13225
  // src/agent.service.ts
13226
- import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE6, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY as DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY2, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval as mayDecideApproval2, readElicitationQuestions, recordAiUsage, settleDeadRun as settleDeadRun2, textActionProposalReply as textActionProposalReply2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
13227
- import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException as ForbiddenException2, GoneException, HttpException, HttpStatus, Inject as Inject8, Injectable as Injectable7, Logger as Logger4, NotFoundException as NotFoundException2, NotImplementedException as NotImplementedException3, Optional as Optional5, PayloadTooLargeException, UnsupportedMediaTypeException } from "@nestjs/common";
13226
+ import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE6, CONTEXT_ACCESSOR as CONTEXT_ACCESSOR2, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY as DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY2, REQUESTER_APPROVER, contextTenantRef, findCatalogModel, mayDecideApproval as mayDecideApproval2, readElicitationQuestions, readTenancy as readTenancy2, recordAiUsage, settleDeadRun as settleDeadRun2, tenantRowFilter as tenantRowFilter2, tenantRowVisible as tenantRowVisible2, textActionProposalReply as textActionProposalReply2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
13227
+ import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException as ForbiddenException2, GoneException, HttpException, HttpStatus, Inject as Inject8, Injectable as Injectable7, Logger as Logger4, NotFoundException as NotFoundException2, NotImplementedException as NotImplementedException3, Optional as Optional6, PayloadTooLargeException, UnsupportedMediaTypeException } from "@nestjs/common";
13228
13228
 
13229
13229
  // src/attachment-limits.ts
13230
13230
  var DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
@@ -13252,8 +13252,8 @@ function attachmentLimits(options, staging) {
13252
13252
  __name(attachmentLimits, "attachmentLimits");
13253
13253
 
13254
13254
  // src/proposals/action-proposal.service.ts
13255
- import { AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_STORE as AGENT_STORE4, DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY, mayDecideApproval, parseTextActionProposalCommand, resolveTextActionProposalDecision, textActionProposalReply, toActionProposalMutationView, toActionProposalView } from "@dudousxd/nestjs-agent-core";
13256
- import { ForbiddenException, Inject as Inject6, Injectable as Injectable5, NotFoundException, NotImplementedException } from "@nestjs/common";
13255
+ import { AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_STORE as AGENT_STORE4, CONTEXT_ACCESSOR, DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY, mayDecideApproval, parseTextActionProposalCommand, readTenancy, resolveTextActionProposalDecision, tenantRowFilter, tenantRowVisible, textActionProposalReply, toActionProposalMutationView, toActionProposalView } from "@dudousxd/nestjs-agent-core";
13256
+ import { ForbiddenException, Inject as Inject6, Injectable as Injectable5, NotFoundException, NotImplementedException, Optional as Optional4 } from "@nestjs/common";
13257
13257
  function _ts_decorate7(decorators, target, key, desc) {
13258
13258
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
13259
13259
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -13286,9 +13286,11 @@ var ActionProposalService = class {
13286
13286
  }
13287
13287
  store;
13288
13288
  options;
13289
- constructor(store, options) {
13289
+ contextAccessor;
13290
+ constructor(store, options, contextAccessor) {
13290
13291
  this.store = store;
13291
13292
  this.options = options;
13293
+ this.contextAccessor = contextAccessor;
13292
13294
  const text = options.actionProposalText;
13293
13295
  this.vocabulary = {
13294
13296
  ...DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY,
@@ -13314,6 +13316,8 @@ var ActionProposalService = class {
13314
13316
  async scope(threadId, actor) {
13315
13317
  const scope = await this.capability().getThreadActionProposalScope(threadId);
13316
13318
  if (!scope) throw new NotFoundException("Thread not found");
13319
+ const filter = tenantRowFilter(readTenancy(this.options.tenancy ?? "inherit", this.contextAccessor), actor.tenantRef);
13320
+ if (filter !== void 0 && !tenantRowVisible(filter, scope.tenantRef)) throw new NotFoundException("Thread not found");
13317
13321
  if (scope.tenantRef !== (actor.tenantRef ?? null)) throw new ForbiddenException("Wrong proposal tenant");
13318
13322
  return scope;
13319
13323
  }
@@ -13433,16 +13437,19 @@ ActionProposalService = _ts_decorate7([
13433
13437
  Injectable5(),
13434
13438
  _ts_param5(0, Inject6(AGENT_STORE4)),
13435
13439
  _ts_param5(1, Inject6(AGENT_OPTIONS2)),
13440
+ _ts_param5(2, Optional4()),
13441
+ _ts_param5(2, Inject6(CONTEXT_ACCESSOR)),
13436
13442
  _ts_metadata5("design:type", Function),
13437
13443
  _ts_metadata5("design:paramtypes", [
13438
13444
  typeof AgentStore === "undefined" ? Object : AgentStore,
13439
- typeof Pick === "undefined" ? Object : Pick
13445
+ typeof Pick === "undefined" ? Object : Pick,
13446
+ Object
13440
13447
  ])
13441
13448
  ], ActionProposalService);
13442
13449
 
13443
13450
  // src/queue/chat-queue.service.ts
13444
13451
  import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK3, AGENT_STORE as AGENT_STORE5, encodeStreamEvent as encodeStreamEvent4, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
13445
- import { Inject as Inject7, Injectable as Injectable6, Logger as Logger3, NotImplementedException as NotImplementedException2, Optional as Optional4 } from "@nestjs/common";
13452
+ import { Inject as Inject7, Injectable as Injectable6, Logger as Logger3, NotImplementedException as NotImplementedException2, Optional as Optional5 } from "@nestjs/common";
13446
13453
 
13447
13454
  // src/quota-exceeded.ts
13448
13455
  import { publishAgentQuotaExceeded } from "@dudousxd/nestjs-agent-core";
@@ -13918,13 +13925,13 @@ ChatQueueService2 = _ts_decorate8([
13918
13925
  Injectable6(),
13919
13926
  _ts_param6(0, Inject7(AGENT_STORE5)),
13920
13927
  _ts_param6(1, Inject7(AGENT_SINK3)),
13921
- _ts_param6(2, Optional4()),
13928
+ _ts_param6(2, Optional5()),
13922
13929
  _ts_param6(2, Inject7(AGENT_QUOTA_PROVIDER)),
13923
- _ts_param6(3, Optional4()),
13930
+ _ts_param6(3, Optional5()),
13924
13931
  _ts_param6(3, Inject7(AGENT_OPTIONS3)),
13925
- _ts_param6(4, Optional4()),
13932
+ _ts_param6(4, Optional5()),
13926
13933
  _ts_param6(4, Inject7(AGENT_ATTACHMENT_STAGING)),
13927
- _ts_param6(5, Optional4()),
13934
+ _ts_param6(5, Optional5()),
13928
13935
  _ts_param6(5, Inject7(AGENT_DEPS_FACTORY3)),
13929
13936
  _ts_metadata6("design:type", Function),
13930
13937
  _ts_metadata6("design:paramtypes", [
@@ -14071,7 +14078,8 @@ var AgentService = class {
14071
14078
  options;
14072
14079
  queue;
14073
14080
  proposals;
14074
- constructor(runner, store, deps, staging, models, quotaProvider, options, queue, proposals) {
14081
+ contextAccessor;
14082
+ constructor(runner, store, deps, staging, models, quotaProvider, options, queue, proposals, contextAccessor) {
14075
14083
  this.runner = runner;
14076
14084
  this.store = store;
14077
14085
  this.deps = deps;
@@ -14081,6 +14089,58 @@ var AgentService = class {
14081
14089
  this.options = options;
14082
14090
  this.queue = queue;
14083
14091
  this.proposals = proposals;
14092
+ this.contextAccessor = contextAccessor;
14093
+ }
14094
+ /**
14095
+ * With tenancy on, the store must be able to tell a thread's tenant: fail the boot with the fix
14096
+ * rather than answer every thread read `404` at runtime. Tenancy enabled explicitly with no
14097
+ * context accessor to read the tenant from fails the boot too.
14098
+ */
14099
+ onApplicationBootstrap() {
14100
+ if (!this.tenancy().enabled) {
14101
+ const option = this.options?.tenancy;
14102
+ if (typeof option === "object" && option.enabled === true) {
14103
+ throw new Error("AgentModule tenancy is enabled explicitly, but no `@dudousxd/nestjs-context` accessor (1.2.0 or later) is available to read the tenant from, so every read would be unscoped. Import `ContextModule`, or remove `tenancy.enabled: true`.");
14104
+ }
14105
+ return;
14106
+ }
14107
+ const missing = [
14108
+ "tenantOf",
14109
+ "listThreadsForTenant"
14110
+ ].filter((method) => typeof this.store[method] !== "function");
14111
+ if (missing.length > 0) {
14112
+ throw new Error(`AgentModule tenancy is on, and ${this.store.constructor.name} does not implement ${missing.join(" / ")}, so thread reads cannot be scoped by tenant. Use a store that does (in-memory, Drizzle, MikroORM), implement them, or set AgentModule's \`tenancy: false\`.`);
14113
+ }
14114
+ }
14115
+ /**
14116
+ * The matching rule for a decision that comes from outside the thread's own actor (the console's
14117
+ * approvals inbox): with tenancy on, a tool call on a thread the request's context tenant may not
14118
+ * see is not found. A no-op with tenancy off.
14119
+ */
14120
+ async assertToolCallInRequestTenant(toolCallId2) {
14121
+ const filter = tenantRowFilter2(this.tenancy());
14122
+ if (filter === void 0) return;
14123
+ const row = typeof this.store.tenantOf === "function" ? await this.store.tenantOf({
14124
+ toolCallId: toolCallId2
14125
+ }) : null;
14126
+ if (row === null || !tenantRowVisible2(filter, row.tenantRef)) {
14127
+ throw new NotFoundException2(`tool call ${toolCallId2} not found`);
14128
+ }
14129
+ }
14130
+ /** The agent's tenancy, read per call: the context's switch can be flipped at any time. */
14131
+ tenancy() {
14132
+ return readTenancy2(this.options?.tenancy ?? "inherit", this.contextAccessor);
14133
+ }
14134
+ /**
14135
+ * The matching rule for one thread, run or tool call: with tenancy on, a row of another tenant
14136
+ * (or, for a request with a tenant, one with no tenant unless `nullRows: 'shared'`) is not found.
14137
+ * The request's tenant is `actor.tenantRef` (the resolver's, else the context's), else none.
14138
+ */
14139
+ async assertTenantVisible(actor, target, notFound) {
14140
+ const filter = tenantRowFilter2(this.tenancy(), actor.tenantRef);
14141
+ if (filter === void 0) return;
14142
+ const row = typeof this.store.tenantOf === "function" ? await this.store.tenantOf(target) : null;
14143
+ if (row === null || !tenantRowVisible2(filter, row.tenantRef)) throw notFound();
14084
14144
  }
14085
14145
  /**
14086
14146
  * Decide one independent proposal through the scoped proposal service — what the native
@@ -14818,6 +14878,9 @@ var AgentService = class {
14818
14878
  if (owner === null) {
14819
14879
  throw new RunNotActiveException(runId);
14820
14880
  }
14881
+ await this.assertTenantVisible(actor, {
14882
+ runId
14883
+ }, () => new RunNotActiveException(runId));
14821
14884
  if (owner !== actor.id) {
14822
14885
  throw new ForbiddenException2("run belongs to another actor");
14823
14886
  }
@@ -14840,8 +14903,15 @@ var AgentService = class {
14840
14903
  await this.assertOwnsActiveStream(actor, runId);
14841
14904
  return this.runner.cancel(runId);
14842
14905
  }
14843
- async listThreads(actorRef) {
14844
- const threads = await this.store.listThreads(actorRef);
14906
+ /**
14907
+ * The actor's threads. With tenancy on, only those the request's tenant may see: pass the
14908
+ * {@link Actor} so a `tenantRef` its resolver set is the tenant; a bare `actorRef` uses the
14909
+ * context's.
14910
+ */
14911
+ async listThreads(actor) {
14912
+ const actorRef = typeof actor === "string" ? actor : actor.id;
14913
+ const filter = tenantRowFilter2(this.tenancy(), typeof actor === "string" ? void 0 : actor.tenantRef);
14914
+ const threads = filter === void 0 ? await this.store.listThreads(actorRef) : typeof this.store.listThreadsForTenant === "function" ? await this.store.listThreadsForTenant(actorRef, filter) : [];
14845
14915
  return Promise.all(threads.map((thread) => this.toSummaryView(thread)));
14846
14916
  }
14847
14917
  async getThread(actor, threadId) {
@@ -14863,6 +14933,9 @@ var AgentService = class {
14863
14933
  if (await this.store.ownerOfThread(threadId) === null) {
14864
14934
  throw new NotFoundException2(`thread ${threadId} not found`);
14865
14935
  }
14936
+ await this.assertTenantVisible(actor, {
14937
+ threadId
14938
+ }, () => new NotFoundException2(`thread ${threadId} not found`));
14866
14939
  } else {
14867
14940
  await this.assertOwnsThread(actor, threadId);
14868
14941
  }
@@ -15165,6 +15238,9 @@ var AgentService = class {
15165
15238
  if (owner === null) {
15166
15239
  throw new NotFoundException2(`thread ${threadId} not found`);
15167
15240
  }
15241
+ await this.assertTenantVisible(actor, {
15242
+ threadId
15243
+ }, () => new NotFoundException2(`thread ${threadId} not found`));
15168
15244
  if (owner !== actor.id) {
15169
15245
  throw new ForbiddenException2("thread belongs to another actor");
15170
15246
  }
@@ -15179,6 +15255,9 @@ var AgentService = class {
15179
15255
  if (owner === null) {
15180
15256
  throw new NotFoundException2(`tool call ${toolCallId2} not found`);
15181
15257
  }
15258
+ await this.assertTenantVisible(actor, {
15259
+ toolCallId: toolCallId2
15260
+ }, () => new NotFoundException2(`tool call ${toolCallId2} not found`));
15182
15261
  if (owner !== actor.id) {
15183
15262
  throw new ForbiddenException2("tool call belongs to another actor");
15184
15263
  }
@@ -15220,6 +15299,9 @@ var AgentService = class {
15220
15299
  if (requesterRef === null) {
15221
15300
  throw new NotFoundException2(`tool call ${toolCallId2} not found`);
15222
15301
  }
15302
+ await this.assertTenantVisible(actor, {
15303
+ toolCallId: toolCallId2
15304
+ }, () => new NotFoundException2(`tool call ${toolCallId2} not found`));
15223
15305
  const allowed = await mayDecideApproval2(this.deps.forAgent().approvalPolicy, actor, {
15224
15306
  toolCallId: toolCallId2,
15225
15307
  approver,
@@ -15265,6 +15347,9 @@ var AgentService = class {
15265
15347
  if (owner === null) {
15266
15348
  throw new NotFoundException2(`no active run ${runId}`);
15267
15349
  }
15350
+ await this.assertTenantVisible(actor, {
15351
+ runId
15352
+ }, () => new NotFoundException2(`no active run ${runId}`));
15268
15353
  if (owner !== actor.id) {
15269
15354
  throw new ForbiddenException2("run belongs to another actor");
15270
15355
  }
@@ -15285,11 +15370,15 @@ var AgentService = class {
15285
15370
  * against nobody.
15286
15371
  */
15287
15372
  recordUsage(input, options = {}) {
15373
+ const tenantRef = input.tenantRef ?? contextTenantRef(this.tenancy());
15288
15374
  return recordAiUsage({
15289
15375
  store: this.store,
15290
15376
  quota: this.deps.forAgent().quota,
15291
15377
  day: utcDay(),
15292
- input,
15378
+ input: tenantRef !== void 0 && input.tenantRef === void 0 ? {
15379
+ ...input,
15380
+ tenantRef
15381
+ } : input,
15293
15382
  options,
15294
15383
  warn: /* @__PURE__ */ __name((message) => usageLogger.warn(message), "warn")
15295
15384
  });
@@ -15300,16 +15389,18 @@ AgentService = _ts_decorate9([
15300
15389
  _ts_param7(0, Inject8(AGENT_RUNNER)),
15301
15390
  _ts_param7(1, Inject8(AGENT_STORE6)),
15302
15391
  _ts_param7(2, Inject8(AGENT_DEPS_FACTORY4)),
15303
- _ts_param7(3, Optional5()),
15392
+ _ts_param7(3, Optional6()),
15304
15393
  _ts_param7(3, Inject8(AGENT_ATTACHMENT_STAGING2)),
15305
- _ts_param7(4, Optional5()),
15394
+ _ts_param7(4, Optional6()),
15306
15395
  _ts_param7(4, Inject8(AGENT_MODEL_CATALOG)),
15307
- _ts_param7(5, Optional5()),
15396
+ _ts_param7(5, Optional6()),
15308
15397
  _ts_param7(5, Inject8(AGENT_QUOTA_PROVIDER2)),
15309
- _ts_param7(6, Optional5()),
15398
+ _ts_param7(6, Optional6()),
15310
15399
  _ts_param7(6, Inject8(AGENT_OPTIONS4)),
15311
- _ts_param7(7, Optional5()),
15312
- _ts_param7(8, Optional5()),
15400
+ _ts_param7(7, Optional6()),
15401
+ _ts_param7(8, Optional6()),
15402
+ _ts_param7(9, Optional6()),
15403
+ _ts_param7(9, Inject8(CONTEXT_ACCESSOR2)),
15313
15404
  _ts_metadata7("design:type", Function),
15314
15405
  _ts_metadata7("design:paramtypes", [
15315
15406
  typeof AgentRunner === "undefined" ? Object : AgentRunner,
@@ -15320,12 +15411,13 @@ AgentService = _ts_decorate9([
15320
15411
  typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
15321
15412
  typeof Pick === "undefined" ? Object : Pick,
15322
15413
  typeof ChatQueueService2 === "undefined" ? Object : ChatQueueService2,
15323
- typeof ActionProposalService === "undefined" ? Object : ActionProposalService
15414
+ typeof ActionProposalService === "undefined" ? Object : ActionProposalService,
15415
+ Object
15324
15416
  ])
15325
15417
  ], AgentService);
15326
15418
 
15327
15419
  // src/approval-port.adapter.ts
15328
- import { Injectable as Injectable8, NotImplementedException as NotImplementedException4, Optional as Optional6 } from "@nestjs/common";
15420
+ import { Injectable as Injectable8, NotImplementedException as NotImplementedException4, Optional as Optional7 } from "@nestjs/common";
15329
15421
  function _ts_decorate10(decorators, target, key, desc) {
15330
15422
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
15331
15423
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -15383,6 +15475,7 @@ var AgentApprovalPortAdapter = class {
15383
15475
  });
15384
15476
  }
15385
15477
  async approve(toolCallId2, opts) {
15478
+ await this.agent.assertToolCallInRequestTenant(toolCallId2);
15386
15479
  await this.agent.signalToolCall(toolCallId2, {
15387
15480
  approved: true,
15388
15481
  ...opts?.executedByRef !== void 0 ? {
@@ -15397,6 +15490,7 @@ var AgentApprovalPortAdapter = class {
15397
15490
  });
15398
15491
  }
15399
15492
  async reject(toolCallId2, opts) {
15493
+ await this.agent.assertToolCallInRequestTenant(toolCallId2);
15400
15494
  await this.agent.signalToolCall(toolCallId2, {
15401
15495
  approved: false,
15402
15496
  ...opts?.executedByRef !== void 0 ? {
@@ -15413,7 +15507,7 @@ var AgentApprovalPortAdapter = class {
15413
15507
  };
15414
15508
  AgentApprovalPortAdapter = _ts_decorate10([
15415
15509
  Injectable8(),
15416
- _ts_param8(1, Optional6()),
15510
+ _ts_param8(1, Optional7()),
15417
15511
  _ts_metadata8("design:type", Function),
15418
15512
  _ts_metadata8("design:paramtypes", [
15419
15513
  typeof AgentService === "undefined" ? Object : AgentService,
@@ -15500,7 +15594,7 @@ AgentsController = _ts_decorate11([
15500
15594
 
15501
15595
  // src/controller/attachments.controller.ts
15502
15596
  import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING3, AGENT_OPTIONS as AGENT_OPTIONS5, CanAnyone as CanAnyone2 } from "@dudousxd/nestjs-agent-core";
15503
- import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject10, NotImplementedException as NotImplementedException5, Optional as Optional7, PayloadTooLargeException as PayloadTooLargeException2, Post, Req, UnsupportedMediaTypeException as UnsupportedMediaTypeException2, UploadedFile, UseInterceptors } from "@nestjs/common";
15597
+ import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject10, NotImplementedException as NotImplementedException5, Optional as Optional8, PayloadTooLargeException as PayloadTooLargeException2, Post, Req, UnsupportedMediaTypeException as UnsupportedMediaTypeException2, UploadedFile, UseInterceptors } from "@nestjs/common";
15504
15598
  import { FileInterceptor } from "@nestjs/platform-express";
15505
15599
  function _ts_decorate12(decorators, target, key, desc) {
15506
15600
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -15613,7 +15707,7 @@ AttachmentsController = _ts_decorate12([
15613
15707
  Controller2("attachments"),
15614
15708
  _ts_param10(0, Inject10(AGENT_OPTIONS5)),
15615
15709
  _ts_param10(1, Inject10(AGENT_ACTOR_RESOLVER)),
15616
- _ts_param10(3, Optional7()),
15710
+ _ts_param10(3, Optional8()),
15617
15711
  _ts_param10(3, Inject10(AGENT_ATTACHMENT_STAGING3)),
15618
15712
  _ts_metadata10("design:type", Function),
15619
15713
  _ts_metadata10("design:paramtypes", [
@@ -15934,7 +16028,7 @@ __name(parseCursor, "parseCursor");
15934
16028
 
15935
16029
  // src/controller/config.controller.ts
15936
16030
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER3, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING4, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG2, AGENT_OPTIONS as AGENT_OPTIONS6, CanAnyone as CanAnyone4 } from "@dudousxd/nestjs-agent-core";
15937
- import { Controller as Controller4, Get as Get4, Inject as Inject12, Optional as Optional8, Req as Req3 } from "@nestjs/common";
16031
+ import { Controller as Controller4, Get as Get4, Inject as Inject12, Optional as Optional9, Req as Req3 } from "@nestjs/common";
15938
16032
 
15939
16033
  // src/resolver/anonymous-actor-resolver.ts
15940
16034
  import { createHash, randomBytes } from "crypto";
@@ -16101,11 +16195,11 @@ ConfigController = _ts_decorate14([
16101
16195
  Controller4("config"),
16102
16196
  _ts_param12(0, Inject12(AGENT_OPTIONS6)),
16103
16197
  _ts_param12(1, Inject12(AGENT_ACTOR_RESOLVER3)),
16104
- _ts_param12(2, Optional8()),
16198
+ _ts_param12(2, Optional9()),
16105
16199
  _ts_param12(2, Inject12(AGENT_ATTACHMENT_STAGING4)),
16106
- _ts_param12(3, Optional8()),
16200
+ _ts_param12(3, Optional9()),
16107
16201
  _ts_param12(3, Inject12(AGENT_MODEL_CATALOG2)),
16108
- _ts_param12(4, Optional8()),
16202
+ _ts_param12(4, Optional9()),
16109
16203
  _ts_param12(4, Inject12(AGENT_GENUI)),
16110
16204
  _ts_metadata12("design:type", Function),
16111
16205
  _ts_metadata12("design:paramtypes", [
@@ -16119,7 +16213,7 @@ ConfigController = _ts_decorate14([
16119
16213
 
16120
16214
  // src/controller/memories.controller.ts
16121
16215
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER4, AGENT_MEMORY as AGENT_MEMORY2, CanAnyone as CanAnyone5, memoryForgetVerdict, offerMemories } from "@dudousxd/nestjs-agent-core";
16122
- import { Controller as Controller5, Delete, ForbiddenException as ForbiddenException3, Get as Get5, Inject as Inject13, NotFoundException as NotFoundException3, Optional as Optional9, Param as Param2, Query as Query2, Req as Req4 } from "@nestjs/common";
16216
+ import { Controller as Controller5, Delete, ForbiddenException as ForbiddenException3, Get as Get5, Inject as Inject13, NotFoundException as NotFoundException3, Optional as Optional10, Param as Param2, Query as Query2, Req as Req4 } from "@nestjs/common";
16123
16217
  function _ts_decorate15(decorators, target, key, desc) {
16124
16218
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16125
16219
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -16244,7 +16338,7 @@ MemoriesController = _ts_decorate15([
16244
16338
  CanAnyone5(),
16245
16339
  Controller5("memories"),
16246
16340
  _ts_param13(0, Inject13(AGENT_ACTOR_RESOLVER4)),
16247
- _ts_param13(1, Optional9()),
16341
+ _ts_param13(1, Optional10()),
16248
16342
  _ts_param13(1, Inject13(AGENT_MEMORY2)),
16249
16343
  _ts_metadata13("design:type", Function),
16250
16344
  _ts_metadata13("design:paramtypes", [
@@ -16635,7 +16729,7 @@ QuotaController = _ts_decorate19([
16635
16729
 
16636
16730
  // src/controller/skills.controller.ts
16637
16731
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER9, AGENT_SKILLS as AGENT_SKILLS2, CanAnyone as CanAnyone10, offerSkills } from "@dudousxd/nestjs-agent-core";
16638
- import { Controller as Controller10, Get as Get9, Inject as Inject18, Optional as Optional10, Query as Query4, Req as Req9 } from "@nestjs/common";
16732
+ import { Controller as Controller10, Get as Get9, Inject as Inject18, Optional as Optional11, Query as Query4, Req as Req9 } from "@nestjs/common";
16639
16733
  function _ts_decorate20(decorators, target, key, desc) {
16640
16734
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16641
16735
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -16699,7 +16793,7 @@ SkillsController = _ts_decorate20([
16699
16793
  CanAnyone10(),
16700
16794
  Controller10("skills"),
16701
16795
  _ts_param18(0, Inject18(AGENT_ACTOR_RESOLVER9)),
16702
- _ts_param18(1, Optional10()),
16796
+ _ts_param18(1, Optional11()),
16703
16797
  _ts_param18(1, Inject18(AGENT_SKILLS2)),
16704
16798
  _ts_metadata18("design:type", Function),
16705
16799
  _ts_metadata18("design:paramtypes", [
@@ -16749,7 +16843,7 @@ var ThreadsController = class {
16749
16843
  }
16750
16844
  async list(req) {
16751
16845
  const actor = await this.actorResolver.resolve(req);
16752
- return this.agent.listThreads(actor.id);
16846
+ return this.agent.listThreads(actor);
16753
16847
  }
16754
16848
  async detail(req, id) {
16755
16849
  const actor = await this.actorResolver.resolve(req);
@@ -17960,6 +18054,10 @@ var LedgerQuotaProvider = class {
17960
18054
  this.store = store;
17961
18055
  this.limits = limits;
17962
18056
  this.options = options;
18057
+ const per = options.per ?? "actor";
18058
+ if (per !== "actor" && typeof store.usageWindowsForTenant !== "function") {
18059
+ throw new Error(`quota.per: '${per}' sums the usage ledger by tenant, and ${store.constructor.name} does not implement usageWindowsForTenant. Use a store that does (in-memory, Drizzle, MikroORM) or a QuotaProvider of your own.`);
18060
+ }
17963
18061
  }
17964
18062
  async report(query) {
17965
18063
  const now = query.now ?? /* @__PURE__ */ new Date();
@@ -17967,7 +18065,16 @@ var LedgerQuotaProvider = class {
17967
18065
  const day = quotaPeriodRange("day", now);
17968
18066
  const month = quotaPeriodRange("month", now);
17969
18067
  const windows = [];
17970
- if (this.store.usageWindows !== void 0) {
18068
+ const per = this.options.per ?? "actor";
18069
+ const tenantRef = query.actor.tenantRef;
18070
+ if (per !== "actor" && typeof tenantRef === "string" && tenantRef !== "" && this.store.usageWindowsForTenant !== void 0) {
18071
+ const [dayUsed, monthUsed] = await this.store.usageWindowsForTenant(tenantRef, [
18072
+ day,
18073
+ month
18074
+ ], per === "actor-in-tenant" ? actorRef : void 0);
18075
+ windows.push(this.usedWindow("day", dayUsed, day.resetsAt));
18076
+ windows.push(this.usedWindow("month", monthUsed, month.resetsAt));
18077
+ } else if (this.store.usageWindows !== void 0) {
17971
18078
  const [dayUsed, monthUsed] = await this.store.usageWindows(actorRef, [
17972
18079
  day,
17973
18080
  month
@@ -18612,7 +18719,7 @@ NestAiModelsBinding = _ts_decorate28([
18612
18719
 
18613
18720
  // src/pricing-boot.service.ts
18614
18721
  import { AGENT_MODEL as AGENT_MODEL2, AGENT_OPTIONS as AGENT_OPTIONS9, AGENT_PRICING_STORE as AGENT_PRICING_STORE2, ensureModelPricing } from "@dudousxd/nestjs-agent-core";
18615
- import { Inject as Inject26, Injectable as Injectable14, Logger as Logger10, Optional as Optional11 } from "@nestjs/common";
18722
+ import { Inject as Inject26, Injectable as Injectable14, Logger as Logger10, Optional as Optional12 } from "@nestjs/common";
18616
18723
  function _ts_decorate29(decorators, target, key, desc) {
18617
18724
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
18618
18725
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -18697,9 +18804,9 @@ var PricingBootService = class {
18697
18804
  PricingBootService = _ts_decorate29([
18698
18805
  Injectable14(),
18699
18806
  _ts_param26(0, Inject26(AGENT_OPTIONS9)),
18700
- _ts_param26(1, Optional11()),
18807
+ _ts_param26(1, Optional12()),
18701
18808
  _ts_param26(1, Inject26(AGENT_MODEL2)),
18702
- _ts_param26(2, Optional11()),
18809
+ _ts_param26(2, Optional12()),
18703
18810
  _ts_param26(2, Inject26(AGENT_PRICING_STORE2)),
18704
18811
  _ts_metadata27("design:type", Function),
18705
18812
  _ts_metadata27("design:paramtypes", [
@@ -19004,9 +19111,22 @@ ActionProposalController = _ts_decorate31([
19004
19111
  ])
19005
19112
  ], ActionProposalController);
19006
19113
 
19114
+ // src/resolver/tenant-filling-resolver.ts
19115
+ import { readTenancy as readTenancy3, withContextTenant } from "@dudousxd/nestjs-agent-core";
19116
+ function tenantFillingResolver(resolver, tenancy, contextAccessor) {
19117
+ if (tenancy === false) return resolver;
19118
+ const wrapper = Object.create(resolver);
19119
+ Object.defineProperty(wrapper, "resolve", {
19120
+ value: /* @__PURE__ */ __name(async (req) => withContextTenant(await resolver.resolve(req), readTenancy3(tenancy ?? "inherit", contextAccessor ?? void 0)), "value"),
19121
+ enumerable: false
19122
+ });
19123
+ return wrapper;
19124
+ }
19125
+ __name(tenantFillingResolver, "tenantFillingResolver");
19126
+
19007
19127
  // src/runner/inline-agent-runner.ts
19008
19128
  import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY8, AGENT_STORE as AGENT_STORE8, RUN_ENDED_BEFORE_TOOL_CALL as RUN_ENDED_BEFORE_TOOL_CALL2, RunCancelledError as RunCancelledError2, agentFailureCode as agentFailureCode2, agentRunContext as agentRunContext2, encodeStreamEvent as encodeStreamEvent5, publishAgentRunCancelled as publishAgentRunCancelled2, publishAgentRunFailed as publishAgentRunFailed2, releaseThreadRun as releaseThreadRun3, runAgentLoop as runAgentLoop2, runDurationMs as runDurationMs2, runEndTimings as runEndTimings2, settleAll as settleAll2, settleUnsettledDelegation as settleUnsettledDelegation3, streamFailure as streamFailure3 } from "@dudousxd/nestjs-agent-core";
19009
- import { Inject as Inject29, Injectable as Injectable16, Logger as Logger12, Optional as Optional12 } from "@nestjs/common";
19129
+ import { Inject as Inject29, Injectable as Injectable16, Logger as Logger12, Optional as Optional13 } from "@nestjs/common";
19010
19130
  function _ts_decorate32(decorators, target, key, desc) {
19011
19131
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19012
19132
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -19553,7 +19673,7 @@ InlineAgentRunner = _ts_decorate32([
19553
19673
  Injectable16(),
19554
19674
  _ts_param29(0, Inject29(AGENT_DEPS_FACTORY8)),
19555
19675
  _ts_param29(1, Inject29(AGENT_STORE8)),
19556
- _ts_param29(2, Optional12()),
19676
+ _ts_param29(2, Optional13()),
19557
19677
  _ts_metadata30("design:type", Function),
19558
19678
  _ts_metadata30("design:paramtypes", [
19559
19679
  typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory,
@@ -19778,13 +19898,20 @@ function sharedProviders(durable, engine) {
19778
19898
  },
19779
19899
  {
19780
19900
  provide: AGENT_ACTOR_RESOLVER14,
19781
- useFactory: /* @__PURE__ */ __name((options) => {
19782
- if (options.actorResolver !== void 0) return options.actorResolver;
19901
+ // With tenancy on, an actor the resolver left without a `tenantRef` gets the context tenant's.
19902
+ useFactory: /* @__PURE__ */ __name((options, contextAccessor) => {
19903
+ if (options.actorResolver !== void 0) {
19904
+ return tenantFillingResolver(options.actorResolver, options.tenancy, contextAccessor);
19905
+ }
19783
19906
  logger4.warn("No `actorResolver` configured \u2014 the agent endpoints are PUBLIC: every browser gets its own anonymous identity (an HttpOnly cookie). Set `actorResolver: requestUserActorResolver()` (or your own) to require login.");
19784
- return new AnonymousActorResolver();
19907
+ return tenantFillingResolver(new AnonymousActorResolver(), options.tenancy, contextAccessor);
19785
19908
  }, "useFactory"),
19786
19909
  inject: [
19787
- AGENT_OPTIONS11
19910
+ AGENT_OPTIONS11,
19911
+ {
19912
+ token: CONTEXT_ACCESSOR3,
19913
+ optional: true
19914
+ }
19788
19915
  ]
19789
19916
  },
19790
19917
  // No `model` (and no `engine`): the turns run on `@nestjs/ai`'s `AiModule` models.
@@ -19807,6 +19934,9 @@ function sharedProviders(durable, engine) {
19807
19934
  } : {},
19808
19935
  ...o.quota?.countEstimatedCost !== void 0 ? {
19809
19936
  countEstimatedCost: o.quota.countEstimatedCost
19937
+ } : {},
19938
+ ...o.quota?.per !== void 0 ? {
19939
+ per: o.quota.per
19810
19940
  } : {}
19811
19941
  }), "useFactory"),
19812
19942
  inject: [