@dudousxd/nestjs-agent 1.19.3 → 1.20.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.
@@ -33,7 +33,7 @@ __name(childSinkWriter, "childSinkWriter");
33
33
  var AGENT_CHAT_QUEUE = /* @__PURE__ */ Symbol.for("@dudousxd/nestjs-agent:chat-queue");
34
34
 
35
35
  // src/durable/agent-run.steps.ts
36
- import { AGENT_DEPS_FACTORY, createFrameBuffer, createUiCollector, encodeStreamEvent, invokeWithTransientRetry, observeTurnFrames, publishAgentToolRetry, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
36
+ import { AGENT_DEPS_FACTORY, createFrameBuffer, createUiCollector, encodeStreamEvent, intersectAllowLists, invokeWithTransientRetry, observeTurnFrames, publishAgentToolRetry, stampToolKinds, toolCallContext, traceLlmTurn, traceToolExecution, withAskTool, withMemoryTool, withSkillTool, withToolTimeout, withTurnFrames, wrapToolStepOutput } from "@dudousxd/nestjs-agent-core";
37
37
  import { Step } from "@dudousxd/nestjs-durable";
38
38
  import { Inject, Injectable } from "@nestjs/common";
39
39
 
@@ -97,14 +97,21 @@ var AgentRunSteps = class {
97
97
  const tools = withMemoryTool({
98
98
  tools: withSkillTool({
99
99
  tools: withAskTool({
100
- tools: await deps.registry.definitionsFor(input.actor, deps.rolesPolicy, deps.toolAllowList, {
101
- ...input.threadId !== void 0 ? {
102
- threadId: input.threadId
103
- } : {},
104
- ...input.agentName !== void 0 ? {
105
- agentName: input.agentName
106
- } : {}
107
- }),
100
+ tools: await deps.registry.definitionsFor(
101
+ input.actor,
102
+ deps.rolesPolicy,
103
+ // The persona narrowing the loop journaled in `persona:resolve` rides the envelope:
104
+ // this worker's own persona config may already say something else.
105
+ intersectAllowLists(deps.toolAllowList, input.personaAllowedTools),
106
+ {
107
+ ...input.threadId !== void 0 ? {
108
+ threadId: input.threadId
109
+ } : {},
110
+ ...input.agentName !== void 0 ? {
111
+ agentName: input.agentName
112
+ } : {}
113
+ }
114
+ ),
108
115
  ask: deps.ask
109
116
  }),
110
117
  enabled: deps.skills !== void 0
@@ -177,7 +184,9 @@ var AgentRunSteps = class {
177
184
  toolType: input.toolType
178
185
  }, () => invokeWithTransientRetry(() => {
179
186
  ui.restart();
180
- const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy);
187
+ const invocation = deps.registry.invoke(input.toolName, input.input, ctx, deps.rolesPolicy, input.allowedTools !== void 0 ? {
188
+ allowedTools: input.allowedTools
189
+ } : {});
181
190
  return input.timeoutMs !== void 0 ? withToolTimeout(invocation, input.timeoutMs, input.toolName) : invocation;
182
191
  }, transientRetry, {
183
192
  onRetry: /* @__PURE__ */ __name((attempt, error) => {
@@ -1085,14 +1094,14 @@ AgentDurableModule = _ts_decorate4([
1085
1094
  ], AgentDurableModule);
1086
1095
 
1087
1096
  // src/agent.module.ts
1088
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER13, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY7, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS7, 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_STORE7, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
1097
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER13, AGENT_APPROVAL_PORT, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY8, AGENT_DURABLE_RUNNER as AGENT_DURABLE_RUNNER2, AGENT_MEMORY as AGENT_MEMORY3, AGENT_MODEL as AGENT_MODEL2, AGENT_MODEL_CATALOG as AGENT_MODEL_CATALOG3, AGENT_OPTIONS as AGENT_OPTIONS7, 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_STORE7, AGENT_TOOL_REGISTRY as AGENT_TOOL_REGISTRY3, AgentRegistry as AgentRegistry6, ClosedRolesPolicy, DefaultRolesPolicy, InMemoryAgentStore, ToolRegistry as ToolRegistry3 } from "@dudousxd/nestjs-agent-core";
1089
1098
  import { Global as Global2, Logger as Logger8, Module as Module2 } from "@nestjs/common";
1090
1099
  import { DiscoveryModule, ModulesContainer, RouterModule } from "@nestjs/core";
1091
1100
 
1092
1101
  // src/agent-deps.factory.ts
1093
- import { AGENT_MEMORY, AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS, AGENT_STORE as AGENT_STORE3, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2, normalizeDelegation, summarizeWithModel, windowHistory } from "@dudousxd/nestjs-agent-core";
1102
+ import { AGENT_MEMORY, AGENT_MODEL, AGENT_PRICING_STORE, AGENT_PROMPT_CONTRIBUTORS, AGENT_REGISTRY, AGENT_ROLES_POLICY, AGENT_SINK as AGENT_SINK2, AGENT_SKILLS, AGENT_STORE as AGENT_STORE3, AGENT_TOOL_REGISTRY, AgentRegistry as AgentRegistry2, ToolRegistry as ToolRegistry2, findPersona, intersectAllowLists as intersectAllowLists2, normalizeDelegation, personaCatalogEntry, resolvePersonaAlias, summarizeWithModel, windowHistory } from "@dudousxd/nestjs-agent-core";
1094
1103
  import { AGENT_OPTIONS } from "@dudousxd/nestjs-agent-core";
1095
- import { Inject as Inject4, Injectable as Injectable4, Optional as Optional3 } from "@nestjs/common";
1104
+ import { BadRequestException, Inject as Inject4, Injectable as Injectable4, Optional as Optional3 } from "@nestjs/common";
1096
1105
  function _ts_decorate5(decorators, target, key, desc) {
1097
1106
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1098
1107
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1190,8 +1199,64 @@ var AgentDepsFactory2 = class {
1190
1199
  ...delegated
1191
1200
  ];
1192
1201
  }
1202
+ /**
1203
+ * The agent a name stands for: itself when it is a registered agent (or unknown — the bare
1204
+ * assistant), else the agent whose persona took the name over (`Persona.aliases`) and that persona.
1205
+ */
1206
+ resolveAgent(name) {
1207
+ if (this.agents.has(name)) {
1208
+ return {
1209
+ agentName: name
1210
+ };
1211
+ }
1212
+ const alias = resolvePersonaAlias(this.agents.list(), name);
1213
+ return alias === void 0 ? {
1214
+ agentName: name
1215
+ } : {
1216
+ agentName: alias.agent,
1217
+ persona: alias.persona
1218
+ };
1219
+ }
1220
+ /** `agentName`'s personas as a picker reads them. Empty when it declares none. */
1221
+ personaCatalog(agentName) {
1222
+ return (this.agents.get(agentName)?.personas ?? []).map(personaCatalogEntry);
1223
+ }
1224
+ /** The persona `agentName` runs under when nothing names one. Undefined → none. */
1225
+ defaultPersona(agentName) {
1226
+ return this.agents.get(agentName)?.defaultPersona;
1227
+ }
1228
+ /**
1229
+ * The persona a turn of `agentName` runs under, most specific first: the one the send names
1230
+ * (refused with `400 persona_not_found` when the agent does not declare it), else the thread's
1231
+ * pinned one when this agent declares it, else the agent's default. Undefined → none.
1232
+ */
1233
+ resolvePersona(args) {
1234
+ const definition = this.agents.get(args.agentName);
1235
+ if (args.requested !== void 0) {
1236
+ if (findPersona(definition, args.requested) === void 0) {
1237
+ throw new BadRequestException({
1238
+ statusCode: 400,
1239
+ code: "persona_not_found",
1240
+ message: `agent "${args.agentName}" has no persona "${args.requested}"`
1241
+ });
1242
+ }
1243
+ return args.requested;
1244
+ }
1245
+ const pinned = args.threadPersona ?? void 0;
1246
+ if (pinned !== void 0 && findPersona(definition, pinned) !== void 0) {
1247
+ return pinned;
1248
+ }
1249
+ return definition?.defaultPersona;
1250
+ }
1193
1251
  forAgent(agentName) {
1194
1252
  const name = agentName ?? this.defaultAgentName();
1253
+ if (agentName !== void 0 && !this.agents.has(agentName)) {
1254
+ const alias = resolvePersonaAlias(this.agents.list(), agentName);
1255
+ const persona = alias === void 0 ? void 0 : findPersona(this.agents.get(alias.agent), alias.persona);
1256
+ if (alias !== void 0 && persona !== void 0) {
1257
+ return this.withPersona(this.forAgent(alias.agent), persona);
1258
+ }
1259
+ }
1195
1260
  const definition = this.agents.get(name);
1196
1261
  const toolAllowList = this.effectiveTools(definition);
1197
1262
  const followUpsCount = this.followUpsCount();
@@ -1256,6 +1321,9 @@ var AgentDepsFactory2 = class {
1256
1321
  ...toolAllowList !== void 0 ? {
1257
1322
  toolAllowList
1258
1323
  } : {},
1324
+ ...definition?.personas !== void 0 ? {
1325
+ personas: definition.personas
1326
+ } : {},
1259
1327
  ...this.options.toolTimeoutMs !== void 0 ? {
1260
1328
  toolTimeoutMs: this.options.toolTimeoutMs
1261
1329
  } : {},
@@ -1274,6 +1342,45 @@ var AgentDepsFactory2 = class {
1274
1342
  };
1275
1343
  }
1276
1344
  /**
1345
+ * A persona baked into an agent's deps — how a run journaled under an agent name that a persona
1346
+ * has since taken over (`Persona.aliases`) is served. That run names no persona of its own (it
1347
+ * predates them, and its input cannot change), so the persona applies the way the old agent's own
1348
+ * config did: as config, re-read on every replay, with no checkpoint of its own.
1349
+ */
1350
+ withPersona(deps, persona) {
1351
+ const base = deps.systemPrompt;
1352
+ const ref = {
1353
+ id: persona.id,
1354
+ label: persona.label
1355
+ };
1356
+ const resolve = /* @__PURE__ */ __name(async (prompt, ctx) => typeof prompt === "function" ? prompt(ctx) : prompt, "resolve");
1357
+ const own = persona.systemPrompt;
1358
+ const systemPrompt = /* @__PURE__ */ __name(async (ctx) => {
1359
+ const scoped = {
1360
+ ...ctx,
1361
+ persona: ref
1362
+ };
1363
+ if (own === void 0) {
1364
+ return resolve(base, scoped);
1365
+ }
1366
+ const basePrompt = typeof own === "function" ? await resolve(base, scoped) : void 0;
1367
+ return resolve(own, {
1368
+ ...scoped,
1369
+ ...basePrompt !== void 0 ? {
1370
+ basePrompt
1371
+ } : {}
1372
+ });
1373
+ }, "systemPrompt");
1374
+ const toolAllowList = intersectAllowLists2(deps.toolAllowList, persona.allowedTools);
1375
+ return {
1376
+ ...deps,
1377
+ systemPrompt,
1378
+ ...toolAllowList !== void 0 ? {
1379
+ toolAllowList
1380
+ } : {}
1381
+ };
1382
+ }
1383
+ /**
1277
1384
  * The ceiling on how much of a thread this agent's turns carry, most specific wins: the agent's
1278
1385
  * own `@Agent({ history })`, else a module-wide custom `historyPolicy`, else the module-wide
1279
1386
  * `history` window. Undefined → unbounded, the behaviour of a module that configures none.
@@ -1348,12 +1455,24 @@ AgentDepsFactory2 = _ts_decorate5([
1348
1455
  ], AgentDepsFactory2);
1349
1456
 
1350
1457
  // src/agent.service.ts
1351
- import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE5, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval, readElicitationQuestions, settleDeadRun as settleDeadRun2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
1352
- import { BadRequestException, ConflictException as ConflictException2, ForbiddenException, GoneException, HttpException, HttpStatus, Inject as Inject6, Injectable as Injectable6, NotFoundException, NotImplementedException as NotImplementedException2, Optional as Optional5 } from "@nestjs/common";
1458
+ import { AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING2, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_MODEL_CATALOG, AGENT_OPTIONS as AGENT_OPTIONS3, AGENT_QUOTA_PROVIDER as AGENT_QUOTA_PROVIDER2, AGENT_RUNNER, AGENT_STORE as AGENT_STORE5, REQUESTER_APPROVER, findCatalogModel, mayDecideApproval, readElicitationQuestions, settleDeadRun as settleDeadRun2, validateElicitationAnswer } from "@dudousxd/nestjs-agent-core";
1459
+ import { BadRequestException as BadRequestException2, ConflictException as ConflictException2, ForbiddenException, GoneException, HttpException, HttpStatus, Inject as Inject6, Injectable as Injectable6, NotFoundException, NotImplementedException as NotImplementedException2, Optional as Optional5 } from "@nestjs/common";
1353
1460
 
1354
1461
  // src/queue/chat-queue.service.ts
1355
- import { AGENT_ATTACHMENT_STAGING, AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK3, AGENT_STORE as AGENT_STORE4, encodeStreamEvent as encodeStreamEvent4, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
1462
+ import { AGENT_ATTACHMENT_STAGING, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY3, AGENT_OPTIONS as AGENT_OPTIONS2, AGENT_QUOTA_PROVIDER, AGENT_SINK as AGENT_SINK3, AGENT_STORE as AGENT_STORE4, encodeStreamEvent as encodeStreamEvent4, isChatQueueStore, queuedMessageView } from "@dudousxd/nestjs-agent-core";
1356
1463
  import { Inject as Inject5, Injectable as Injectable5, Logger as Logger3, NotImplementedException, Optional as Optional4 } from "@nestjs/common";
1464
+
1465
+ // src/thread-persona.ts
1466
+ async function threadPersona(store, threadId) {
1467
+ const projecting = store;
1468
+ if (typeof projecting.personaForThread === "function") {
1469
+ return projecting.personaForThread(threadId);
1470
+ }
1471
+ return (await store.getThread(threadId))?.persona ?? null;
1472
+ }
1473
+ __name(threadPersona, "threadPersona");
1474
+
1475
+ // src/queue/chat-queue.service.ts
1357
1476
  function _ts_decorate6(decorators, target, key, desc) {
1358
1477
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1359
1478
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -1390,18 +1509,20 @@ var ChatQueueService2 = class _ChatQueueService {
1390
1509
  quotaProvider;
1391
1510
  options;
1392
1511
  staging;
1512
+ deps;
1393
1513
  logger = new Logger3(_ChatQueueService.name);
1394
1514
  /**
1395
1515
  * Runs this process claimed a thread for and has not handed to a runner yet. A holder in here is
1396
1516
  * alive whatever the runner says — it simply has not registered the run yet.
1397
1517
  */
1398
1518
  starting = /* @__PURE__ */ new Set();
1399
- constructor(store, sink, quotaProvider, options, staging) {
1519
+ constructor(store, sink, quotaProvider, options, staging, deps) {
1400
1520
  this.store = store;
1401
1521
  this.sink = sink;
1402
1522
  this.quotaProvider = quotaProvider;
1403
1523
  this.options = options;
1404
1524
  this.staging = staging;
1525
+ this.deps = deps;
1405
1526
  }
1406
1527
  /** Whether the bound store can hold a queue. Without one, a busy thread is not queued. */
1407
1528
  get supported() {
@@ -1699,13 +1820,17 @@ var ChatQueueService2 = class _ChatQueueService {
1699
1820
  */
1700
1821
  async inputFor(message) {
1701
1822
  const attachments = await this.freshAttachments(message.actor, message.attachments ?? []);
1823
+ const { agentName, persona } = await this.targetFor(message);
1702
1824
  return {
1703
1825
  threadId: message.threadId,
1704
1826
  actor: message.actor,
1705
1827
  userText: message.content,
1706
1828
  day: utcDay(),
1707
- ...message.agentName !== void 0 ? {
1708
- agentName: message.agentName
1829
+ ...agentName !== void 0 ? {
1830
+ agentName
1831
+ } : {},
1832
+ ...persona !== void 0 ? {
1833
+ persona
1709
1834
  } : {},
1710
1835
  ...attachments.length > 0 ? {
1711
1836
  attachments
@@ -1718,6 +1843,37 @@ var ChatQueueService2 = class _ChatQueueService {
1718
1843
  } : {}
1719
1844
  };
1720
1845
  }
1846
+ /**
1847
+ * The agent and persona a queued message starts as. A message carries the persona its send
1848
+ * resolved; one that carries none — queued before personas existed, or by a host that sets none —
1849
+ * resolves it now, exactly as a send would: an agent name a persona took over, then the thread's
1850
+ * pinned persona, then the agent's default. Never refused here: nobody is waiting on a 400.
1851
+ */
1852
+ async targetFor(message) {
1853
+ const deps = this.deps;
1854
+ if (message.persona !== void 0 || deps === void 0 || message.agentName === void 0) {
1855
+ return {
1856
+ ...message.agentName !== void 0 ? {
1857
+ agentName: message.agentName
1858
+ } : {},
1859
+ ...message.persona !== void 0 ? {
1860
+ persona: message.persona
1861
+ } : {}
1862
+ };
1863
+ }
1864
+ const target = deps.resolveAgent(message.agentName);
1865
+ const hasPersonas = deps.personaCatalog(target.agentName).length > 0;
1866
+ const persona = target.persona ?? (hasPersonas ? deps.resolvePersona({
1867
+ agentName: target.agentName,
1868
+ threadPersona: await threadPersona(this.store, message.threadId)
1869
+ }) : void 0);
1870
+ return {
1871
+ agentName: target.agentName,
1872
+ ...persona !== void 0 ? {
1873
+ persona
1874
+ } : {}
1875
+ };
1876
+ }
1721
1877
  async freshAttachments(actor, attachments) {
1722
1878
  const staging = this.staging;
1723
1879
  if (attachments.length === 0 || staging === void 0 || typeof staging.resolve !== "function") {
@@ -1745,13 +1901,16 @@ ChatQueueService2 = _ts_decorate6([
1745
1901
  _ts_param5(3, Inject5(AGENT_OPTIONS2)),
1746
1902
  _ts_param5(4, Optional4()),
1747
1903
  _ts_param5(4, Inject5(AGENT_ATTACHMENT_STAGING)),
1904
+ _ts_param5(5, Optional4()),
1905
+ _ts_param5(5, Inject5(AGENT_DEPS_FACTORY3)),
1748
1906
  _ts_metadata5("design:type", Function),
1749
1907
  _ts_metadata5("design:paramtypes", [
1750
1908
  typeof AgentStore === "undefined" ? Object : AgentStore,
1751
1909
  typeof TokenStreamSink === "undefined" ? Object : TokenStreamSink,
1752
1910
  typeof QuotaProvider === "undefined" ? Object : QuotaProvider,
1753
1911
  typeof Pick === "undefined" ? Object : Pick,
1754
- typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore
1912
+ typeof AttachmentStagingStore === "undefined" ? Object : AttachmentStagingStore,
1913
+ typeof AgentDepsFactory === "undefined" ? Object : AgentDepsFactory
1755
1914
  ])
1756
1915
  ], ChatQueueService2);
1757
1916
  function pauseReasonFor(outcome, head) {
@@ -1923,17 +2082,17 @@ var AgentService = class {
1923
2082
  */
1924
2083
  async assertModelAllowed(actor, agent, model) {
1925
2084
  if (this.models === void 0) {
1926
- throw new BadRequestException(`model "${model}" cannot be selected: no ModelCatalog is configured (AgentModule.forRoot({ models }))`);
2085
+ throw new BadRequestException2(`model "${model}" cannot be selected: no ModelCatalog is configured (AgentModule.forRoot({ models }))`);
1927
2086
  }
1928
2087
  const entry = findCatalogModel(await this.models.list({
1929
2088
  actor,
1930
2089
  agent
1931
2090
  }), model);
1932
2091
  if (entry === void 0) {
1933
- throw new BadRequestException(`model "${model}" is not offered`);
2092
+ throw new BadRequestException2(`model "${model}" is not offered`);
1934
2093
  }
1935
2094
  if (!entry.available) {
1936
- throw new BadRequestException(`model "${model}" is not available${entry.unavailableReason ? `: ${entry.unavailableReason}` : ""}`);
2095
+ throw new BadRequestException2(`model "${model}" is not available${entry.unavailableReason ? `: ${entry.unavailableReason}` : ""}`);
1937
2096
  }
1938
2097
  return entry.id;
1939
2098
  }
@@ -1949,7 +2108,7 @@ var AgentService = class {
1949
2108
  })).locked : void 0;
1950
2109
  if (locked !== void 0) {
1951
2110
  if (requested !== void 0 && requested !== locked.model) {
1952
- throw new BadRequestException(`model "${requested}" cannot be selected: ${locked.reason ?? `this agent always uses "${locked.model}"`}`);
2111
+ throw new BadRequestException2(`model "${requested}" cannot be selected: ${locked.reason ?? `this agent always uses "${locked.model}"`}`);
1953
2112
  }
1954
2113
  return locked.model;
1955
2114
  }
@@ -2005,13 +2164,15 @@ var AgentService = class {
2005
2164
  */
2006
2165
  async send(params) {
2007
2166
  await this.assertWithinQuota(params.actor);
2008
- const agentName = await this.resolveAgentName(params.agentName, params.threadId);
2167
+ const target = this.deps.resolveAgent(await this.resolveAgentName(params.agentName, params.threadId));
2168
+ const agentName = target.agentName;
2169
+ const persona = await this.resolvePersona(agentName, params.personaId ?? target.persona, params.threadId);
2009
2170
  const model = await this.resolveModel(params.actor, agentName, params.model, params.threadId);
2010
2171
  const attachments = await this.resolveAttachments(params.actor, params.attachments ?? []);
2011
2172
  let threadId = params.threadId;
2012
2173
  if (threadId === void 0) {
2013
2174
  if (params.regenerate === true) {
2014
- throw new BadRequestException("regenerate requires an existing threadId");
2175
+ throw new BadRequestException2("regenerate requires an existing threadId");
2015
2176
  }
2016
2177
  const created = await this.store.createThread({
2017
2178
  actor: params.actor,
@@ -2020,11 +2181,17 @@ var AgentService = class {
2020
2181
  } : {},
2021
2182
  ...params.newThreadId !== void 0 ? {
2022
2183
  id: params.newThreadId
2184
+ } : {},
2185
+ ...params.personaId !== void 0 ? {
2186
+ persona: params.personaId
2023
2187
  } : {}
2024
2188
  });
2025
2189
  threadId = created.id;
2026
2190
  } else {
2027
2191
  await this.assertOwnsThread(params.actor, threadId);
2192
+ if (params.personaId !== void 0) {
2193
+ await this.pinThreadPersona(threadId, params.personaId);
2194
+ }
2028
2195
  }
2029
2196
  const input = {
2030
2197
  threadId,
@@ -2032,6 +2199,9 @@ var AgentService = class {
2032
2199
  userText: params.message,
2033
2200
  day: utcDay(),
2034
2201
  agentName,
2202
+ ...persona !== void 0 ? {
2203
+ persona
2204
+ } : {},
2035
2205
  ...params.regenerate === true ? {
2036
2206
  regenerate: true
2037
2207
  } : {},
@@ -2118,6 +2288,9 @@ var AgentService = class {
2118
2288
  ...input.agentName !== void 0 ? {
2119
2289
  agentName: input.agentName
2120
2290
  } : {},
2291
+ ...input.persona !== void 0 ? {
2292
+ persona: input.persona
2293
+ } : {},
2121
2294
  ...input.model !== void 0 ? {
2122
2295
  model: input.model
2123
2296
  } : {},
@@ -2170,7 +2343,7 @@ var AgentService = class {
2170
2343
  const store = queue.queueStore();
2171
2344
  const threadId = await this.assertOwnsQueuedMessage(actor, messageId);
2172
2345
  if (patch.message !== void 0 && patch.message.trim().length === 0) {
2173
- throw new BadRequestException("message must not be empty");
2346
+ throw new BadRequestException2("message must not be empty");
2174
2347
  }
2175
2348
  const attachments = patch.attachments === void 0 || patch.attachments === null ? patch.attachments : await this.resolveAttachments(actor, patch.attachments);
2176
2349
  if (patch.message !== void 0 || attachments !== void 0) {
@@ -2188,7 +2361,7 @@ var AgentService = class {
2188
2361
  }
2189
2362
  if (patch.position !== void 0) {
2190
2363
  if (!Number.isInteger(patch.position) || patch.position < 0) {
2191
- throw new BadRequestException("position must be a non-negative integer");
2364
+ throw new BadRequestException2("position must be a non-negative integer");
2192
2365
  }
2193
2366
  if (!await store.moveQueuedMessage(messageId, patch.position)) {
2194
2367
  throw new GoneException(`queued message ${messageId} already started or was removed`);
@@ -2512,16 +2685,22 @@ var AgentService = class {
2512
2685
  async updateThread(actor, threadId, patch) {
2513
2686
  const title = patch.title !== void 0 ? this.validateTitle(patch.title) : void 0;
2514
2687
  await this.assertOwnsThread(actor, threadId);
2515
- if (patch.defaultAgent === void 0 && patch.model === void 0) {
2688
+ if (patch.defaultAgent === void 0 && patch.model === void 0 && patch.persona === void 0) {
2516
2689
  if (title !== void 0) {
2517
2690
  await this.store.setTitle(threadId, title);
2518
2691
  }
2519
2692
  return;
2520
2693
  }
2521
2694
  if (this.store.updateThread === void 0) {
2522
- throw new NotImplementedException2("Setting a thread's defaultAgent or model requires an AgentStore that implements updateThread(); the bound store does not support it.");
2695
+ throw new NotImplementedException2("Setting a thread's defaultAgent, model or persona requires an AgentStore that implements updateThread(); the bound store does not support it.");
2523
2696
  }
2524
2697
  const model = patch.model === void 0 || patch.model === null ? patch.model : await this.assertModelAllowed(actor, patch.defaultAgent ?? await this.resolveAgentName(void 0, threadId), patch.model);
2698
+ if (patch.persona !== void 0 && patch.persona !== null) {
2699
+ this.deps.resolvePersona({
2700
+ agentName: this.deps.resolveAgent(patch.defaultAgent ?? await this.resolveAgentName(void 0, threadId)).agentName,
2701
+ requested: patch.persona
2702
+ });
2703
+ }
2525
2704
  await this.store.updateThread(threadId, {
2526
2705
  ...title !== void 0 ? {
2527
2706
  title
@@ -2531,16 +2710,46 @@ var AgentService = class {
2531
2710
  } : {},
2532
2711
  ...model !== void 0 ? {
2533
2712
  model
2713
+ } : {},
2714
+ ...patch.persona !== void 0 ? {
2715
+ persona: patch.persona
2716
+ } : {}
2717
+ });
2718
+ }
2719
+ /**
2720
+ * The persona this send runs under — see {@link AgentDepsFactory.resolvePersona}. The thread's
2721
+ * pinned persona is read only when the send names none AND the agent has personas to pick from.
2722
+ */
2723
+ async resolvePersona(agentName, requested, threadId) {
2724
+ const needsThread = requested === void 0 && threadId !== void 0 && this.deps.personaCatalog(agentName).length > 0;
2725
+ return this.deps.resolvePersona({
2726
+ agentName,
2727
+ ...requested !== void 0 ? {
2728
+ requested
2729
+ } : {},
2730
+ ...needsThread ? {
2731
+ threadPersona: await threadPersona(this.store, threadId)
2534
2732
  } : {}
2535
2733
  });
2536
2734
  }
2735
+ /** Pin `persona` on the thread when it is not already — a no-op on a store that cannot. */
2736
+ async pinThreadPersona(threadId, persona) {
2737
+ if (this.store.updateThread === void 0) {
2738
+ return;
2739
+ }
2740
+ if (await threadPersona(this.store, threadId) !== persona) {
2741
+ await this.store.updateThread(threadId, {
2742
+ persona
2743
+ });
2744
+ }
2745
+ }
2537
2746
  validateTitle(title) {
2538
2747
  const trimmed = title.trim();
2539
2748
  if (trimmed.length === 0) {
2540
- throw new BadRequestException("title must not be empty");
2749
+ throw new BadRequestException2("title must not be empty");
2541
2750
  }
2542
2751
  if (trimmed.length > 200) {
2543
- throw new BadRequestException("title must be at most 200 characters");
2752
+ throw new BadRequestException2("title must be at most 200 characters");
2544
2753
  }
2545
2754
  return trimmed;
2546
2755
  }
@@ -2579,6 +2788,7 @@ var AgentService = class {
2579
2788
  ...thread,
2580
2789
  defaultAgent: thread.defaultAgent ?? null,
2581
2790
  model: thread.model ?? null,
2791
+ persona: thread.persona ?? null,
2582
2792
  activeRunId: await this.store.activeRunForThread?.(thread.id) ?? thread.activeRunId ?? null
2583
2793
  };
2584
2794
  }
@@ -2643,14 +2853,14 @@ var AgentService = class {
2643
2853
  */
2644
2854
  async setMessageFeedback(actor, messageId, input) {
2645
2855
  if (input.value !== null && input.value !== "up" && input.value !== "down") {
2646
- throw new BadRequestException("value must be 'up', 'down' or null");
2856
+ throw new BadRequestException2("value must be 'up', 'down' or null");
2647
2857
  }
2648
2858
  if (input.comment !== void 0 && typeof input.comment !== "string") {
2649
- throw new BadRequestException("comment must be a string");
2859
+ throw new BadRequestException2("comment must be a string");
2650
2860
  }
2651
2861
  const comment = input.comment?.trim();
2652
2862
  if (comment !== void 0 && comment.length > 2e3) {
2653
- throw new BadRequestException("comment must be at most 2000 characters");
2863
+ throw new BadRequestException2("comment must be at most 2000 characters");
2654
2864
  }
2655
2865
  if (this.store.threadOfMessage === void 0 || this.store.setMessageFeedback === void 0) {
2656
2866
  throw new NotImplementedException2("Message feedback requires an AgentStore that implements threadOfMessage() and setMessageFeedback(); the bound store does not support it.");
@@ -2775,7 +2985,7 @@ var AgentService = class {
2775
2985
  const submitted = Object.hasOwn(answers2, question.id) ? answers2[question.id] : void 0;
2776
2986
  const problem = validateElicitationAnswer(question, submitted ?? question.defaults ?? []);
2777
2987
  if (problem !== null) {
2778
- throw new BadRequestException(`answers["${question.id}"] ${problem}`);
2988
+ throw new BadRequestException2(`answers["${question.id}"] ${problem}`);
2779
2989
  }
2780
2990
  }
2781
2991
  }
@@ -2849,7 +3059,7 @@ AgentService = _ts_decorate7([
2849
3059
  Injectable6(),
2850
3060
  _ts_param6(0, Inject6(AGENT_RUNNER)),
2851
3061
  _ts_param6(1, Inject6(AGENT_STORE5)),
2852
- _ts_param6(2, Inject6(AGENT_DEPS_FACTORY3)),
3062
+ _ts_param6(2, Inject6(AGENT_DEPS_FACTORY4)),
2853
3063
  _ts_param6(3, Optional5()),
2854
3064
  _ts_param6(3, Inject6(AGENT_ATTACHMENT_STAGING2)),
2855
3065
  _ts_param6(4, Optional5()),
@@ -2940,7 +3150,7 @@ AgentApprovalPortAdapter = _ts_decorate8([
2940
3150
  ], AgentApprovalPortAdapter);
2941
3151
 
2942
3152
  // src/controller/agents.controller.ts
2943
- import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY4, AGENT_REGISTRY as AGENT_REGISTRY2, AgentRegistry as AgentRegistry3 } from "@dudousxd/nestjs-agent-core";
3153
+ import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY5, AGENT_REGISTRY as AGENT_REGISTRY2, AgentRegistry as AgentRegistry3 } from "@dudousxd/nestjs-agent-core";
2944
3154
  import { Controller, Get, Inject as Inject7 } from "@nestjs/common";
2945
3155
  function _ts_decorate9(decorators, target, key, desc) {
2946
3156
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -2980,13 +3190,22 @@ var AgentsController = class {
2980
3190
  }
2981
3191
  list() {
2982
3192
  const defaultAgentName = this.depsFactory.defaultAgentName();
2983
- return this.agents.list().map((definition) => ({
2984
- name: definition.name,
2985
- description: definition.description ?? "",
2986
- ...definition.name === defaultAgentName ? {
2987
- isDefault: true
2988
- } : {}
2989
- }));
3193
+ return this.agents.list().map((definition) => {
3194
+ const personas = this.depsFactory.personaCatalog(definition.name);
3195
+ return {
3196
+ name: definition.name,
3197
+ description: definition.description ?? "",
3198
+ ...definition.name === defaultAgentName ? {
3199
+ isDefault: true
3200
+ } : {},
3201
+ ...personas.length > 0 ? {
3202
+ personas
3203
+ } : {},
3204
+ ...definition.defaultPersona !== void 0 ? {
3205
+ defaultPersona: definition.defaultPersona
3206
+ } : {}
3207
+ };
3208
+ });
2990
3209
  }
2991
3210
  };
2992
3211
  _ts_decorate9([
@@ -2998,7 +3217,7 @@ _ts_decorate9([
2998
3217
  AgentsController = _ts_decorate9([
2999
3218
  Controller("agents"),
3000
3219
  _ts_param7(0, Inject7(AGENT_REGISTRY2)),
3001
- _ts_param7(1, Inject7(AGENT_DEPS_FACTORY4)),
3220
+ _ts_param7(1, Inject7(AGENT_DEPS_FACTORY5)),
3002
3221
  _ts_metadata8("design:type", Function),
3003
3222
  _ts_metadata8("design:paramtypes", [
3004
3223
  typeof AgentRegistry3 === "undefined" ? Object : AgentRegistry3,
@@ -3008,7 +3227,7 @@ AgentsController = _ts_decorate9([
3008
3227
 
3009
3228
  // src/controller/attachments.controller.ts
3010
3229
  import { AGENT_ACTOR_RESOLVER, AGENT_ATTACHMENT_STAGING as AGENT_ATTACHMENT_STAGING3, AGENT_OPTIONS as AGENT_OPTIONS4 } from "@dudousxd/nestjs-agent-core";
3011
- import { BadRequestException as BadRequestException2, Controller as Controller2, Get as Get2, Inject as Inject8, NotImplementedException as NotImplementedException3, Optional as Optional6, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
3230
+ import { BadRequestException as BadRequestException3, Controller as Controller2, Get as Get2, Inject as Inject8, NotImplementedException as NotImplementedException3, Optional as Optional6, PayloadTooLargeException, Post, Req, UnsupportedMediaTypeException, UploadedFile, UseInterceptors } from "@nestjs/common";
3012
3231
  import { FileInterceptor } from "@nestjs/platform-express";
3013
3232
 
3014
3233
  // src/attachment-limits.ts
@@ -3099,7 +3318,7 @@ var AttachmentsController = class {
3099
3318
  throw new NotImplementedException3("Attachment upload is not configured on this server: bind AGENT_ATTACHMENT_STAGING (e.g. import AgentMediaAttachmentsModule).");
3100
3319
  }
3101
3320
  if (file === void 0) {
3102
- throw new BadRequestException2('multipart field "file" is required');
3321
+ throw new BadRequestException3('multipart field "file" is required');
3103
3322
  }
3104
3323
  const { allowedContentTypes, maxBytes } = attachmentLimits(this.options, this.staging);
3105
3324
  if (!allowedContentTypes.includes(file.mimetype)) {
@@ -3160,7 +3379,7 @@ AttachmentsController = _ts_decorate10([
3160
3379
 
3161
3380
  // src/controller/chat.controller.ts
3162
3381
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER2, AgentStreamError as AgentStreamError2, streamFailure as streamFailure2 } from "@dudousxd/nestjs-agent-core";
3163
- import { BadRequestException as BadRequestException3, Body, Controller as Controller3, Get as Get3, Inject as Inject9, Param, Post as Post2, Query, Req as Req2, Res } from "@nestjs/common";
3382
+ import { BadRequestException as BadRequestException4, Body, Controller as Controller3, Get as Get3, Inject as Inject9, Param, Post as Post2, Query, Req as Req2, Res } from "@nestjs/common";
3164
3383
  function _ts_decorate11(decorators, target, key, desc) {
3165
3384
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3166
3385
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -3197,7 +3416,7 @@ function sendMode(body) {
3197
3416
  if (body.mode === "auto" || body.mode === "queue" || body.mode === "interrupt") {
3198
3417
  return body.mode;
3199
3418
  }
3200
- throw new BadRequestException3("mode must be 'auto', 'queue' or 'interrupt'");
3419
+ throw new BadRequestException4("mode must be 'auto', 'queue' or 'interrupt'");
3201
3420
  }
3202
3421
  __name(sendMode, "sendMode");
3203
3422
  function attachmentRefs(claimed) {
@@ -3205,21 +3424,21 @@ function attachmentRefs(claimed) {
3205
3424
  return [];
3206
3425
  }
3207
3426
  if (!Array.isArray(claimed)) {
3208
- throw new BadRequestException3("attachments must be an array of { mediaId }");
3427
+ throw new BadRequestException4("attachments must be an array of { mediaId }");
3209
3428
  }
3210
3429
  if (claimed.length > MAX_ATTACHMENTS_PER_MESSAGE) {
3211
- throw new BadRequestException3(`a message may carry at most ${MAX_ATTACHMENTS_PER_MESSAGE} attachments`);
3430
+ throw new BadRequestException4(`a message may carry at most ${MAX_ATTACHMENTS_PER_MESSAGE} attachments`);
3212
3431
  }
3213
3432
  return claimed.map((entry) => {
3214
3433
  if (typeof entry !== "object" || entry === null || !("mediaId" in entry)) {
3215
- throw new BadRequestException3("each attachment must be an object with a mediaId");
3434
+ throw new BadRequestException4("each attachment must be an object with a mediaId");
3216
3435
  }
3217
3436
  if (Object.keys(entry).some((key) => key !== "mediaId")) {
3218
- throw new BadRequestException3("attachments are { mediaId } refs \u2014 send nothing but the id");
3437
+ throw new BadRequestException4("attachments are { mediaId } refs \u2014 send nothing but the id");
3219
3438
  }
3220
3439
  const { mediaId } = entry;
3221
3440
  if (typeof mediaId !== "string" || mediaId.length === 0) {
3222
- throw new BadRequestException3("each attachment must carry a non-empty string mediaId");
3441
+ throw new BadRequestException4("each attachment must carry a non-empty string mediaId");
3223
3442
  }
3224
3443
  return {
3225
3444
  mediaId
@@ -3256,6 +3475,9 @@ var ChatController = class {
3256
3475
  ...body.agent !== void 0 ? {
3257
3476
  agentName: body.agent
3258
3477
  } : {},
3478
+ ...typeof body.persona === "string" && body.persona.length > 0 ? {
3479
+ personaId: body.persona
3480
+ } : {},
3259
3481
  ...attachments.length > 0 ? {
3260
3482
  attachments
3261
3483
  } : {},
@@ -3882,7 +4104,7 @@ ModelsController = _ts_decorate15([
3882
4104
 
3883
4105
  // src/controller/queue.controller.ts
3884
4106
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER7 } from "@dudousxd/nestjs-agent-core";
3885
- import { BadRequestException as BadRequestException4, Body as Body3, Controller as Controller8, Delete as Delete2, Get as Get7, Inject as Inject14, Param as Param4, Patch, Post as Post4, Req as Req7 } from "@nestjs/common";
4107
+ import { BadRequestException as BadRequestException5, Body as Body3, Controller as Controller8, Delete as Delete2, Get as Get7, Inject as Inject14, Param as Param4, Patch, Post as Post4, Req as Req7 } from "@nestjs/common";
3886
4108
  function _ts_decorate16(decorators, target, key, desc) {
3887
4109
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3888
4110
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -3932,10 +4154,10 @@ var QueueController = class {
3932
4154
  async update(req, messageId, body) {
3933
4155
  const actor = await this.actorResolver.resolve(req);
3934
4156
  if (body.message !== void 0 && typeof body.message !== "string") {
3935
- throw new BadRequestException4("message must be a string");
4157
+ throw new BadRequestException5("message must be a string");
3936
4158
  }
3937
4159
  if (body.position !== void 0 && typeof body.position !== "number") {
3938
- throw new BadRequestException4("position must be a number");
4160
+ throw new BadRequestException5("position must be a number");
3939
4161
  }
3940
4162
  const attachments = body.attachments === void 0 ? void 0 : body.attachments === null ? null : attachmentRefs(body.attachments);
3941
4163
  return this.agent.updateQueuedMessage(actor, messageId, {
@@ -4255,6 +4477,9 @@ var ThreadsController = class {
4255
4477
  } : {},
4256
4478
  ..."model" in body ? {
4257
4479
  model: body.model ?? null
4480
+ } : {},
4481
+ ..."persona" in body ? {
4482
+ persona: body.persona ?? null
4258
4483
  } : {}
4259
4484
  });
4260
4485
  return {
@@ -4369,7 +4594,7 @@ ThreadsController = _ts_decorate19([
4369
4594
 
4370
4595
  // src/controller/tool-call.controller.ts
4371
4596
  import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER11 } from "@dudousxd/nestjs-agent-core";
4372
- import { BadRequestException as BadRequestException5, Body as Body5, Controller as Controller12, Inject as Inject18, Post as Post6, Req as Req11 } from "@nestjs/common";
4597
+ import { BadRequestException as BadRequestException6, Body as Body5, Controller as Controller12, Inject as Inject18, Post as Post6, Req as Req11 } from "@nestjs/common";
4373
4598
  function _ts_decorate20(decorators, target, key, desc) {
4374
4599
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4375
4600
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -4404,7 +4629,7 @@ var MAX_VIA_LENGTH = 64;
4404
4629
  var DEFAULT_VIA = "web";
4405
4630
  function toolCallId(claimed) {
4406
4631
  if (typeof claimed !== "string" || claimed.length === 0) {
4407
- throw new BadRequestException5("toolCallId must be a non-empty string");
4632
+ throw new BadRequestException6("toolCallId must be a non-empty string");
4408
4633
  }
4409
4634
  return claimed;
4410
4635
  }
@@ -4414,10 +4639,10 @@ function rejectReason(claimed) {
4414
4639
  return void 0;
4415
4640
  }
4416
4641
  if (typeof claimed !== "string") {
4417
- throw new BadRequestException5("reason must be a string");
4642
+ throw new BadRequestException6("reason must be a string");
4418
4643
  }
4419
4644
  if (claimed.length > MAX_REJECT_REASON_LENGTH) {
4420
- throw new BadRequestException5(`reason must be at most ${MAX_REJECT_REASON_LENGTH} characters`);
4645
+ throw new BadRequestException6(`reason must be at most ${MAX_REJECT_REASON_LENGTH} characters`);
4421
4646
  }
4422
4647
  return claimed;
4423
4648
  }
@@ -4427,7 +4652,7 @@ function remember(claimed) {
4427
4652
  return false;
4428
4653
  }
4429
4654
  if (typeof claimed !== "boolean") {
4430
- throw new BadRequestException5("remember must be a boolean");
4655
+ throw new BadRequestException6("remember must be a boolean");
4431
4656
  }
4432
4657
  return claimed;
4433
4658
  }
@@ -4437,7 +4662,7 @@ function via(claimed) {
4437
4662
  return DEFAULT_VIA;
4438
4663
  }
4439
4664
  if (typeof claimed !== "string" || claimed.length === 0 || claimed.length > MAX_VIA_LENGTH) {
4440
- throw new BadRequestException5(`via must be a string of 1-${MAX_VIA_LENGTH} characters`);
4665
+ throw new BadRequestException6(`via must be a string of 1-${MAX_VIA_LENGTH} characters`);
4441
4666
  }
4442
4667
  return claimed;
4443
4668
  }
@@ -4447,26 +4672,26 @@ function answers(claimed) {
4447
4672
  return void 0;
4448
4673
  }
4449
4674
  if (typeof claimed !== "object" || claimed === null || Array.isArray(claimed)) {
4450
- throw new BadRequestException5("answers must be an object of questionId \u2192 chosen values");
4675
+ throw new BadRequestException6("answers must be an object of questionId \u2192 chosen values");
4451
4676
  }
4452
4677
  const entries = Object.entries(claimed);
4453
4678
  if (entries.length > MAX_ANSWERED_QUESTIONS) {
4454
- throw new BadRequestException5(`answers may cover at most ${MAX_ANSWERED_QUESTIONS} questions`);
4679
+ throw new BadRequestException6(`answers may cover at most ${MAX_ANSWERED_QUESTIONS} questions`);
4455
4680
  }
4456
4681
  const validated = /* @__PURE__ */ Object.create(null);
4457
4682
  for (const [questionId, values] of entries) {
4458
4683
  if (!Array.isArray(values)) {
4459
- throw new BadRequestException5(`answers["${questionId}"] must be an array of chosen values`);
4684
+ throw new BadRequestException6(`answers["${questionId}"] must be an array of chosen values`);
4460
4685
  }
4461
4686
  if (values.length > MAX_VALUES_PER_QUESTION) {
4462
- throw new BadRequestException5(`answers["${questionId}"] may carry at most ${MAX_VALUES_PER_QUESTION} values`);
4687
+ throw new BadRequestException6(`answers["${questionId}"] may carry at most ${MAX_VALUES_PER_QUESTION} values`);
4463
4688
  }
4464
4689
  for (const value of values) {
4465
4690
  if (typeof value !== "string") {
4466
- throw new BadRequestException5(`answers["${questionId}"] must contain only strings`);
4691
+ throw new BadRequestException6(`answers["${questionId}"] must contain only strings`);
4467
4692
  }
4468
4693
  if (value.length > MAX_ANSWER_VALUE_LENGTH) {
4469
- throw new BadRequestException5(`answers["${questionId}"] values must be at most ${MAX_ANSWER_VALUE_LENGTH} characters`);
4694
+ throw new BadRequestException6(`answers["${questionId}"] values must be at most ${MAX_ANSWER_VALUE_LENGTH} characters`);
4470
4695
  }
4471
4696
  }
4472
4697
  validated[questionId] = values;
@@ -4583,7 +4808,7 @@ ToolCallController = _ts_decorate20([
4583
4808
  ], ToolCallController);
4584
4809
 
4585
4810
  // src/controller/tools.controller.ts
4586
- import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER12, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY5, AGENT_REGISTRY as AGENT_REGISTRY3, ALL_AGENTS, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
4811
+ import { AGENT_ACTOR_RESOLVER as AGENT_ACTOR_RESOLVER12, AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY6, AGENT_REGISTRY as AGENT_REGISTRY3, ALL_AGENTS, AgentRegistry as AgentRegistry4 } from "@dudousxd/nestjs-agent-core";
4587
4812
  import { Controller as Controller13, Get as Get11, Inject as Inject19, NotFoundException as NotFoundException3, Query as Query5, Req as Req12 } from "@nestjs/common";
4588
4813
  function _ts_decorate21(decorators, target, key, desc) {
4589
4814
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -4668,7 +4893,7 @@ _ts_decorate21([
4668
4893
  ToolsController = _ts_decorate21([
4669
4894
  Controller13("tools"),
4670
4895
  _ts_param19(0, Inject19(AGENT_ACTOR_RESOLVER12)),
4671
- _ts_param19(1, Inject19(AGENT_DEPS_FACTORY5)),
4896
+ _ts_param19(1, Inject19(AGENT_DEPS_FACTORY6)),
4672
4897
  _ts_param19(2, Inject19(AGENT_REGISTRY3)),
4673
4898
  _ts_metadata20("design:type", Function),
4674
4899
  _ts_metadata20("design:paramtypes", [
@@ -4750,6 +4975,7 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
4750
4975
  }
4751
4976
  this.collectContributors(instance);
4752
4977
  }
4978
+ this.assertPersonas(this.registry.list());
4753
4979
  }
4754
4980
  /** Build the internal {@link AgentDefinition} from an `@Agent` instance and its options. */
4755
4981
  definitionFrom(instance, meta) {
@@ -4793,10 +5019,48 @@ var AgentDiscoveryService = class _AgentDiscoveryService {
4793
5019
  } : {},
4794
5020
  ...meta.handoff !== void 0 ? {
4795
5021
  delegatesTo: this.handoffEdges(meta)
5022
+ } : {},
5023
+ ...meta.personas !== void 0 ? {
5024
+ personas: meta.personas
5025
+ } : {},
5026
+ ...meta.defaultPersona !== void 0 ? {
5027
+ defaultPersona: meta.defaultPersona
4796
5028
  } : {}
4797
5029
  };
4798
5030
  }
4799
5031
  /**
5032
+ * Refuse to boot on a persona declaration that could only fail later, per request: a default that
5033
+ * names no persona, an id declared twice, an alias two personas claim, or an alias that is a real
5034
+ * agent's name (which would never be reached — a registered agent always wins).
5035
+ */
5036
+ assertPersonas(definitions) {
5037
+ const agentNames = new Set(definitions.map((definition) => definition.name));
5038
+ const aliasOwner = /* @__PURE__ */ new Map();
5039
+ for (const definition of definitions) {
5040
+ const ids = /* @__PURE__ */ new Set();
5041
+ for (const persona of definition.personas ?? []) {
5042
+ if (ids.has(persona.id)) {
5043
+ throw new Error(`Agent "${definition.name}" declares persona "${persona.id}" twice.`);
5044
+ }
5045
+ ids.add(persona.id);
5046
+ for (const alias of persona.aliases ?? []) {
5047
+ const owner = `${definition.name}/${persona.id}`;
5048
+ if (agentNames.has(alias)) {
5049
+ throw new Error(`Persona ${owner} claims the alias "${alias}", which is a registered agent's name.`);
5050
+ }
5051
+ const previous = aliasOwner.get(alias);
5052
+ if (previous !== void 0) {
5053
+ throw new Error(`Personas ${previous} and ${owner} both claim the alias "${alias}".`);
5054
+ }
5055
+ aliasOwner.set(alias, owner);
5056
+ }
5057
+ }
5058
+ if (definition.defaultPersona !== void 0 && !ids.has(definition.defaultPersona)) {
5059
+ throw new Error(`Agent "${definition.name}" names "${definition.defaultPersona}" as its default persona, but declares no persona with that id.`);
5060
+ }
5061
+ }
5062
+ }
5063
+ /**
4800
5064
  * Resolve each handoff entry to an {@link AgentDelegation} — its target's registered name, plus
4801
5065
  * whether that edge detaches (skipping non-agent classes). A bare name is kept for a plain edge
4802
5066
  * rather than an always-object form, so a definition an older host built by hand still reads.
@@ -5228,7 +5492,7 @@ var LedgerQuotaProvider = class {
5228
5492
  };
5229
5493
 
5230
5494
  // src/runner/inline-agent-runner.ts
5231
- import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY6, AGENT_STORE as AGENT_STORE6, RUN_ENDED_BEFORE_TOOL_CALL as RUN_ENDED_BEFORE_TOOL_CALL2, RunCancelledError as RunCancelledError2, agentFailureCode as agentFailureCode2, encodeStreamEvent as encodeStreamEvent5, publishAgentRunFailed as publishAgentRunFailed2, releaseThreadRun as releaseThreadRun3, runAgentLoop as runAgentLoop2, settleAll as settleAll2, settleUnsettledDelegation as settleUnsettledDelegation3, streamFailure as streamFailure3 } from "@dudousxd/nestjs-agent-core";
5495
+ import { AGENT_DEPS_FACTORY as AGENT_DEPS_FACTORY7, AGENT_STORE as AGENT_STORE6, RUN_ENDED_BEFORE_TOOL_CALL as RUN_ENDED_BEFORE_TOOL_CALL2, RunCancelledError as RunCancelledError2, agentFailureCode as agentFailureCode2, encodeStreamEvent as encodeStreamEvent5, publishAgentRunFailed as publishAgentRunFailed2, releaseThreadRun as releaseThreadRun3, runAgentLoop as runAgentLoop2, settleAll as settleAll2, settleUnsettledDelegation as settleUnsettledDelegation3, streamFailure as streamFailure3 } from "@dudousxd/nestjs-agent-core";
5232
5496
  import { Inject as Inject23, Injectable as Injectable11, Logger as Logger7, Optional as Optional10 } from "@nestjs/common";
5233
5497
  function _ts_decorate25(decorators, target, key, desc) {
5234
5498
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -5708,7 +5972,7 @@ var InlineAgentRunner = class _InlineAgentRunner {
5708
5972
  };
5709
5973
  InlineAgentRunner = _ts_decorate25([
5710
5974
  Injectable11(),
5711
- _ts_param23(0, Inject23(AGENT_DEPS_FACTORY6)),
5975
+ _ts_param23(0, Inject23(AGENT_DEPS_FACTORY7)),
5712
5976
  _ts_param23(1, Inject23(AGENT_STORE6)),
5713
5977
  _ts_param23(2, Optional10()),
5714
5978
  _ts_metadata24("design:type", Function),
@@ -5920,7 +6184,7 @@ function sharedProviders(durable) {
5920
6184
  },
5921
6185
  AgentDepsFactory2,
5922
6186
  {
5923
- provide: AGENT_DEPS_FACTORY7,
6187
+ provide: AGENT_DEPS_FACTORY8,
5924
6188
  useExisting: AgentDepsFactory2
5925
6189
  },
5926
6190
  // Populates the registry + contributors (onModuleInit) BEFORE AiToolDiscoveryService synthesizes
@@ -5993,7 +6257,7 @@ function exportsFor() {
5993
6257
  AGENT_PROMPT_CONTRIBUTORS3,
5994
6258
  AGENT_SKILLS3,
5995
6259
  AGENT_MEMORY3,
5996
- AGENT_DEPS_FACTORY7,
6260
+ AGENT_DEPS_FACTORY8,
5997
6261
  AgentDepsFactory2,
5998
6262
  AgentService,
5999
6263
  ChatQueueService2,