briyah 1.2.4 → 1.2.5

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.
Files changed (118) hide show
  1. package/README.md +55 -6
  2. package/data/common/config/image_models.json +160 -97
  3. package/data/common/config/markup +1 -1
  4. package/data/common/config/story_models.json +15 -3
  5. package/data/common/config/story_models_full.json +2 -2
  6. package/data/common/prompts/character/create_user_character.prompt +3 -12
  7. package/data/common/prompts/character/introduce_character.json +18 -0
  8. package/data/common/prompts/character/introduce_character.mock +4 -0
  9. package/data/common/prompts/character/introduce_character.prompt +58 -0
  10. package/data/common/prompts/character/perceive.prompt +3 -0
  11. package/data/common/prompts/character/progress_character.json +8 -4
  12. package/data/common/prompts/character/progress_character.mock +1 -0
  13. package/data/common/prompts/character/progress_character.prompt +20 -2
  14. package/data/common/prompts/character/update_portrait.json +18 -0
  15. package/data/common/prompts/character/update_portrait.mock +4 -0
  16. package/data/common/prompts/character/update_portrait.prompt +17 -1
  17. package/data/common/prompts/narrator/create_simple_plot.json +0 -0
  18. package/data/common/prompts/narrator/create_simple_plot.mock +13 -0
  19. package/data/common/prompts/narrator/create_simple_plot.prompt +35 -0
  20. package/data/common/prompts/narrator/perceive.prompt +12 -9
  21. package/data/common/prompts/narrator/progress_simple_plot.json +0 -0
  22. package/data/common/prompts/narrator/progress_simple_plot.mock +13 -0
  23. package/data/common/prompts/narrator/progress_simple_plot.prompt +40 -0
  24. package/data/common/prompts/perceive.json +1 -1
  25. package/data/common/prompts/perceive.prompt +82 -20
  26. package/data/common/prompts/story_moderator/moderate.json +1 -1
  27. package/data/common/prompts/story_moderator/moderate.prompt +26 -6
  28. package/dist-sdk/server/src/ai/LLM/anthropic.service.js +1 -2
  29. package/dist-sdk/server/src/ai/LLM/base-ai.service.d.ts +1 -1
  30. package/dist-sdk/server/src/ai/LLM/base-ai.service.js +13 -42
  31. package/dist-sdk/server/src/ai/LLM/deepseek.service.js +9 -0
  32. package/dist-sdk/server/src/ai/LLM/fal.service.js +1 -2
  33. package/dist-sdk/server/src/ai/LLM/googleai.service.js +1 -2
  34. package/dist-sdk/server/src/ai/LLM/grok.service.js +1 -2
  35. package/dist-sdk/server/src/ai/LLM/openai.service.js +1 -2
  36. package/dist-sdk/server/src/ai/LLM/together.service.js +1 -2
  37. package/dist-sdk/server/src/ai/agent-config.d.ts +2 -0
  38. package/dist-sdk/server/src/ai/agent-store.service.js +8 -0
  39. package/dist-sdk/server/src/ai/agent.d.ts +2 -0
  40. package/dist-sdk/server/src/ai/agent.js +2 -0
  41. package/dist-sdk/server/src/ai/model_prices.js +2 -1
  42. package/dist-sdk/server/src/app/user-service-factory.js +7 -3
  43. package/dist-sdk/server/src/app.controller.d.ts +15 -4
  44. package/dist-sdk/server/src/app.controller.js +171 -5
  45. package/dist-sdk/server/src/app.service.d.ts +19 -5
  46. package/dist-sdk/server/src/app.service.js +50 -4
  47. package/dist-sdk/server/src/room/message.js +5 -1
  48. package/dist-sdk/server/src/room/room-factory.d.ts +5 -1
  49. package/dist-sdk/server/src/room/room-factory.js +6 -1
  50. package/dist-sdk/server/src/room/room-store.service.d.ts +5 -1
  51. package/dist-sdk/server/src/room/room-store.service.js +13 -2
  52. package/dist-sdk/server/src/room/room.d.ts +25 -4
  53. package/dist-sdk/server/src/room/room.js +379 -95
  54. package/dist-sdk/server/src/sdk/index.d.ts +1 -1
  55. package/dist-sdk/server/src/story/story.service.d.ts +5 -4
  56. package/dist-sdk/server/src/story/story.service.js +207 -120
  57. package/dist-sdk/server/src/tools/tool-execution.service.d.ts +19 -0
  58. package/dist-sdk/server/src/tools/tool-execution.service.js +100 -0
  59. package/dist-sdk/server/src/tools/tool-store.service.d.ts +17 -0
  60. package/dist-sdk/server/src/tools/tool-store.service.js +143 -0
  61. package/dist-sdk/shared/types/app.types.d.ts +44 -5
  62. package/dist-sdk/shared/types/app.types.js +3 -0
  63. package/docs/assets/hierarchy.js +1 -1
  64. package/docs/assets/highlight.css +0 -7
  65. package/docs/assets/navigation.js +1 -1
  66. package/docs/assets/search.js +1 -1
  67. package/docs/classes/Agent.html +22 -14
  68. package/docs/classes/Briyah.html +10 -10
  69. package/docs/classes/BriyahConfigService.html +5 -5
  70. package/docs/classes/Room.html +32 -26
  71. package/docs/classes/RoomMessage.html +10 -10
  72. package/docs/enums/MessageAction.html +6 -3
  73. package/docs/hierarchy.html +1 -1
  74. package/docs/index.html +12 -5
  75. package/docs/interfaces/AgentInfo.html +3 -2
  76. package/docs/interfaces/AgentMessagesResponse.html +2 -2
  77. package/docs/interfaces/AppService.html +184 -149
  78. package/docs/interfaces/Artifact.html +3 -3
  79. package/docs/interfaces/ArtifactMetadata.html +2 -2
  80. package/docs/interfaces/AttachDocumentResponse.html +2 -2
  81. package/docs/interfaces/BriyahConfigOptions.html +7 -7
  82. package/docs/interfaces/ChapterInfo.html +2 -2
  83. package/docs/interfaces/Character.html +2 -2
  84. package/docs/interfaces/CreateAgentResponse.html +2 -2
  85. package/docs/interfaces/CreateRoomResponse.html +2 -2
  86. package/docs/interfaces/CreateStoryResponse.html +2 -2
  87. package/docs/interfaces/FileList.html +2 -2
  88. package/docs/interfaces/FileMetadata.html +3 -3
  89. package/docs/interfaces/IConfigService.html +3 -3
  90. package/docs/interfaces/LoggingOptions.html +6 -6
  91. package/docs/interfaces/Message.html +2 -2
  92. package/docs/interfaces/ModelInfo.html +2 -3
  93. package/docs/interfaces/PreparedPromptResponse.html +2 -2
  94. package/docs/interfaces/ProcessTextResponse.html +2 -2
  95. package/docs/interfaces/PromptFile.html +2 -2
  96. package/docs/interfaces/PromptFileContent.html +2 -2
  97. package/docs/interfaces/PromptFilesResponse.html +2 -2
  98. package/docs/interfaces/PromptFolder.html +2 -2
  99. package/docs/interfaces/PromptFoldersResponse.html +2 -2
  100. package/docs/interfaces/RoomDetails.html +2 -2
  101. package/docs/interfaces/RoomInfo.html +2 -2
  102. package/docs/interfaces/RoomMessagesResponse.html +2 -2
  103. package/docs/interfaces/StoryErrorEvent.html +3 -3
  104. package/docs/interfaces/StoryIdea.html +2 -2
  105. package/docs/interfaces/StoryInfo.html +5 -4
  106. package/docs/interfaces/StoryIntroduceCharacterEvent.html +3 -3
  107. package/docs/interfaces/StoryProgressChapterEvent.html +3 -3
  108. package/docs/interfaces/StoryState.html +5 -5
  109. package/docs/interfaces/StoryStateEvent.html +3 -3
  110. package/docs/interfaces/ToolDefinition.html +6 -0
  111. package/docs/interfaces/ToolParameter.html +5 -0
  112. package/docs/interfaces/ToolsResponse.html +2 -0
  113. package/docs/interfaces/Transaction.html +2 -2
  114. package/docs/interfaces/TransactionHistoryResponse.html +2 -2
  115. package/docs/modules.html +1 -1
  116. package/docs/types/PromptScope.html +1 -1
  117. package/docs/types/ToolRunResult.html +1 -0
  118. package/package.json +2 -1
@@ -5,9 +5,9 @@ const app_types_1 = require("../../../shared/types/app.types");
5
5
  const message_1 = require("./message");
6
6
  const crypto_1 = require("crypto");
7
7
  const errors_1 = require("../common/errors");
8
- const child_process_1 = require("child_process");
9
8
  const logger_1 = require("../common/logger");
10
9
  class Room {
10
+ static MAX_TOOL_ITERATIONS = 5;
11
11
  id;
12
12
  name;
13
13
  goal;
@@ -28,11 +28,14 @@ class Room {
28
28
  onStateChangeCallbacks = new Map();
29
29
  onError;
30
30
  currentSituation = '';
31
+ currentSituationTime = '';
31
32
  onSituationUpdate;
32
33
  onModeratorResponseCallback;
33
34
  templateRoomId;
34
35
  storageDir;
35
36
  roomStoreService;
37
+ toolStoreService;
38
+ toolExecutionService;
36
39
  constructor(id, name, goal, baseRoomDir = '', storageDir = '', roomStoreService = null) {
37
40
  this.name = name;
38
41
  this.goal = goal;
@@ -147,7 +150,7 @@ class Room {
147
150
  getLatestRoomMessages(fromIndex = 0, includeThoughts = false) {
148
151
  const messages = this.roomMessages.filter((msg) => msg.index >= fromIndex);
149
152
  if (!includeThoughts) {
150
- return messages.filter((msg) => msg.action !== app_types_1.MessageAction.THINK);
153
+ return messages.filter((msg) => msg.action !== app_types_1.MessageAction.THINK && msg.action !== app_types_1.MessageAction.TOOL);
151
154
  }
152
155
  return messages;
153
156
  }
@@ -158,12 +161,12 @@ class Room {
158
161
  });
159
162
  this.nextMessageIndex = this.roomMessages.length;
160
163
  }
161
- addRoomMessage(message) {
164
+ addRoomMessage(message, options) {
162
165
  message.index = this.nextMessageIndex++;
163
166
  this.roomMessages.push(message);
164
167
  this.saveMessages([message]);
165
- if (message.situation) {
166
- this.handleSituationUpdate(message.situation);
168
+ if (message.situation && !options?.suppressSituationUpdate) {
169
+ void this.handleSituationUpdate(message.situation);
167
170
  }
168
171
  this.notifyStateChange();
169
172
  }
@@ -233,6 +236,12 @@ class Room {
233
236
  }
234
237
  }
235
238
  }
239
+ if (normalizedAction === app_types_1.MessageAction.EXECUTE && (!response.name || !response.name.trim())) {
240
+ needsModeration = true;
241
+ }
242
+ if (normalizedAction === app_types_1.MessageAction.COMMISSION && targets.length === 0) {
243
+ needsModeration = true;
244
+ }
236
245
  }
237
246
  if (needsModeration) {
238
247
  return new message_1.RoomMessage(agent.agentNickname, app_types_1.MessageAction.MODERATE, content, [], null, situation);
@@ -284,45 +293,162 @@ class Room {
284
293
  const values = Object.values(app_types_1.MessageAction);
285
294
  return values.includes(lowered) ? lowered : undefined;
286
295
  }
287
- async getAgentAiResponse(agent, onResponse) {
288
- let answer = null;
289
- try {
290
- const visibleArtifacts = this.getVisibleArtifacts(agent.agentNickname)
291
- .map((a) => `${a.name} (by ${a.creator}): ${a.body}`)
292
- .join('\n\n');
293
- const allArtifacts = this.getArtifacts();
294
- const invisibleArtifactNames = allArtifacts
295
- .filter((a) => !this.getVisibleArtifacts(agent.agentNickname).includes(a))
296
- .map((a) => a.name)
297
- .join(', ');
298
- const humanAgent = this.getAgents().find((a) => a.isControlledByHuman);
299
- const humanCharacterName = humanAgent ? humanAgent.agentNickname : 'Player';
300
- const maxOutputChars = 4096;
301
- const variables = {
302
- agentName: agent.agentName,
303
- agentNickname: agent.agentNickname,
304
- agentDescription: agent.description,
305
- otherAgents: this.agents.filter((a) => a.agentNickname !== agent.agentNickname),
306
- roomLeader: this.getRoomLeader(),
307
- roomGoal: this.getGoal(),
308
- scenario: this.getGoal(),
309
- situation: this.getSituation() || 'Story beginning',
310
- visibleArtifacts: visibleArtifacts,
311
- invisibleArtifactNames: invisibleArtifactNames,
312
- humanCharacterName: humanCharacterName,
313
- humanAgentName: humanCharacterName,
314
- maxOutputChars: maxOutputChars
315
- };
316
- let prompt = null;
317
- let situation = this.getSituation();
318
- if (situation)
319
- prompt = `Current Situation: ${situation}`;
320
- let response = await agent.instructedPrompt(prompt, 'perceive', variables, false, true, maxOutputChars);
321
- answer = this.parseAgentResponse(agent, response);
322
- agent.addToConversationHistory(response, true);
296
+ getPresentCharacters(perceivingAgent, message) {
297
+ const audienceNames = message.getTargets();
298
+ const senderName = message.getSender();
299
+ return this.agents.filter((a) => {
300
+ if (a.promptFolder !== 'character')
301
+ return false;
302
+ if (a.agentNickname === perceivingAgent.agentNickname)
303
+ return false;
304
+ if (this.checkAgentNicknameMatch(a.agentNickname, senderName))
305
+ return true;
306
+ if (audienceNames.some((name) => this.checkAgentNicknameMatch(a.agentNickname, name)))
307
+ return true;
308
+ if (audienceNames.length === 0 && message.canHear(a.agentNickname))
309
+ return true;
310
+ return false;
311
+ });
312
+ }
313
+ buildCharacterPrivateContextDigest() {
314
+ return this.agents
315
+ .filter((a) => a.promptFolder === 'character' && a.privateContext && a.privateContext.trim())
316
+ .map((a) => `### ${a.agentNickname}\n${a.privateContext}`)
317
+ .join('\n\n');
318
+ }
319
+ async buildAvailableTools(agent) {
320
+ if (!this.toolStoreService || !agent.toolNames || agent.toolNames.length === 0) {
321
+ return [];
322
+ }
323
+ const tools = [];
324
+ for (const name of agent.toolNames) {
325
+ const tool = await this.toolStoreService.getTool(name);
326
+ if (tool) {
327
+ tools.push({
328
+ name: tool.name,
329
+ description: tool.description,
330
+ parameters: tool.parameters || [],
331
+ });
332
+ }
333
+ }
334
+ return tools;
335
+ }
336
+ async buildPerceiveVariables(agent) {
337
+ const visibleArtifacts = this.getVisibleArtifacts(agent.agentNickname)
338
+ .map((a) => `${a.name} (by ${a.creator}): ${a.body}`)
339
+ .join('\n\n');
340
+ const allArtifacts = this.getArtifacts();
341
+ const invisibleArtifactNames = allArtifacts
342
+ .filter((a) => !this.getVisibleArtifacts(agent.agentNickname).includes(a))
343
+ .map((a) => a.name)
344
+ .join(', ');
345
+ const humanAgent = this.getAgents().find((a) => a.isControlledByHuman);
346
+ const humanCharacterName = humanAgent ? humanAgent.agentNickname : 'Player';
347
+ const maxOutputChars = 4096;
348
+ return {
349
+ agentName: agent.agentName,
350
+ agentNickname: agent.agentNickname,
351
+ agentDescription: agent.description,
352
+ otherAgents: this.agents.filter((a) => a.agentNickname !== agent.agentNickname),
353
+ roomLeader: this.getRoomLeader(),
354
+ roomGoal: this.getGoal(),
355
+ scenario: this.getGoal(),
356
+ situation: this.getSituation() || 'Story beginning',
357
+ visibleArtifacts: visibleArtifacts,
358
+ invisibleArtifactNames: invisibleArtifactNames,
359
+ humanCharacterName: humanCharacterName,
360
+ humanAgentName: humanCharacterName,
361
+ maxOutputChars: maxOutputChars,
362
+ availableTools: await this.buildAvailableTools(agent),
363
+ };
364
+ }
365
+ buildTransientPrompt(agent, message) {
366
+ let prompt = this.buildSituationHeader() || null;
367
+ if (message) {
368
+ const presentCharacters = this.getPresentCharacters(agent, message);
369
+ if (presentCharacters.length > 0) {
370
+ const descriptions = presentCharacters
371
+ .map((c) => `- ${c.agentNickname}: ${c.description}`)
372
+ .join('\n');
373
+ const charactersPresent = `Characters present (how they currently appear to you):\n${descriptions}`;
374
+ prompt = prompt ? `${prompt}\n\n${charactersPresent}` : charactersPresent;
375
+ }
376
+ }
377
+ if (agent.privateContext && agent.privateContext.trim()) {
378
+ const privateBlock = `Your private context (known only to you):\n${agent.privateContext}`;
379
+ prompt = prompt ? `${prompt}\n\n${privateBlock}` : privateBlock;
380
+ }
381
+ if (agent.agentNickname === this.getRoomLeader()) {
382
+ const digest = this.buildCharacterPrivateContextDigest();
383
+ if (digest) {
384
+ const digestBlock = `Character Inventories and Conditions:\n${digest}`;
385
+ prompt = prompt ? `${prompt}\n\n${digestBlock}` : digestBlock;
386
+ }
387
+ }
388
+ return prompt;
389
+ }
390
+ async promptAgentOnce(agent, transientPrompt, variables) {
391
+ const response = await agent.instructedPrompt(transientPrompt, 'perceive', variables, false, true, variables.maxOutputChars);
392
+ const answer = this.parseAgentResponse(agent, response);
393
+ agent.addToConversationHistory(response, true);
394
+ agent.save();
395
+ return answer;
396
+ }
397
+ async runAgentTurn(agent, heardMessage, opts = {}) {
398
+ const variables = await this.buildPerceiveVariables(agent);
399
+ let response = await this.promptAgentOnce(agent, this.buildTransientPrompt(agent, heardMessage), variables);
400
+ for (let i = 0; i < Room.MAX_TOOL_ITERATIONS; i++) {
401
+ if (this.isPaused || this.isAdjourned)
402
+ return null;
403
+ let feedback;
404
+ if (response.action === app_types_1.MessageAction.PUBLISH && response.name) {
405
+ this.publishArtifact(response.name, agent.agentNickname, response.content, response.targets);
406
+ const wasDeleted = !response.content || !response.content.trim();
407
+ feedback = `From system: Artifact "${response.name}" was ${wasDeleted ? 'deleted' : 'published'}.`;
408
+ }
409
+ else if (response.action === app_types_1.MessageAction.EXECUTE) {
410
+ feedback = await this.executeToolForAgent(agent, response);
411
+ }
412
+ else if (opts.inCommission && response.action === app_types_1.MessageAction.COMMISSION) {
413
+ feedback = `From system: Nested commissions are not permitted. Complete your own task and respond with action "deliver".`;
414
+ }
415
+ else {
416
+ if (!opts.inCommission && response.action === app_types_1.MessageAction.DELIVER) {
417
+ response.action = app_types_1.MessageAction.SPEAK;
418
+ }
419
+ return response;
420
+ }
421
+ agent.addToConversationHistory(feedback, false);
323
422
  agent.save();
423
+ response = await this.promptAgentOnce(agent, this.buildTransientPrompt(agent, null), variables);
324
424
  }
325
- catch (e) {
425
+ if (this.isPaused || this.isAdjourned)
426
+ return null;
427
+ agent.addToConversationHistory(`From system: You have reached the tool-call limit for this turn. Respond now with an audible action (speak, whisper, think, ...).`, false);
428
+ agent.save();
429
+ response = await this.promptAgentOnce(agent, this.buildTransientPrompt(agent, null), variables);
430
+ if (response.action === app_types_1.MessageAction.EXECUTE ||
431
+ response.action === app_types_1.MessageAction.PUBLISH) {
432
+ response = new message_1.RoomMessage(agent.agentNickname, app_types_1.MessageAction.THINK, response.content, []);
433
+ }
434
+ return response;
435
+ }
436
+ async executeToolForAgent(agent, message) {
437
+ const toolName = message.name;
438
+ const result = this.toolExecutionService
439
+ ? await this.toolExecutionService.runForAgent(toolName, message.content, agent.toolNames || [])
440
+ : { ok: false, error: 'Tool execution is not available in this room' };
441
+ const argsPreview = message.content && message.content.length > 200
442
+ ? `${message.content.slice(0, 200)}...`
443
+ : message.content || '';
444
+ const statusText = 'error' in result ? `error: ${result.error}` : 'ok';
445
+ this.addRoomMessage(new message_1.RoomMessage(agent.agentNickname, app_types_1.MessageAction.TOOL, `${toolName}(${argsPreview}) → ${statusText}`));
446
+ return `From system: Result of tool "${toolName}":\n${JSON.stringify(result)}`;
447
+ }
448
+ getAgentAiResponse(agent, message, onResponse) {
449
+ this.runAgentTurn(agent, message)
450
+ .then((answer) => onResponse(answer))
451
+ .catch((e) => {
326
452
  if (e instanceof errors_1.InsufficientBalanceError) {
327
453
  this.handleInsufficientBalance(e);
328
454
  }
@@ -330,8 +456,8 @@ class Room {
330
456
  let internalizedError = `${agent.agentNickname} thinks: No one heard me because ${e.message}`;
331
457
  agent.addToConversationHistory(internalizedError, true);
332
458
  }
333
- }
334
- onResponse(answer);
459
+ onResponse(null);
460
+ });
335
461
  }
336
462
  perceive(agent, message, onResponse) {
337
463
  if (!message.canHear(agent.agentNickname)) {
@@ -347,7 +473,7 @@ class Room {
347
473
  if (agent.isControlledByHuman) {
348
474
  return;
349
475
  }
350
- this.getAgentAiResponse(agent, onResponse);
476
+ this.getAgentAiResponse(agent, message, onResponse);
351
477
  }
352
478
  async moderate(moderatorAgent, message, onResponse) {
353
479
  const humanAgent = this.getAgents().find((agent) => agent.isControlledByHuman);
@@ -374,10 +500,14 @@ class Room {
374
500
  invisibleArtifactNames: invisibleArtifactNames,
375
501
  };
376
502
  let prompt = `
377
- Current Situation: ${this.getSituation()}
503
+ ${this.buildSituationHeader()}
378
504
  Sender: ${message.getSender()}
379
505
  Recent Message: ${message.getContent()}
380
506
  `;
507
+ const characterContexts = this.buildCharacterPrivateContextDigest();
508
+ if (characterContexts) {
509
+ prompt += `\nCharacter Inventories and Conditions:\n${characterContexts}\n`;
510
+ }
381
511
  try {
382
512
  let response = await moderatorAgent.instructedPrompt(prompt, 'moderate', variables, false, true);
383
513
  let answer = this.parseAgentResponse(moderatorAgent, response);
@@ -471,6 +601,10 @@ Recent Message: ${message.getContent()}
471
601
  setRoomStoreService(service) {
472
602
  this.roomStoreService = service;
473
603
  }
604
+ setToolServices(toolStore, toolExecution) {
605
+ this.toolStoreService = toolStore;
606
+ this.toolExecutionService = toolExecution;
607
+ }
474
608
  saveMessages(messages) {
475
609
  if (!this.roomStoreService || !this.storageDir || !this.id) {
476
610
  return;
@@ -520,6 +654,22 @@ Recent Message: ${message.getContent()}
520
654
  getSituation() {
521
655
  return this.currentSituation;
522
656
  }
657
+ getSituationTime() {
658
+ return this.currentSituationTime;
659
+ }
660
+ setSituationTime(time) {
661
+ this.currentSituationTime = time || '';
662
+ }
663
+ buildSituationHeader() {
664
+ const lines = [];
665
+ if (this.currentSituationTime) {
666
+ lines.push(`Current time: ${this.currentSituationTime} (24-hour clock)`);
667
+ }
668
+ if (this.currentSituation) {
669
+ lines.push(`Current Situation: ${this.currentSituation}`);
670
+ }
671
+ return lines.join('\n');
672
+ }
523
673
  setSituation(situation) {
524
674
  this.currentSituation = situation;
525
675
  }
@@ -529,11 +679,11 @@ Recent Message: ${message.getContent()}
529
679
  setOnModeratorResponse(callback) {
530
680
  this.onModeratorResponseCallback = callback;
531
681
  }
532
- handleSituationUpdate(situation) {
682
+ async handleSituationUpdate(situation, messageBody) {
533
683
  logger_1.logger.log(`Situation updated: ${situation}`);
534
684
  this.currentSituation = situation;
535
685
  if (this.onSituationUpdate) {
536
- this.onSituationUpdate(situation);
686
+ await this.onSituationUpdate(situation, messageBody);
537
687
  }
538
688
  }
539
689
  handlePublishMessages(messages) {
@@ -547,37 +697,6 @@ Recent Message: ${message.getContent()}
547
697
  }
548
698
  }
549
699
  }
550
- handleExecuteMessages(messages) {
551
- for (const message of messages) {
552
- if (message.content && message.content.trim()) {
553
- const command = message.content.trim();
554
- const creator = message.sender;
555
- const description = message.name || 'Command execution';
556
- const resultViewers = message.targets;
557
- this.executeCommand(command, creator, description, resultViewers);
558
- }
559
- }
560
- }
561
- executeCommand(command, creator, description, resultViewers = []) {
562
- const workingDir = this.baseRoomDir || process.cwd();
563
- logger_1.logger.log(`FEATURE DISABLED -- Executing command: ${command} in directory: ${workingDir} by agent: ${creator}`);
564
- return;
565
- (0, child_process_1.exec)(command, { cwd: workingDir }, (error, stdout, stderr) => {
566
- let result = '';
567
- if (error) {
568
- result = `Error: ${error.message}\n${stderr}`;
569
- logger_1.logger.error(`Command execution error: ${error.message}`);
570
- }
571
- else if (stderr) {
572
- result = `${stdout}\n\nStderr: ${stderr}`;
573
- }
574
- else {
575
- result = stdout;
576
- }
577
- const artifactBody = `Command: ${command}\nWorking Directory: ${workingDir}\n\n${result}`;
578
- this.publishArtifact(description, creator, artifactBody, resultViewers);
579
- });
580
- }
581
700
  handleAdjournMessages(messages) {
582
701
  if (messages.length === 0) {
583
702
  return;
@@ -693,7 +812,7 @@ Recent Message: ${message.getContent()}
693
812
  }
694
813
  logger_1.logger.log(`Moderator routing: sender=${originalMessage.sender} action=${moderatorMessage.action}, name=${responderNickname}, targets=${targets.join(', ')}`);
695
814
  if (moderatorMessage.action === app_types_1.MessageAction.RELAY) {
696
- this.addRoomMessage(new message_1.RoomMessage(originalMessage.sender, originalMessage.action, content, originalMessage.targets, originalMessage.name, originalMessage.situation));
815
+ this.addRoomMessage(new message_1.RoomMessage(originalMessage.sender, originalMessage.action, content, originalMessage.targets, originalMessage.name, originalMessage.situation), { suppressSituationUpdate: true });
697
816
  }
698
817
  for (const recipientName of targets) {
699
818
  if (recipientName === responderNickname)
@@ -724,6 +843,7 @@ Recent Message: ${message.getContent()}
724
843
  return;
725
844
  }
726
845
  this.setCurrentSpeaker(responderNickname);
846
+ originalMessage.targets = targets;
727
847
  this.perceive(responderAgent, originalMessage, (response) => {
728
848
  if (this.isPaused) {
729
849
  this.processingInProgress = false;
@@ -751,6 +871,149 @@ Recent Message: ${message.getContent()}
751
871
  }
752
872
  }
753
873
  }
874
+ async runDeliverTurn(agent, commission) {
875
+ try {
876
+ let response = await this.runAgentTurn(agent, commission, { inCommission: true });
877
+ if (response === null)
878
+ return null;
879
+ if (response.action !== app_types_1.MessageAction.DELIVER) {
880
+ agent.addToConversationHistory(`From system: You were commissioned by ${commission.sender}. Respond now with action "deliver" targeting ${commission.sender}, containing your complete result.`, false);
881
+ agent.save();
882
+ const variables = await this.buildPerceiveVariables(agent);
883
+ response = await this.promptAgentOnce(agent, this.buildTransientPrompt(agent, null), variables);
884
+ }
885
+ if (response.action !== app_types_1.MessageAction.DELIVER) {
886
+ return new message_1.RoomMessage(agent.agentNickname, app_types_1.MessageAction.DELIVER, response.content, [commission.sender]);
887
+ }
888
+ response.sender = agent.agentNickname;
889
+ response.targets = [commission.sender];
890
+ return response;
891
+ }
892
+ catch (e) {
893
+ if (e instanceof errors_1.InsufficientBalanceError) {
894
+ this.handleInsufficientBalance(e);
895
+ return null;
896
+ }
897
+ logger_1.logger.error(`Commissioned agent ${agent.agentNickname} failed:`, e);
898
+ return new message_1.RoomMessage(agent.agentNickname, app_types_1.MessageAction.DELIVER, `(No deliverable: ${agent.agentNickname} encountered an error: ${e.message})`, [commission.sender]);
899
+ }
900
+ }
901
+ async handleCommissionMessage(msg) {
902
+ try {
903
+ const aiTargets = [];
904
+ const humanTargetNames = [];
905
+ const unknownNames = [];
906
+ for (const name of [...new Set(msg.getTargets())]) {
907
+ const agent = this.agents.find((a) => this.checkAgentNicknameMatch(a.agentNickname, name));
908
+ if (!agent) {
909
+ unknownNames.push(name);
910
+ }
911
+ else if (agent.agentNickname === msg.sender) {
912
+ }
913
+ else if (agent.isControlledByHuman) {
914
+ humanTargetNames.push(agent.agentNickname);
915
+ }
916
+ else if (!aiTargets.includes(agent)) {
917
+ aiTargets.push(agent);
918
+ }
919
+ }
920
+ for (const agent of this.agents) {
921
+ if (agent.agentNickname === msg.sender)
922
+ continue;
923
+ agent.addToConversationHistory(msg, false);
924
+ agent.save();
925
+ }
926
+ const commissioner = this.agents.find((a) => this.checkAgentNicknameMatch(a.agentNickname, msg.sender));
927
+ if (aiTargets.length === 0) {
928
+ const reasons = [];
929
+ if (unknownNames.length > 0)
930
+ reasons.push(`unknown agents: ${unknownNames.join(', ')}`);
931
+ if (humanTargetNames.length > 0)
932
+ reasons.push(`human-controlled agents cannot be commissioned: ${humanTargetNames.join(', ')}`);
933
+ const note = `From system: Your commission could not be delivered (${reasons.join('; ') || 'no valid targets'}).`;
934
+ await this.respondToCommissioner(commissioner, note);
935
+ return;
936
+ }
937
+ const settled = await Promise.allSettled(aiTargets.map((t) => this.runDeliverTurn(t, msg)));
938
+ if (this.isPaused || this.isAdjourned || !this.processingInProgress) {
939
+ if (this.processingInProgress) {
940
+ this.processingInProgress = false;
941
+ this.notifyStateChange();
942
+ }
943
+ return;
944
+ }
945
+ const delivers = settled.map((result, i) => {
946
+ if (result.status === 'fulfilled' && result.value)
947
+ return result.value;
948
+ return new message_1.RoomMessage(aiTargets[i].agentNickname, app_types_1.MessageAction.DELIVER, `(No deliverable: ${aiTargets[i].agentNickname} did not complete the commission)`, [msg.sender]);
949
+ });
950
+ for (const deliver of delivers) {
951
+ this.addRoomMessage(deliver);
952
+ for (const agent of this.agents) {
953
+ if (agent.agentNickname === deliver.sender)
954
+ continue;
955
+ if (this.checkAgentNicknameMatch(agent.agentNickname, msg.sender))
956
+ continue;
957
+ agent.addToConversationHistory(deliver, false);
958
+ agent.save();
959
+ }
960
+ }
961
+ const sections = delivers.map((d) => `## From ${d.sender}\n${d.content}`);
962
+ if (humanTargetNames.length > 0) {
963
+ sections.push(`(Skipped: ${humanTargetNames.join(', ')} — human-controlled agents cannot be commissioned)`);
964
+ }
965
+ if (unknownNames.length > 0) {
966
+ sections.push(`(Unknown agents: ${unknownNames.join(', ')})`);
967
+ }
968
+ const aggregate = `From system: Deliverables for your commission:\n\n${sections.join('\n\n')}`;
969
+ await this.respondToCommissioner(commissioner, aggregate);
970
+ }
971
+ catch (error) {
972
+ logger_1.logger.error('Error handling commission message:', error);
973
+ this.processingInProgress = false;
974
+ this.notifyStateChange();
975
+ if (this.pendingMessages && this.pendingMessages.length > 0) {
976
+ this.processPendingMessages();
977
+ }
978
+ }
979
+ }
980
+ async respondToCommissioner(commissioner, note) {
981
+ if (!commissioner) {
982
+ logger_1.logger.warn('Commissioner not found in room; dropping commission results');
983
+ }
984
+ else {
985
+ commissioner.addToConversationHistory(note, false);
986
+ commissioner.save();
987
+ if (commissioner.isControlledByHuman) {
988
+ this.addRoomMessage(new message_1.RoomMessage('system', app_types_1.MessageAction.SYSTEM, note, [
989
+ commissioner.agentNickname,
990
+ ]));
991
+ this.processingInProgress = false;
992
+ this.notifyStateChange();
993
+ this.setCurrentSpeaker(commissioner.agentNickname);
994
+ return;
995
+ }
996
+ let reply = null;
997
+ try {
998
+ reply = await this.runAgentTurn(commissioner, null);
999
+ }
1000
+ catch (e) {
1001
+ if (e instanceof errors_1.InsufficientBalanceError) {
1002
+ this.handleInsufficientBalance(e);
1003
+ return;
1004
+ }
1005
+ throw e;
1006
+ }
1007
+ if (reply !== null && !this.isPaused && !this.isAdjourned) {
1008
+ this.pendingMessages = [...(this.pendingMessages || []), reply];
1009
+ }
1010
+ }
1011
+ this.processingInProgress = false;
1012
+ this.notifyStateChange();
1013
+ if (this.pendingMessages && this.pendingMessages.length > 0) {
1014
+ this.processPendingMessages();
1015
+ }
1016
+ }
754
1017
  processPendingMessages() {
755
1018
  if (this.isPaused ||
756
1019
  this.processingInProgress ||
@@ -763,7 +1026,10 @@ Recent Message: ${message.getContent()}
763
1026
  const messages = [...this.pendingMessages];
764
1027
  this.pendingMessages = [];
765
1028
  this.handlePublishMessages(messages.filter((m) => m.getAction() === app_types_1.MessageAction.PUBLISH));
766
- this.handleExecuteMessages(messages.filter((m) => m.getAction() === app_types_1.MessageAction.EXECUTE));
1029
+ const strayExecuteMessages = messages.filter((m) => m.getAction() === app_types_1.MessageAction.EXECUTE);
1030
+ if (strayExecuteMessages.length > 0) {
1031
+ logger_1.logger.warn(`Dropping ${strayExecuteMessages.length} queued EXECUTE message(s); tool calls are handled within the sender's turn`);
1032
+ }
767
1033
  this.handleAdjournMessages(messages.filter((m) => m.getAction() === app_types_1.MessageAction.ADJOURN));
768
1034
  if (this.isAdjourned) {
769
1035
  logger_1.logger.log(`Room ${this.name} has been adjourned. Message processing stopped.`);
@@ -789,21 +1055,34 @@ Recent Message: ${message.getContent()}
789
1055
  if (moderateMessages.length > 1) {
790
1056
  this.pendingMessages = [...moderateMessages.slice(1), ...this.pendingMessages];
791
1057
  }
792
- this.moderate(moderator, originalMessage, (response) => {
793
- if (this.isPaused) {
794
- this.processingInProgress = false;
795
- this.notifyStateChange();
796
- return;
797
- }
798
- if (response !== null) {
799
- this.handleModeratorResponse(response, originalMessage);
1058
+ const dispatchToModerator = async () => {
1059
+ if (originalMessage.situation) {
1060
+ await this.handleSituationUpdate(originalMessage.situation, originalMessage.getContent());
800
1061
  }
801
- else {
802
- this.processingInProgress = false;
803
- this.notifyStateChange();
804
- if (this.pendingMessages && this.pendingMessages.length > 0) {
805
- this.processPendingMessages();
1062
+ await this.moderate(moderator, originalMessage, (response) => {
1063
+ if (this.isPaused) {
1064
+ this.processingInProgress = false;
1065
+ this.notifyStateChange();
1066
+ return;
806
1067
  }
1068
+ if (response !== null) {
1069
+ this.handleModeratorResponse(response, originalMessage);
1070
+ }
1071
+ else {
1072
+ this.processingInProgress = false;
1073
+ this.notifyStateChange();
1074
+ if (this.pendingMessages && this.pendingMessages.length > 0) {
1075
+ this.processPendingMessages();
1076
+ }
1077
+ }
1078
+ });
1079
+ };
1080
+ dispatchToModerator().catch((error) => {
1081
+ logger_1.logger.error('Error dispatching message to moderator:', error);
1082
+ this.processingInProgress = false;
1083
+ this.notifyStateChange();
1084
+ if (this.pendingMessages && this.pendingMessages.length > 0) {
1085
+ this.processPendingMessages();
807
1086
  }
808
1087
  });
809
1088
  return;
@@ -825,6 +1104,10 @@ Recent Message: ${message.getContent()}
825
1104
  nextMessage = filteredMessage;
826
1105
  }
827
1106
  this.addRoomMessage(nextMessage);
1107
+ if (nextMessage.getAction() === app_types_1.MessageAction.COMMISSION) {
1108
+ void this.handleCommissionMessage(nextMessage);
1109
+ return;
1110
+ }
828
1111
  this.setCurrentSpeaker(nextMessage.targets[0]);
829
1112
  let agentsInProgress = this.agents.length;
830
1113
  if (agentsInProgress === 0) {
@@ -872,7 +1155,8 @@ Recent Message: ${message.getContent()}
872
1155
  filtered = shoutMessages;
873
1156
  }
874
1157
  if (filtered.length > 1) {
875
- const speakMessages = filtered.filter((m) => m.getAction() === app_types_1.MessageAction.SPEAK);
1158
+ const speakMessages = filtered.filter((m) => m.getAction() === app_types_1.MessageAction.SPEAK ||
1159
+ m.getAction() === app_types_1.MessageAction.COMMISSION);
876
1160
  const whisperMessages = filtered.filter((m) => m.getAction() === app_types_1.MessageAction.WHISPER);
877
1161
  if (speakMessages.length > 0) {
878
1162
  filtered = speakMessages;
@@ -1,7 +1,7 @@
1
1
  export { Briyah } from './briyah';
2
2
  export { BriyahConfigService, BriyahConfigOptions } from './briyah-config';
3
3
  export type { AppService } from '../app.service';
4
- export type { AgentInfo, CreateAgentResponse, RoomInfo, RoomDetails, CreateRoomResponse, StoryInfo, CreateStoryResponse, ProcessTextResponse, FileList, PromptFileContent, AttachDocumentResponse, AgentMessagesResponse, RoomMessagesResponse, StoryState, Message, MessageAction, ModelInfo, ArtifactMetadata, PreparedPromptResponse, PromptScope, PromptFolder, PromptFoldersResponse, PromptFile, PromptFilesResponse, StoryIdea, Transaction, TransactionHistoryResponse, StoryStateEvent, StoryIntroduceCharacterEvent, StoryProgressChapterEvent, StoryErrorEvent, Character, ChapterInfo, } from '../../../shared/types/app.types';
4
+ export type { AgentInfo, CreateAgentResponse, RoomInfo, RoomDetails, CreateRoomResponse, StoryInfo, CreateStoryResponse, ProcessTextResponse, FileList, PromptFileContent, AttachDocumentResponse, AgentMessagesResponse, RoomMessagesResponse, StoryState, Message, MessageAction, ModelInfo, ArtifactMetadata, PreparedPromptResponse, PromptScope, PromptFolder, PromptFoldersResponse, PromptFile, PromptFilesResponse, StoryIdea, Transaction, TransactionHistoryResponse, ToolDefinition, ToolParameter, ToolsResponse, ToolRunResult, StoryStateEvent, StoryIntroduceCharacterEvent, StoryProgressChapterEvent, StoryErrorEvent, Character, ChapterInfo, } from '../../../shared/types/app.types';
5
5
  export type { LoggingOptions } from './briyah-config';
6
6
  export { Agent } from '../ai/agent';
7
7
  export { Room } from '../room/room';