@dudousxd/nestjs-agent 1.23.1 → 1.24.1

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,8 +1,8 @@
1
1
  import { DynamicModule, Type, OnApplicationBootstrap, OnModuleInit, ConflictException, OnModuleDestroy } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter, e as AgentSkillsOptions } from './chat-queue.service-D1z3WjFI.cjs';
3
- export { f as AGENT_TOOL_BRAND, g as AgentAttachmentsOptions, h as AgentDeps, i as AgentEngine, j as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QueuePlan, k as QueueSettleOutcome, l as QueuedTurn, m as QueuedTurnStarter, n as QuotaLimits, o as QuotaWindowLimits, p as defineTool, q as delegateToolName, r as provideAgentTool, s as provideAgentTools, u as utcDay } from './chat-queue.service-D1z3WjFI.cjs';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter, e as AgentSkillsOptions } from './chat-queue.service-Crf9uwum.cjs';
3
+ export { f as AGENT_TOOL_BRAND, g as AgentAttachmentsOptions, h as AgentDeps, i as AgentEngine, j as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QueuePlan, k as QueueSettleOutcome, l as QueuedTurn, m as QueuedTurnStarter, n as QuotaLimits, o as QuotaWindowLimits, p as defineTool, q as delegateToolName, r as provideAgentTool, s as provideAgentTools, u as utcDay } from './chat-queue.service-Crf9uwum.cjs';
4
4
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
5
- import { AgentStore, Actor, ListActionProposals, ActionProposalMutationView, AgentRunner, AttachmentStagingStore, ModelCatalog, QuotaProvider, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver, AgentApprovalPort, MessageAttachment, AgentAttachmentConfig, AgentClientConfig, ToolSpec, ToolPresentation, AgentHistoryWindow, AgentIntake, Persona, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, AgentRunStartOptions, TokenStreamSink, SinkWriter } from '@dudousxd/nestjs-agent-core';
5
+ import { AgentAttachmentConfig, AttachmentStagingStore, AgentStore, Actor, ListActionProposals, ActionProposalMutationView, TextActionProposalVocabulary, AgentRunner, ModelCatalog, QuotaProvider, ActionApprovalMode, ActionProposalView, MessageAttachment, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver, AgentApprovalPort, AgentClientConfig, ToolSpec, ToolPresentation, AgentHistoryWindow, AgentIntake, Persona, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, AgentRunStartOptions, TokenStreamSink, SinkWriter, ActionProposal } from '@dudousxd/nestjs-agent-core';
6
6
  export * from '@dudousxd/nestjs-agent-core';
7
7
  export { FunctionalToolDefinition } from '@dudousxd/nestjs-agent-core';
8
8
  import { Request, Response } from 'express';
@@ -16,6 +16,20 @@ declare class AgentModule {
16
16
  static forRootAsync(options: AgentModuleAsyncOptions): DynamicModule;
17
17
  }
18
18
 
19
+ /** Default per-file size cap (20 MiB). */
20
+ declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
21
+ /** Default allowlist: what multimodal model providers commonly accept as native image/file parts. */
22
+ declare const DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES: readonly string[];
23
+ /** How many attachments one message may name. */
24
+ declare const MAX_ATTACHMENTS_PER_MESSAGE = 10;
25
+ /** The attachment rules in force — `AgentAttachmentConfig`, as `GET <base>/config` serves it. */
26
+ type AttachmentLimits = AgentAttachmentConfig;
27
+ /**
28
+ * One source for attachment limits: the staging store's own `describe()` when it declares them
29
+ * (`AgentMediaAttachmentsModule` does), else `AgentModule`'s `attachments` option, else the defaults.
30
+ */
31
+ declare function attachmentLimits(options: Pick<AgentModuleOptions, 'attachments'> | undefined, staging: AttachmentStagingStore | undefined): AttachmentLimits;
32
+
19
33
  declare class ActionProposalService {
20
34
  private readonly store;
21
35
  private readonly options;
@@ -55,8 +69,10 @@ declare class ActionProposalService {
55
69
  text: string;
56
70
  }>;
57
71
  private textReceipt;
72
+ /** The configured words a text decision is made of (`actionProposalText.vocabulary`). */
73
+ textVocabulary(): TextActionProposalVocabulary;
58
74
  /** The configured reply to a decision the store answered with `result`. */
59
- reply(result: ActionProposalMutationView, decision: 'approved' | 'rejected'): string;
75
+ reply(result: Pick<ActionProposalMutationView, 'status' | 'proposal'>, decision: 'approved' | 'rejected'): string;
60
76
  }
61
77
 
62
78
  /**
@@ -165,7 +181,7 @@ declare class AgentService {
165
181
  private readonly options?;
166
182
  private readonly queue?;
167
183
  private readonly proposals?;
168
- constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quota" | "actionApprovalMode"> | undefined, queue?: ChatQueueService | undefined, proposals?: ActionProposalService | undefined);
184
+ constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quota" | "actionApprovalMode" | "attachments"> | undefined, queue?: ChatQueueService | undefined, proposals?: ActionProposalService | undefined);
169
185
  /**
170
186
  * Decide one independent proposal through the scoped proposal service — what the native
171
187
  * `action-proposals/:id/approve|reject` routes call — and the reply to show for it. `404` when
@@ -194,6 +210,37 @@ declare class AgentService {
194
210
  };
195
211
  text: string;
196
212
  }>;
213
+ /** How `action` tools wait for their approval here — `AgentModule.forRoot({ actionApprovalMode })`. */
214
+ actionApprovalMode(): ActionApprovalMode;
215
+ /**
216
+ * The words a text decision is made of (`actionProposalText.vocabulary`, English by default) — what
217
+ * a surface without buttons tells the person to reply.
218
+ */
219
+ actionProposalVocabulary(): TextActionProposalVocabulary;
220
+ /** The configured reply (`actionProposalText.replies`) to a decision the store answered with `result`. */
221
+ actionProposalReply(result: Pick<ActionProposalMutationView, 'status' | 'proposal'>, decision: 'approved' | 'rejected'): string;
222
+ /**
223
+ * The proposals of a thread this actor may see — the thread's own actor, or one the policy lets
224
+ * decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page). `404`
225
+ * when independent approvals are not on.
226
+ */
227
+ listActionProposals(actor: Actor, threadId: string): Promise<ActionProposalView[]>;
228
+ /**
229
+ * The attachment rules in force — what `GET <base>/config` serves and `POST <base>/attachments`
230
+ * enforces. `enabled: false` when no `AGENT_ATTACHMENT_STAGING` provider is bound.
231
+ */
232
+ attachmentLimits(): AttachmentLimits;
233
+ /**
234
+ * Stage a file for a later turn, held to the same limits as `POST <base>/attachments` — for a
235
+ * surface that receives files itself (a messaging webhook). Refuses with `501` when attachments are
236
+ * off, `415` for a type outside the allowlist and `413` past the size cap; send the returned
237
+ * `mediaId` as `attachments: [{ mediaId }]`.
238
+ */
239
+ stageAttachment(actor: Actor, file: {
240
+ data: Buffer;
241
+ contentType: string;
242
+ filename: string;
243
+ }): Promise<MessageAttachment>;
197
244
  /** The queue service when the bound store can hold a queue, else `undefined`. */
198
245
  private queueing;
199
246
  /** The queue service, or a 501 naming what is missing. */
@@ -677,20 +724,6 @@ declare class AttachmentsController {
677
724
  upload(req: Request, file: Express.Multer.File | undefined): Promise<MessageAttachment>;
678
725
  }
679
726
 
680
- /** Default per-file size cap (20 MiB). */
681
- declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
682
- /** Default allowlist: what multimodal model providers commonly accept as native image/file parts. */
683
- declare const DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES: readonly string[];
684
- /** How many attachments one message may name. */
685
- declare const MAX_ATTACHMENTS_PER_MESSAGE = 10;
686
- /** The attachment rules in force — `AgentAttachmentConfig`, as `GET <base>/config` serves it. */
687
- type AttachmentLimits = AgentAttachmentConfig;
688
- /**
689
- * One source for attachment limits: the staging store's own `describe()` when it declares them
690
- * (`AgentMediaAttachmentsModule` does), else `AgentModule`'s `attachments` option, else the defaults.
691
- */
692
- declare function attachmentLimits(options: Pick<AgentModuleOptions, 'attachments'> | undefined, staging: AttachmentStagingStore | undefined): AttachmentLimits;
693
-
694
727
  declare class ConfigController {
695
728
  private readonly options;
696
729
  private readonly actorResolver;
@@ -1465,15 +1498,26 @@ declare class ActionProposalController {
1465
1498
  reject(threadId: string, proposalId: string, request: Request, body: unknown): Promise<_dudousxd_nestjs_agent_core.ActionProposalMutationView>;
1466
1499
  }
1467
1500
 
1501
+ /** Called with a proposal the worker just settled (executed, or failed executing). */
1502
+ type ActionProposalSettledListener = (proposal: ActionProposal) => void | Promise<void>;
1468
1503
  declare class ActionProposalWorkerService implements OnModuleInit, OnModuleDestroy {
1469
1504
  private readonly store;
1470
1505
  private readonly options;
1471
1506
  private readonly deps;
1472
1507
  private worker;
1473
1508
  private readonly logger;
1509
+ private readonly settledListeners;
1510
+ /**
1511
+ * Run `listener` after every proposal this process's worker settles — how a module relays an
1512
+ * outcome somewhere the turn's stream no longer reaches (a text channel's conversation). Next to
1513
+ * `actionProposalWorker.onSettled`; a listener that throws is logged and does not stop the others.
1514
+ * Returns the unsubscribe. Only the replicas that run the worker (not `surface: 'http'`) call it.
1515
+ */
1516
+ onSettled(listener: ActionProposalSettledListener): () => void;
1517
+ private settled;
1474
1518
  constructor(store: AgentStore, options: AgentModuleOptions, deps: AgentDepsFactory);
1475
1519
  onModuleInit(): void;
1476
1520
  onModuleDestroy(): Promise<void>;
1477
1521
  }
1478
1522
 
1479
- export { AGENT_CHAT_QUEUE, AGENT_METADATA, AI_TOOL_METADATA, ATTACHMENT_PAGE_SIZE, ActionProposalController, ActionProposalService, ActionProposalWorkerService, type AgUiAdapterOptions, AgUiRunHandler, Agent, AgentApprovalPortAdapter, AgentDepsFactory, AgentDiscoveryService, AgentModule, AgentModuleAsyncOptions, AgentModuleOptions, type AgentOptions, AgentProtocolAdapter, AgentService, AgentSkillsOptions, AiTool, AiToolDiscoveryService, type AiToolOptions, type AnonymousActorOptions, AnonymousActorResolver, type AttachmentLimits, AttachmentsController, type ChatParams, ChatQueueService, type ChatSendMode, type ChatSendResult, ConfigController, DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, DEFAULT_MAX_ATTACHMENT_BYTES, type DeclaredSkill, HeaderActorResolver, InProcessTokenStreamSink, InlineAgentRunner, MAX_ATTACHMENTS_PER_MESSAGE, MemoriesController, MessagesController, ModelsController, QueueController, type QueuedSend, type RequestUserMapper, type ResolvedAiToolOptions, RunNotActiveException, SKILL_METADATA, SYSTEM_PROMPT_CONTRIBUTOR_METADATA, SYSTEM_PROMPT_METADATA, Skill, type SkillBody, SkillDiscoveryService, type SkillOptions, SkillsController, SystemPrompt, SystemPromptContributor, type ThreadDefaultAgentReader, type ThreadModelReader, type ThreadPersonaReader, ToolsController, agUiAdapter, attachmentLimits, declaredSkillProvider, defaultRequestUserMapper, readAgentMetadata, readAiToolMetadata, readSkillMetadata, requestUserActorResolver, resolveSkillsConfig, skillScope, threadPersona, toolNameFromClass };
1523
+ export { AGENT_CHAT_QUEUE, AGENT_METADATA, AI_TOOL_METADATA, ATTACHMENT_PAGE_SIZE, ActionProposalController, ActionProposalService, type ActionProposalSettledListener, ActionProposalWorkerService, type AgUiAdapterOptions, AgUiRunHandler, Agent, AgentApprovalPortAdapter, AgentDepsFactory, AgentDiscoveryService, AgentModule, AgentModuleAsyncOptions, AgentModuleOptions, type AgentOptions, AgentProtocolAdapter, AgentService, AgentSkillsOptions, AiTool, AiToolDiscoveryService, type AiToolOptions, type AnonymousActorOptions, AnonymousActorResolver, type AttachmentLimits, AttachmentsController, type ChatParams, ChatQueueService, type ChatSendMode, type ChatSendResult, ConfigController, DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, DEFAULT_MAX_ATTACHMENT_BYTES, type DeclaredSkill, HeaderActorResolver, InProcessTokenStreamSink, InlineAgentRunner, MAX_ATTACHMENTS_PER_MESSAGE, MemoriesController, MessagesController, ModelsController, QueueController, type QueuedSend, type RequestUserMapper, type ResolvedAiToolOptions, RunNotActiveException, SKILL_METADATA, SYSTEM_PROMPT_CONTRIBUTOR_METADATA, SYSTEM_PROMPT_METADATA, Skill, type SkillBody, SkillDiscoveryService, type SkillOptions, SkillsController, SystemPrompt, SystemPromptContributor, type ThreadDefaultAgentReader, type ThreadModelReader, type ThreadPersonaReader, ToolsController, agUiAdapter, attachmentLimits, declaredSkillProvider, defaultRequestUserMapper, readAgentMetadata, readAiToolMetadata, readSkillMetadata, requestUserActorResolver, resolveSkillsConfig, skillScope, threadPersona, toolNameFromClass };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { DynamicModule, Type, OnApplicationBootstrap, OnModuleInit, ConflictException, OnModuleDestroy } from '@nestjs/common';
2
- import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter, e as AgentSkillsOptions } from './chat-queue.service-CwxJDrBM.js';
3
- export { f as AGENT_TOOL_BRAND, g as AgentAttachmentsOptions, h as AgentDeps, i as AgentEngine, j as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QueuePlan, k as QueueSettleOutcome, l as QueuedTurn, m as QueuedTurnStarter, n as QuotaLimits, o as QuotaWindowLimits, p as defineTool, q as delegateToolName, r as provideAgentTool, s as provideAgentTools, u as utcDay } from './chat-queue.service-CwxJDrBM.js';
2
+ import { b as AgentModuleOptions, c as AgentModuleAsyncOptions, A as AgentDepsFactory, C as ChatQueueService, d as AgentProtocolAdapter, e as AgentSkillsOptions } from './chat-queue.service-ZQkqb1Yw.js';
3
+ export { f as AGENT_TOOL_BRAND, g as AgentAttachmentsOptions, h as AgentDeps, i as AgentEngine, j as AgentMemoryOptions, a as AgentSurface, F as FunctionalTool, L as LedgerQuotaProvider, Q as QueuePlan, k as QueueSettleOutcome, l as QueuedTurn, m as QueuedTurnStarter, n as QuotaLimits, o as QuotaWindowLimits, p as defineTool, q as delegateToolName, r as provideAgentTool, s as provideAgentTools, u as utcDay } from './chat-queue.service-ZQkqb1Yw.js';
4
4
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
5
- import { AgentStore, Actor, ListActionProposals, ActionProposalMutationView, AgentRunner, AttachmentStagingStore, ModelCatalog, QuotaProvider, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver, AgentApprovalPort, MessageAttachment, AgentAttachmentConfig, AgentClientConfig, ToolSpec, ToolPresentation, AgentHistoryWindow, AgentIntake, Persona, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, AgentRunStartOptions, TokenStreamSink, SinkWriter } from '@dudousxd/nestjs-agent-core';
5
+ import { AgentAttachmentConfig, AttachmentStagingStore, AgentStore, Actor, ListActionProposals, ActionProposalMutationView, TextActionProposalVocabulary, AgentRunner, ModelCatalog, QuotaProvider, ActionApprovalMode, ActionProposalView, MessageAttachment, QuotaReport, ModelCatalogView, AgentHostContext, AttachmentRef, PageContext, ChatQueueState, HumanReply, ThreadSummary, ThreadDetail, UpdateThreadInput, MessageFeedbackValue, MessageFeedback, StagedAttachment, ActorResolver, AgentApprovalPort, AgentClientConfig, ToolSpec, ToolPresentation, AgentHistoryWindow, AgentIntake, Persona, SkillContext, ToolRegistry, AgentRegistry, PromptContributor, SkillsConfig, SkillCatalogEntry, ToolCatalogEntry, MemoryConfig, MemoryDigestEntry, SkillProvider, AgentRunInput, AgentRunStartOptions, TokenStreamSink, SinkWriter, ActionProposal } from '@dudousxd/nestjs-agent-core';
6
6
  export * from '@dudousxd/nestjs-agent-core';
7
7
  export { FunctionalToolDefinition } from '@dudousxd/nestjs-agent-core';
8
8
  import { Request, Response } from 'express';
@@ -16,6 +16,20 @@ declare class AgentModule {
16
16
  static forRootAsync(options: AgentModuleAsyncOptions): DynamicModule;
17
17
  }
18
18
 
19
+ /** Default per-file size cap (20 MiB). */
20
+ declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
21
+ /** Default allowlist: what multimodal model providers commonly accept as native image/file parts. */
22
+ declare const DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES: readonly string[];
23
+ /** How many attachments one message may name. */
24
+ declare const MAX_ATTACHMENTS_PER_MESSAGE = 10;
25
+ /** The attachment rules in force — `AgentAttachmentConfig`, as `GET <base>/config` serves it. */
26
+ type AttachmentLimits = AgentAttachmentConfig;
27
+ /**
28
+ * One source for attachment limits: the staging store's own `describe()` when it declares them
29
+ * (`AgentMediaAttachmentsModule` does), else `AgentModule`'s `attachments` option, else the defaults.
30
+ */
31
+ declare function attachmentLimits(options: Pick<AgentModuleOptions, 'attachments'> | undefined, staging: AttachmentStagingStore | undefined): AttachmentLimits;
32
+
19
33
  declare class ActionProposalService {
20
34
  private readonly store;
21
35
  private readonly options;
@@ -55,8 +69,10 @@ declare class ActionProposalService {
55
69
  text: string;
56
70
  }>;
57
71
  private textReceipt;
72
+ /** The configured words a text decision is made of (`actionProposalText.vocabulary`). */
73
+ textVocabulary(): TextActionProposalVocabulary;
58
74
  /** The configured reply to a decision the store answered with `result`. */
59
- reply(result: ActionProposalMutationView, decision: 'approved' | 'rejected'): string;
75
+ reply(result: Pick<ActionProposalMutationView, 'status' | 'proposal'>, decision: 'approved' | 'rejected'): string;
60
76
  }
61
77
 
62
78
  /**
@@ -165,7 +181,7 @@ declare class AgentService {
165
181
  private readonly options?;
166
182
  private readonly queue?;
167
183
  private readonly proposals?;
168
- constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quota" | "actionApprovalMode"> | undefined, queue?: ChatQueueService | undefined, proposals?: ActionProposalService | undefined);
184
+ constructor(runner: AgentRunner, store: AgentStore, deps: AgentDepsFactory, staging?: AttachmentStagingStore | undefined, models?: ModelCatalog | undefined, quotaProvider?: QuotaProvider | undefined, options?: Pick<AgentModuleOptions, "quota" | "actionApprovalMode" | "attachments"> | undefined, queue?: ChatQueueService | undefined, proposals?: ActionProposalService | undefined);
169
185
  /**
170
186
  * Decide one independent proposal through the scoped proposal service — what the native
171
187
  * `action-proposals/:id/approve|reject` routes call — and the reply to show for it. `404` when
@@ -194,6 +210,37 @@ declare class AgentService {
194
210
  };
195
211
  text: string;
196
212
  }>;
213
+ /** How `action` tools wait for their approval here — `AgentModule.forRoot({ actionApprovalMode })`. */
214
+ actionApprovalMode(): ActionApprovalMode;
215
+ /**
216
+ * The words a text decision is made of (`actionProposalText.vocabulary`, English by default) — what
217
+ * a surface without buttons tells the person to reply.
218
+ */
219
+ actionProposalVocabulary(): TextActionProposalVocabulary;
220
+ /** The configured reply (`actionProposalText.replies`) to a decision the store answered with `result`. */
221
+ actionProposalReply(result: Pick<ActionProposalMutationView, 'status' | 'proposal'>, decision: 'approved' | 'rejected'): string;
222
+ /**
223
+ * The proposals of a thread this actor may see — the thread's own actor, or one the policy lets
224
+ * decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page). `404`
225
+ * when independent approvals are not on.
226
+ */
227
+ listActionProposals(actor: Actor, threadId: string): Promise<ActionProposalView[]>;
228
+ /**
229
+ * The attachment rules in force — what `GET <base>/config` serves and `POST <base>/attachments`
230
+ * enforces. `enabled: false` when no `AGENT_ATTACHMENT_STAGING` provider is bound.
231
+ */
232
+ attachmentLimits(): AttachmentLimits;
233
+ /**
234
+ * Stage a file for a later turn, held to the same limits as `POST <base>/attachments` — for a
235
+ * surface that receives files itself (a messaging webhook). Refuses with `501` when attachments are
236
+ * off, `415` for a type outside the allowlist and `413` past the size cap; send the returned
237
+ * `mediaId` as `attachments: [{ mediaId }]`.
238
+ */
239
+ stageAttachment(actor: Actor, file: {
240
+ data: Buffer;
241
+ contentType: string;
242
+ filename: string;
243
+ }): Promise<MessageAttachment>;
197
244
  /** The queue service when the bound store can hold a queue, else `undefined`. */
198
245
  private queueing;
199
246
  /** The queue service, or a 501 naming what is missing. */
@@ -677,20 +724,6 @@ declare class AttachmentsController {
677
724
  upload(req: Request, file: Express.Multer.File | undefined): Promise<MessageAttachment>;
678
725
  }
679
726
 
680
- /** Default per-file size cap (20 MiB). */
681
- declare const DEFAULT_MAX_ATTACHMENT_BYTES: number;
682
- /** Default allowlist: what multimodal model providers commonly accept as native image/file parts. */
683
- declare const DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES: readonly string[];
684
- /** How many attachments one message may name. */
685
- declare const MAX_ATTACHMENTS_PER_MESSAGE = 10;
686
- /** The attachment rules in force — `AgentAttachmentConfig`, as `GET <base>/config` serves it. */
687
- type AttachmentLimits = AgentAttachmentConfig;
688
- /**
689
- * One source for attachment limits: the staging store's own `describe()` when it declares them
690
- * (`AgentMediaAttachmentsModule` does), else `AgentModule`'s `attachments` option, else the defaults.
691
- */
692
- declare function attachmentLimits(options: Pick<AgentModuleOptions, 'attachments'> | undefined, staging: AttachmentStagingStore | undefined): AttachmentLimits;
693
-
694
727
  declare class ConfigController {
695
728
  private readonly options;
696
729
  private readonly actorResolver;
@@ -1465,15 +1498,26 @@ declare class ActionProposalController {
1465
1498
  reject(threadId: string, proposalId: string, request: Request, body: unknown): Promise<_dudousxd_nestjs_agent_core.ActionProposalMutationView>;
1466
1499
  }
1467
1500
 
1501
+ /** Called with a proposal the worker just settled (executed, or failed executing). */
1502
+ type ActionProposalSettledListener = (proposal: ActionProposal) => void | Promise<void>;
1468
1503
  declare class ActionProposalWorkerService implements OnModuleInit, OnModuleDestroy {
1469
1504
  private readonly store;
1470
1505
  private readonly options;
1471
1506
  private readonly deps;
1472
1507
  private worker;
1473
1508
  private readonly logger;
1509
+ private readonly settledListeners;
1510
+ /**
1511
+ * Run `listener` after every proposal this process's worker settles — how a module relays an
1512
+ * outcome somewhere the turn's stream no longer reaches (a text channel's conversation). Next to
1513
+ * `actionProposalWorker.onSettled`; a listener that throws is logged and does not stop the others.
1514
+ * Returns the unsubscribe. Only the replicas that run the worker (not `surface: 'http'`) call it.
1515
+ */
1516
+ onSettled(listener: ActionProposalSettledListener): () => void;
1517
+ private settled;
1474
1518
  constructor(store: AgentStore, options: AgentModuleOptions, deps: AgentDepsFactory);
1475
1519
  onModuleInit(): void;
1476
1520
  onModuleDestroy(): Promise<void>;
1477
1521
  }
1478
1522
 
1479
- export { AGENT_CHAT_QUEUE, AGENT_METADATA, AI_TOOL_METADATA, ATTACHMENT_PAGE_SIZE, ActionProposalController, ActionProposalService, ActionProposalWorkerService, type AgUiAdapterOptions, AgUiRunHandler, Agent, AgentApprovalPortAdapter, AgentDepsFactory, AgentDiscoveryService, AgentModule, AgentModuleAsyncOptions, AgentModuleOptions, type AgentOptions, AgentProtocolAdapter, AgentService, AgentSkillsOptions, AiTool, AiToolDiscoveryService, type AiToolOptions, type AnonymousActorOptions, AnonymousActorResolver, type AttachmentLimits, AttachmentsController, type ChatParams, ChatQueueService, type ChatSendMode, type ChatSendResult, ConfigController, DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, DEFAULT_MAX_ATTACHMENT_BYTES, type DeclaredSkill, HeaderActorResolver, InProcessTokenStreamSink, InlineAgentRunner, MAX_ATTACHMENTS_PER_MESSAGE, MemoriesController, MessagesController, ModelsController, QueueController, type QueuedSend, type RequestUserMapper, type ResolvedAiToolOptions, RunNotActiveException, SKILL_METADATA, SYSTEM_PROMPT_CONTRIBUTOR_METADATA, SYSTEM_PROMPT_METADATA, Skill, type SkillBody, SkillDiscoveryService, type SkillOptions, SkillsController, SystemPrompt, SystemPromptContributor, type ThreadDefaultAgentReader, type ThreadModelReader, type ThreadPersonaReader, ToolsController, agUiAdapter, attachmentLimits, declaredSkillProvider, defaultRequestUserMapper, readAgentMetadata, readAiToolMetadata, readSkillMetadata, requestUserActorResolver, resolveSkillsConfig, skillScope, threadPersona, toolNameFromClass };
1523
+ export { AGENT_CHAT_QUEUE, AGENT_METADATA, AI_TOOL_METADATA, ATTACHMENT_PAGE_SIZE, ActionProposalController, ActionProposalService, type ActionProposalSettledListener, ActionProposalWorkerService, type AgUiAdapterOptions, AgUiRunHandler, Agent, AgentApprovalPortAdapter, AgentDepsFactory, AgentDiscoveryService, AgentModule, AgentModuleAsyncOptions, AgentModuleOptions, type AgentOptions, AgentProtocolAdapter, AgentService, AgentSkillsOptions, AiTool, AiToolDiscoveryService, type AiToolOptions, type AnonymousActorOptions, AnonymousActorResolver, type AttachmentLimits, AttachmentsController, type ChatParams, ChatQueueService, type ChatSendMode, type ChatSendResult, ConfigController, DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES, DEFAULT_MAX_ATTACHMENT_BYTES, type DeclaredSkill, HeaderActorResolver, InProcessTokenStreamSink, InlineAgentRunner, MAX_ATTACHMENTS_PER_MESSAGE, MemoriesController, MessagesController, ModelsController, QueueController, type QueuedSend, type RequestUserMapper, type ResolvedAiToolOptions, RunNotActiveException, SKILL_METADATA, SYSTEM_PROMPT_CONTRIBUTOR_METADATA, SYSTEM_PROMPT_METADATA, Skill, type SkillBody, SkillDiscoveryService, type SkillOptions, SkillsController, SystemPrompt, SystemPromptContributor, type ThreadDefaultAgentReader, type ThreadModelReader, type ThreadPersonaReader, ToolsController, agUiAdapter, attachmentLimits, declaredSkillProvider, defaultRequestUserMapper, readAgentMetadata, readAiToolMetadata, readSkillMetadata, requestUserActorResolver, resolveSkillsConfig, skillScope, threadPersona, toolNameFromClass };
package/dist/index.js CHANGED
@@ -565,8 +565,8 @@ AgentDepsFactory2 = _ts_decorate2([
565
565
  ], AgentDepsFactory2);
566
566
 
567
567
  // src/agent.service.ts
568
- import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY2, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE4, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval as mayDecideApproval2, readElicitationQuestions, settleDeadRun, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
569
- import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException as ForbiddenException2, GoneException, HttpException, HttpStatus, Inject as Inject5, Injectable as Injectable4, NotFoundException as NotFoundException2, NotImplementedException as NotImplementedException3, Optional as Optional3 } from "@nestjs/common";
568
+ import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY2, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS4, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE4, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY as DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY2, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval as mayDecideApproval2, readElicitationQuestions, settleDeadRun, textActionProposalReply as textActionProposalReply2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
569
+ import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException as ForbiddenException2, GoneException, HttpException, HttpStatus, Inject as Inject5, Injectable as Injectable4, NotFoundException as NotFoundException2, NotImplementedException as NotImplementedException3, Optional as Optional3, PayloadTooLargeException, UnsupportedMediaTypeException } from "@nestjs/common";
570
570
 
571
571
  // src/agent-deps.ts
572
572
  function utcDay(date = /* @__PURE__ */ new Date()) {
@@ -590,6 +590,31 @@ function childSinkWriter(writer) {
590
590
  }
591
591
  __name(childSinkWriter, "childSinkWriter");
592
592
 
593
+ // src/attachment-limits.ts
594
+ var DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
595
+ var DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES = [
596
+ "image/png",
597
+ "image/jpeg",
598
+ "image/gif",
599
+ "image/webp",
600
+ "application/pdf",
601
+ "text/plain",
602
+ "text/csv"
603
+ ];
604
+ var MAX_ATTACHMENTS_PER_MESSAGE = 10;
605
+ function attachmentLimits(options, staging) {
606
+ const declared = staging?.describe?.();
607
+ const own = options?.attachments;
608
+ return {
609
+ enabled: staging !== void 0,
610
+ upload: staging === void 0 ? null : declared?.upload ?? "multipart",
611
+ maxBytes: declared?.maxBytes ?? own?.maxBytes ?? DEFAULT_MAX_ATTACHMENT_BYTES,
612
+ allowedContentTypes: declared?.allowedContentTypes ?? own?.allowedContentTypes ?? DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES,
613
+ maxPerMessage: MAX_ATTACHMENTS_PER_MESSAGE
614
+ };
615
+ }
616
+ __name(attachmentLimits, "attachmentLimits");
617
+
593
618
  // src/proposals/action-proposal.service.ts
594
619
  import { AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_STORE as AGENT_STORE2, DEFAULT_TEXT_ACTION_PROPOSAL_REPLIES, DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY, mayDecideApproval, parseTextActionProposalCommand, resolveTextActionProposalDecision, textActionProposalReply, toActionProposalMutationView, toActionProposalView } from "@dudousxd/nestjs-agent-core";
595
620
  import { ForbiddenException, Inject as Inject3, Injectable as Injectable2, NotFoundException, NotImplementedException } from "@nestjs/common";
@@ -746,6 +771,10 @@ var ActionProposalService = class {
746
771
  text: this.reply(result, decision)
747
772
  };
748
773
  }
774
+ /** The configured words a text decision is made of (`actionProposalText.vocabulary`). */
775
+ textVocabulary() {
776
+ return this.vocabulary;
777
+ }
749
778
  /** The configured reply to a decision the store answered with `result`. */
750
779
  reply(result, decision) {
751
780
  return textActionProposalReply(result, decision, this.replies);
@@ -1372,6 +1401,65 @@ var AgentService = class {
1372
1401
  };
1373
1402
  return this.proposals.handleTextDecision(threadId, actor, text);
1374
1403
  }
1404
+ /** How `action` tools wait for their approval here — `AgentModule.forRoot({ actionApprovalMode })`. */
1405
+ actionApprovalMode() {
1406
+ return this.options?.actionApprovalMode ?? "blocking";
1407
+ }
1408
+ /**
1409
+ * The words a text decision is made of (`actionProposalText.vocabulary`, English by default) — what
1410
+ * a surface without buttons tells the person to reply.
1411
+ */
1412
+ actionProposalVocabulary() {
1413
+ return this.proposals?.textVocabulary() ?? DEFAULT_TEXT_ACTION_PROPOSAL_VOCABULARY2;
1414
+ }
1415
+ /** The configured reply (`actionProposalText.replies`) to a decision the store answered with `result`. */
1416
+ actionProposalReply(result, decision) {
1417
+ return this.proposals?.reply(result, decision) ?? textActionProposalReply2(result, decision);
1418
+ }
1419
+ /**
1420
+ * The proposals of a thread this actor may see — the thread's own actor, or one the policy lets
1421
+ * decide them; what `GET <base>/threads/:threadId/action-proposals` serves (its first page). `404`
1422
+ * when independent approvals are not on.
1423
+ */
1424
+ async listActionProposals(actor, threadId) {
1425
+ if (this.options?.actionApprovalMode !== "independent" || !this.proposals) {
1426
+ throw new NotFoundException2("Proposal not found");
1427
+ }
1428
+ return this.proposals.list(threadId, actor);
1429
+ }
1430
+ /**
1431
+ * The attachment rules in force — what `GET <base>/config` serves and `POST <base>/attachments`
1432
+ * enforces. `enabled: false` when no `AGENT_ATTACHMENT_STAGING` provider is bound.
1433
+ */
1434
+ attachmentLimits() {
1435
+ return attachmentLimits(this.options, this.staging);
1436
+ }
1437
+ /**
1438
+ * Stage a file for a later turn, held to the same limits as `POST <base>/attachments` — for a
1439
+ * surface that receives files itself (a messaging webhook). Refuses with `501` when attachments are
1440
+ * off, `415` for a type outside the allowlist and `413` past the size cap; send the returned
1441
+ * `mediaId` as `attachments: [{ mediaId }]`.
1442
+ */
1443
+ async stageAttachment(actor, file) {
1444
+ if (this.staging === void 0) {
1445
+ throw new NotImplementedException3("Attachments are not configured on this server: bind AGENT_ATTACHMENT_STAGING (e.g. import AgentMediaAttachmentsModule).");
1446
+ }
1447
+ const { allowedContentTypes, maxBytes } = this.attachmentLimits();
1448
+ const contentType = file.contentType.split(";")[0]?.trim().toLowerCase() ?? "";
1449
+ if (!allowedContentTypes.includes(contentType)) {
1450
+ throw new UnsupportedMediaTypeException(`content type "${contentType}" is not allowed (allowed: ${allowedContentTypes.join(", ")})`);
1451
+ }
1452
+ if (file.data.byteLength > maxBytes) {
1453
+ throw new PayloadTooLargeException(`file exceeds the ${maxBytes}-byte limit`);
1454
+ }
1455
+ return this.staging.stage({
1456
+ data: file.data,
1457
+ filename: file.filename,
1458
+ contentType,
1459
+ sizeBytes: file.data.byteLength,
1460
+ actor
1461
+ });
1462
+ }
1375
1463
  /** The queue service when the bound store can hold a queue, else `undefined`. */
1376
1464
  queueing() {
1377
1465
  return this.queue?.supported === true ? this.queue : void 0;
@@ -2653,35 +2741,8 @@ AgentsController = _ts_decorate7([
2653
2741
 
2654
2742
  // src/controller/attachments.controller.ts
2655
2743
  import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING3, AGENT_OPTIONS as AGENT_OPTIONS5 } from "@dudousxd/nestjs-agent-core";
2656
- import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject7, NotImplementedException as NotImplementedException5, Optional as Optional5, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
2744
+ import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject7, NotImplementedException as NotImplementedException5, Optional as Optional5, PayloadTooLargeException as PayloadTooLargeException2, Post, Req, UnsupportedMediaTypeException as UnsupportedMediaTypeException2, UploadedFile, UseInterceptors } from "@nestjs/common";
2657
2745
  import { FileInterceptor } from "@nestjs/platform-express";
2658
-
2659
- // src/attachment-limits.ts
2660
- var DEFAULT_MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024;
2661
- var DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES = [
2662
- "image/png",
2663
- "image/jpeg",
2664
- "image/gif",
2665
- "image/webp",
2666
- "application/pdf",
2667
- "text/plain",
2668
- "text/csv"
2669
- ];
2670
- var MAX_ATTACHMENTS_PER_MESSAGE = 10;
2671
- function attachmentLimits(options, staging) {
2672
- const declared = staging?.describe?.();
2673
- const own = options?.attachments;
2674
- return {
2675
- enabled: staging !== void 0,
2676
- upload: staging === void 0 ? null : declared?.upload ?? "multipart",
2677
- maxBytes: declared?.maxBytes ?? own?.maxBytes ?? DEFAULT_MAX_ATTACHMENT_BYTES,
2678
- allowedContentTypes: declared?.allowedContentTypes ?? own?.allowedContentTypes ?? DEFAULT_ALLOWED_ATTACHMENT_CONTENT_TYPES,
2679
- maxPerMessage: MAX_ATTACHMENTS_PER_MESSAGE
2680
- };
2681
- }
2682
- __name(attachmentLimits, "attachmentLimits");
2683
-
2684
- // src/controller/attachments.controller.ts
2685
2746
  function _ts_decorate8(decorators, target, key, desc) {
2686
2747
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2687
2748
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -2748,10 +2809,10 @@ var AttachmentsController = class {
2748
2809
  }
2749
2810
  const { allowedContentTypes, maxBytes } = attachmentLimits(this.options, this.staging);
2750
2811
  if (!allowedContentTypes.includes(file.mimetype)) {
2751
- throw new UnsupportedMediaTypeException(`content type "${file.mimetype}" is not allowed (allowed: ${allowedContentTypes.join(", ")})`);
2812
+ throw new UnsupportedMediaTypeException2(`content type "${file.mimetype}" is not allowed (allowed: ${allowedContentTypes.join(", ")})`);
2752
2813
  }
2753
2814
  if (file.size > maxBytes) {
2754
- throw new PayloadTooLargeException(`file exceeds the ${maxBytes}-byte limit`);
2815
+ throw new PayloadTooLargeException2(`file exceeds the ${maxBytes}-byte limit`);
2755
2816
  }
2756
2817
  const actor = await this.actorResolver.resolve(req);
2757
2818
  return this.staging.stage({
@@ -5084,6 +5145,34 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
5084
5145
  deps;
5085
5146
  worker;
5086
5147
  logger = new Logger5(_ActionProposalWorkerService.name);
5148
+ settledListeners = /* @__PURE__ */ new Set();
5149
+ /**
5150
+ * Run `listener` after every proposal this process's worker settles — how a module relays an
5151
+ * outcome somewhere the turn's stream no longer reaches (a text channel's conversation). Next to
5152
+ * `actionProposalWorker.onSettled`; a listener that throws is logged and does not stop the others.
5153
+ * Returns the unsubscribe. Only the replicas that run the worker (not `surface: 'http'`) call it.
5154
+ */
5155
+ onSettled(listener) {
5156
+ this.settledListeners.add(listener);
5157
+ return () => {
5158
+ this.settledListeners.delete(listener);
5159
+ };
5160
+ }
5161
+ async settled(proposal) {
5162
+ const configured = this.options.actionProposalWorker?.onSettled;
5163
+ for (const listener of [
5164
+ ...configured ? [
5165
+ configured
5166
+ ] : [],
5167
+ ...this.settledListeners
5168
+ ]) {
5169
+ try {
5170
+ await listener(proposal);
5171
+ } catch (error) {
5172
+ this.logger.error(error);
5173
+ }
5174
+ }
5175
+ }
5087
5176
  constructor(store, options, deps) {
5088
5177
  this.store = store;
5089
5178
  this.options = options;
@@ -5099,6 +5188,7 @@ var ActionProposalWorkerService = class _ActionProposalWorkerService {
5099
5188
  store: this.store,
5100
5189
  workerId: randomUUID(),
5101
5190
  ...this.options.actionProposalWorker,
5191
+ onSettled: /* @__PURE__ */ __name((proposal) => this.settled(proposal), "onSettled"),
5102
5192
  executor: new ActionProposalExecutor({
5103
5193
  resolver,
5104
5194
  resolveExecution: /* @__PURE__ */ __name(async (proposal, actor) => {