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
@@ -16,7 +16,14 @@ Refer to the conversation history above for recent events from your perspective.
16
16
  ## Updated Plot Plan (narrator's eyes only — do not reveal to others)
17
17
  {{plotPlan}}
18
18
 
19
- ## Your task
19
+ ## First, decide whether an update is even needed
20
+ Rewriting a full profile is expensive, so only do it when the recent story events genuinely affected {{agentName}}.
21
+
22
+ If {{agentName}} was **not** significantly affected by recent events — they were absent, on the periphery, or nothing happened that would meaningfully change their backstory, personality, motivations, relationships, knowledge, or possessions — then return `{"no_changes": true}` and **nothing else**. Do not rewrite the profile, do not write a new diary entry, and do not include any other fields. The existing profile will be kept unchanged.
23
+
24
+ Only if {{agentName}} **was** significantly affected should you proceed to rewrite the profile below. In that case, set `"no_changes": false` and include the updated fields.
25
+
26
+ ## Your task (only when no_changes is false)
20
27
  Your task is to create an updated, comprehensive character profile that reflects how {{agentName}} has grown, changed, or been affected by recent events in the story. This profile should capture the character's current state as the story moves forward.
21
28
 
22
29
  The character may have:
@@ -67,7 +74,17 @@ Create an updated character profile that includes:
67
74
  - Consider how relationships with other characters have evolved
68
75
 
69
76
  ## Response format
70
- Return a JSON object with these fields:
77
+ Return a JSON object.
78
+
79
+ **If {{agentName}} was not significantly affected**, return only:
80
+ ```json
81
+ {
82
+ "no_changes": true
83
+ }
84
+ ```
85
+
86
+ **Otherwise**, return these fields:
87
+ - `no_changes`: `false`
71
88
  - `description`: Updated observable description (optional — only include if appearance changed).
72
89
  - `character_profile`: The entire updated markdown-formatted character profile, ending with the diary entry section.
73
90
  - `inventory`: An updated concise inventory reflecting any items {{agentName}} gained, lost, consumed, or equipped during recent events, plus any new/resolved physical or mental conditions (wounded, healed, exhausted, etc.). Use `## Items` and (optionally) `## Conditions` sections. Carry forward unchanged items from the current inventory. Omit this field entirely if there is no existing inventory artifact and nothing meaningful to record.
@@ -75,6 +92,7 @@ Return a JSON object with these fields:
75
92
  Example format:
76
93
  ```json
77
94
  {
95
+ "no_changes": false,
78
96
  "description": "A woman in her early 30s with olive skin, dark hair pulled back in a ponytail, and an athletic build. She has a small scar above her left eyebrow.",
79
97
  "character_profile": "**Name:** {{agentName}}\n\n**Backstory:** [Updated backstory integrating recent events]\n\n**Personality:** [Evolution of traits]\n\n...\n\n**Personal Diary Entry:**\n\n*[Date or chapter reference]*\n\nDear Diary,\n\n[First-person reflection in character's voice]\n\n[Character's signature or closing]",
80
98
  "inventory": "## Items\n- Worn leather satchel\n- Brass compass\n- Hunting knife (chipped)\n\n## Conditions\n- Sprained ankle (healing)"
@@ -0,0 +1,18 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "name": "update_portrait_response",
4
+ "description": "Response schema for updating a character's portrait when their appearance has changed",
5
+ "type": "object",
6
+ "properties": {
7
+ "visual_prompt": {
8
+ "type": "string",
9
+ "description": "A single cohesive 150-200 word image-editing paragraph describing the character's current appearance, sent directly to the image editing system"
10
+ },
11
+ "description": {
12
+ "type": "string",
13
+ "description": "A brief 1-2 sentence description containing only immediately observable physical characteristics of the character's current appearance"
14
+ }
15
+ },
16
+ "required": ["visual_prompt", "description"],
17
+ "additionalProperties": false
18
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "visual_prompt": "A high-quality character portrait showing the character as they appear now, maintaining the original art style and lighting, with subtle changes to attire and expression reflecting recent events.",
3
+ "description": "A character whose appearance has changed slightly due to recent events."
4
+ }
@@ -6,6 +6,11 @@ You are updating the portrait of the character {{characterName}} in an interacti
6
6
  **Current Character Profile:**
7
7
  {{characterProfile}}
8
8
 
9
+ **Current Observable Description (their appearance before this change):**
10
+ {{currentDescription}}
11
+
12
+ Start from this current observable description and adjust only what has changed — don't re-derive the character's whole appearance from scratch.
13
+
9
14
  Your task is to create a detailed visual description of the character as they appear RIGHT NOW. This description will be used to edit their existing portrait image, so focus on their current appearance — including any recent changes — while maintaining the core elements that make the character recognizable.
10
15
 
11
16
  Focus on these key elements:
@@ -28,4 +33,15 @@ Focus on these key elements:
28
33
 
29
34
  Create a single, cohesive paragraph (150-200 words) that can be used directly as an image editing prompt. The description should be detailed enough for an AI to accurately update the existing portrait.
30
35
 
31
- Return only the visual description text. Do not include any preamble, commentary, or JSON formatting—just the pure descriptive paragraph that will be sent to the image editing system.
36
+ ## Response format
37
+ Return a JSON object with these fields:
38
+ - `visual_prompt`: The single cohesive 150-200 word image-editing paragraph described above. This is sent directly to the image editing system.
39
+ - `description`: A brief 1-2 sentence description of how {{characterName}} looks RIGHT NOW, covering only immediately observable physical characteristics (appearance, attire, visible marks). Start from the "Current Observable Description" above and revise only what changed. Do NOT include art-style, lighting, mood, or camera notes. This becomes the character's short observable description, so keep it concise and plainly descriptive.
40
+
41
+ Example format:
42
+ ```json
43
+ {
44
+ "visual_prompt": "A weathered man in his 50s, now with a fresh bandage wrapped around his left forearm and a torn, mud-stained jacket ... (150-200 words, image-editing style, including art style and lighting)",
45
+ "description": "A weathered man in his 50s with a freshly bandaged left forearm and a torn, mud-stained jacket."
46
+ }
47
+ ```
@@ -0,0 +1,13 @@
1
+ ## Scenario Overview
2
+
3
+ A simple test scenario where the characters meet and begin their adventure.
4
+
5
+ ## Setting & Environment
6
+
7
+ - **Location**: A test room
8
+ - **Atmosphere**: Calm and quiet
9
+ - **Notable Features**: A door and a window
10
+
11
+ ## Situation
12
+
13
+ The characters are gathered together as the story opens, ready to interact.
@@ -0,0 +1,35 @@
1
+ You are creating a simple plot plan for an interactive story titled "{{name}}".
2
+
3
+ **Story Scenario:**
4
+ {{scenario}}
5
+
6
+ **Characters:**
7
+ {{#each characters}}
8
+ - **{{name}}**{{#if isControlledByHuman}} (Player Character){{/if}}: {{description}}
9
+ {{/each}}
10
+
11
+ Your task is to write a short, simple plot plan in markdown format. This plot plan is **FOR YOUR EYES ONLY** - the characters will not see it. You will consult it as you narrate the story.
12
+
13
+ Unlike a detailed plot plan, this one is deliberately light. Do **not** invent elaborate mysteries, hidden secrets, plot twists, or a list of scripted events. Just establish the setting and premise so the story can unfold naturally from the characters' actions.
14
+
15
+ ## Plot Plan Format:
16
+ Keep it brief - a few short paragraphs total.
17
+
18
+ ### 1. Scenario Overview
19
+ Restate the story scenario above in your own words, capturing the premise and tone.
20
+
21
+ ### 2. Setting & Environment
22
+ - **Location**: Where does the story take place?
23
+ - **Atmosphere**: The mood and a few sensory details (sights, sounds, weather).
24
+ - **Notable Features**: A couple of locations or landmarks worth mentioning.
25
+
26
+ ### 3. Situation
27
+ What is going on as the story opens? What are the characters doing, and what is the immediate circumstance that gets things moving?
28
+
29
+ ## Guidelines:
30
+ - Keep it short and grounded - this is a starting point, not a script.
31
+ - Do not plan out secrets, twists, or scripted events; let the story emerge from character choices.
32
+ - Stay consistent with the scenario and character descriptions above.
33
+ - It is not your role to design the characters. They have their own backstories you know nothing of until they reveal them.
34
+
35
+ Return a string containing the entire markdown-formatted plot plan.
@@ -24,6 +24,9 @@ Use this information to guide your narration letting characters discover any sec
24
24
  {{visibleArtifacts}}
25
25
  ```
26
26
 
27
+ ### Character Inventories and Conditions
28
+ If a "Character Inventories and Conditions" section is included with the current situation, it lists what each character is currently carrying or wearing and any physical or mental conditions (wounded, exhausted, etc.). Use it to keep your narration consistent — characters can only use items they actually have, and their conditions should shape what they can do. The characters cannot see each other's inventories.
29
+
27
30
  ## Your Role as Narrator
28
31
 
29
32
  ### When you receive a user message, that means a character is requesting to perform an action and you must narrate both the action and its outcome
@@ -50,10 +53,10 @@ Try to do this when there is a notable pause (end of day) or a significant trans
50
53
  ### Introducing a new character
51
54
  If a character attempts to talk to or interact with a character who is *not* in the Available Characters list,
52
55
  You should:
53
- - Decide whether or not this character is going to be significant to the story
54
- - If so, choose a one-word name for that character (which will become their agent name). Prefer a single first name.
56
+ - Choose a one-word name for that character (which will become their agent name). Prefer a single first name.
55
57
  - Set `<introduce_character>CharacterName</introduce_character>` so the system can create a new agent for that character.
56
- - If that character is *not* going to be significant in the story and doesn't need their own character agent, set `<introduce_character>none</introduce_character>` and simply respond with dialog and narration like always.
58
+ - Do this for *every* new character who speaks or is interacted with, even minor ones. It does not matter whether the character is significant to the story - each character gets their own agent so that every character only knows what they would realistically know.
59
+ - Only set `<introduce_character>none</introduce_character>` when no new character speaks or is interacted with in this narration.
57
60
 
58
61
  ### When you receive a PASS message
59
62
  This means the user has decided not to take any particular action, so just continue narrating more of the story.
@@ -103,13 +106,13 @@ The moderator uses this to decide message routing:
103
106
  ### `<introduce_character>`
104
107
  This is a deliberate decision you must make on every turn. You **must** include reasoning in parentheses, even when the value is `none`.
105
108
 
106
- Choose `none` when no new character agent is needed.
107
- Choose a single capitalized first name when a character should be promoted to their own agent see the "Introducing a new character" section above for criteria.
109
+ Choose `none` only when no new character speaks or is interacted with in this narration.
110
+ Choose a single capitalized first name whenever a character who is *not* in the Available Characters list speaks or is interacted with even minor characters get their own agent.
108
111
 
109
112
  **Examples:**
110
- - `<introduce_character>none (the merchant is a one-time interaction, no need for a persistent agent)</introduce_character>`
113
+ - `<introduce_character>none (no new characters speak or are interacted with in this scene)</introduce_character>`
111
114
  - `<introduce_character>none (Sergei is mentioned but not present in the scene)</introduce_character>`
112
- - `<introduce_character>Sergei (the user has spoken with the dock master three times and might feature heavily in the story)</introduce_character>`
115
+ - `<introduce_character>Sergei (the dock master speaks with the user and is not in the Available Characters list)</introduce_character>`
113
116
 
114
117
  ### `<progress_chapter>`
115
118
  This is a deliberate decision you must make on every turn. You **must** include reasoning in parentheses, even when the value is `no`.
@@ -255,13 +258,13 @@ Correct response:
255
258
  ```
256
259
  <time>10:15</time>
257
260
  <situation>Mike is in the museum lobby speaking with the curator for the first time</situation>
258
- <introduce_character>Benjamin (the museum curator is a knowledge gatekeeper for the artifact plotline and the user has initiated direct dialog with him)</introduce_character>
261
+ <introduce_character>Benjamin (the museum curator speaks with Mike and is not in the Available Characters list)</introduce_character>
259
262
  <progress_chapter>no (Mike has just arrived at the museum, the investigation is beginning)</progress_chapter>
260
263
 
261
264
  That's right. I'm Benjamin Morris, the curator of this museum. What can I do to help you?
262
265
  ```
263
266
  NOTE: Typically, the narrator only responds to requested actions not dialog, but the Moderator routed this dialog message to the Narrator because that character was not on its Available Characters list.
264
- If the Narrator decides that this museum curator is going to be central to the story, setting `<introduce_character>Benjamin</introduce_character>` causes a new agent to be created for that character.
267
+ Since the curator is a new character being spoken to, setting `<introduce_character>Benjamin</introduce_character>` causes a new agent to be created for that character, regardless of how significant he turns out to be.
265
268
 
266
269
  ## Important Reminders
267
270
  - **Narrate consequences, not feelings** - describe what happens, what characters sense
@@ -0,0 +1,13 @@
1
+ ## Story Progress So Far
2
+
3
+ The characters have moved through the opening events and reached a natural turning point.
4
+
5
+ ## Current Situation
6
+
7
+ The group is regrouping and deciding what to do next.
8
+
9
+ ## Setting & Environment
10
+
11
+ - **Current Location**: A test room
12
+ - **Atmosphere**: Calm, with a sense of anticipation
13
+ - **Notable Features**: A door and a window
@@ -0,0 +1,40 @@
1
+ # Progress Simple Plot
2
+ You are updating the simple plot plan for the interactive story as it progresses to the next chapter.
3
+
4
+ ## Current Plot Plan
5
+ {{currentPlotPlan}}
6
+
7
+ ## Recent Story Events
8
+ Refer to the conversation history above for recent events.
9
+
10
+ ## Your Task
11
+ Update the plot plan so it reflects everything that has happened so far in the story. This plot plan is **FOR YOUR EYES ONLY** - the characters will not see it.
12
+
13
+ Keep it simple. Do **not** invent elaborate mysteries, hidden secrets, plot twists, or a list of scripted events. Just keep the setting and situation current so the story can continue to unfold naturally from the characters' actions.
14
+
15
+ As you update the plan:
16
+ - **Review what has happened**: Reflect on the recent story events and how they've unfolded.
17
+ - **Update the situation**: Describe where the characters are now and what has changed since the last chapter.
18
+ - **Stay consistent**: Keep the plan consistent with established story facts and character development.
19
+
20
+ The updated plot plan should include (keep it brief - a few short paragraphs total):
21
+
22
+ ## 1. Story Progress So Far
23
+ A brief summary of the key events that have occurred and how they've shaped the story.
24
+
25
+ ## 2. Current Situation
26
+ What circumstances do the characters find themselves in now? What has changed?
27
+
28
+ ## 3. Setting & Environment
29
+ - **Current Location**: Where are the characters now?
30
+ - **Atmosphere**: The current mood and a few sensory details.
31
+ - **Notable Features**: A couple of locations or landmarks relevant now.
32
+
33
+ **Important Guidelines:**
34
+ - Keep it short and grounded - this is a starting point for the next chapter, not a script.
35
+ - Do not plan out secrets, twists, or scripted events; let the story emerge from character choices.
36
+ - Ensure consistency with established story facts and character development.
37
+ - **This new plot plan replaces the previous one** - make it self-contained.
38
+
39
+ ## Response format
40
+ Return the entire markdown-formatted updated plot plan as a string.
@@ -5,7 +5,7 @@
5
5
  "properties": {
6
6
  "action": {
7
7
  "type": "string",
8
- "enum": ["think", "whisper", "speak", "shout", "publish", "execute", "adjourn"]
8
+ "enum": ["think", "whisper", "speak", "shout", "publish", "execute", "commission", "deliver", "adjourn"]
9
9
  },
10
10
  "targets": {
11
11
  "type": "array",
@@ -61,8 +61,12 @@ You must choose ONE of these actions:
61
61
  3. **SPEAK** - Normal message that all agents can hear (but always choose one agent to target for a response)
62
62
  4. **SHOUT** - Interrupts all other conversations
63
63
  5. **PUBLISH** - Create an artifact document that may be shared with other agents
64
- 6. **EXECUTE** - Run a shell command and receive a notification of the results
65
- 7. **ADJOURN** - Used by the group leader when the ultimate room goal has been met
64
+ {{#if availableTools}}
65
+ 6. **EXECUTE** - Run one of your available tools and privately receive its result
66
+ {{/if}}
67
+ 7. **COMMISSION** - Delegate a task to one or more named agents and wait for their deliverables
68
+ 8. **DELIVER** - Submit your completed result when you have been commissioned
69
+ 9. **ADJOURN** - Used by the group leader when the ultimate room goal has been met
66
70
 
67
71
  ## Decision Rules
68
72
 
@@ -99,15 +103,43 @@ You must choose ONE of these actions:
99
103
  - The 'name' string should contain a descriptive name of the artifact being published
100
104
  - The 'name' is used to identify the artifact in the conversation
101
105
 
106
+ {{#if availableTools}}
102
107
  ### When to EXECUTE
103
- - When you believe that executing a certain shell command will help achieve the room goal.
108
+ - When running one of your available tools (listed below) would help you answer a question, do research, or achieve the room goal.
104
109
 
105
110
  #### Execution rules
106
- - The 'content' of the JSON response should contain the exact string to execute in the shell.
107
- - The 'targets' array may contain a list of agent names that should receive the results (stdout) of the shell command.
108
- - If the 'targets' array is empty, only the sender of the EXECUTE message will receive the results.
109
- - The 'name' string should contain a description of that the shell output represents
110
- - Each shell command is always executed in the root of the Room's project folder
111
+ - The 'name' string must contain the exact name of the tool to run (from Your Available Tools below).
112
+ - The 'content' of the JSON response must contain a JSON object of named arguments for the tool, e.g. "{\"city\": \"Paris\"}". Use "{}" if the tool takes no arguments.
113
+ - The 'targets' array is not used for EXECUTE; leave it empty.
114
+ - The tool's result is returned privately to you as a system message. No other agent sees it.
115
+ - You may chain multiple EXECUTE and PUBLISH actions in a single turn (do research, then publish findings) before finally responding with an audible action such as SPEAK. The other agents wait until you respond.
116
+ - If a tool fails, you will receive the error and may retry with corrected arguments or give up and respond normally.
117
+
118
+ #### Your Available Tools
119
+ {{#each availableTools}}
120
+ - **{{this.name}}**: {{this.description}}
121
+ {{#each this.parameters}}
122
+ - {{this.name}} ({{this.type}}{{#if this.required}}, required{{/if}}): {{this.description}}
123
+ {{/each}}
124
+ {{/each}}
125
+ {{/if}}
126
+
127
+ ### When to COMMISSION
128
+ - When a task would benefit from one or more other agents doing focused work (research, analysis, drafting) before the conversation continues.
129
+ - The commissioned agents each work independently and reply with a DELIVER; you will then receive all of their deliverables at once, before anyone else speaks.
130
+
131
+ #### Commission rules
132
+ - The 'targets' array must contain the names of the agents you are commissioning (at least one, not yourself).
133
+ - The 'content' should state the task clearly enough that each commissioned agent can work without further clarification.
134
+ - Human-controlled agents cannot be commissioned.
135
+
136
+ ### When to DELIVER
137
+ - ONLY when you have been commissioned and have completed your task. This is the required final action of a commissioned agent.
138
+ - Before delivering, you may use EXECUTE and PUBLISH to do the work.
139
+
140
+ #### Deliver rules
141
+ - The 'targets' array should contain the name of the agent who commissioned you.
142
+ - The 'content' must contain your complete result. If you published an artifact as part of your work, mention its name here.
111
143
 
112
144
  ### When to ADJOURN
113
145
  - When you believe the goals of the room have been achieved and no further discussion would be helpful
@@ -118,7 +150,7 @@ You must choose ONE of these actions:
118
150
  Always respond with this exact JSON structure:
119
151
  ```
120
152
  {
121
- "action": "THINK|WHISPER|SPEAK|SHOUT|PUBLISH|EXECUTE|ADJOURN",
153
+ "action": "THINK|WHISPER|SPEAK|SHOUT|PUBLISH|EXECUTE|COMMISSION|DELIVER|ADJOURN",
122
154
  "targets": ["Message target 1", "Message target 2"],
123
155
  "name": "Artifact name",
124
156
  "content": "The body of your message"
@@ -127,13 +159,13 @@ Always respond with this exact JSON structure:
127
159
  **NOTE**: The 'content' property of the JSON response must be double-quoted. Avoid using double-quotes within the actual content itself.
128
160
 
129
161
  ## Format Rules
130
- - `action` must be one of: "THINK", "WHISPER", "SPEAK", "SHOUT", "DRAFT", "APPROVE", "EXECUTE", "ADJOURN"
162
+ - `action` must be one of: "THINK", "WHISPER", "SPEAK", "SHOUT", "PUBLISH", "EXECUTE", "COMMISSION", "DELIVER", "ADJOURN"
131
163
  - `targets` must be:
132
- - Empty array `[]` for THINK or when speaking to everyone
133
- - Array with specific agent names for WHISPER, PUBLISH, and EXECUTE
164
+ - Empty array `[]` for THINK, EXECUTE, or when speaking to everyone
165
+ - Array with specific agent names for WHISPER, PUBLISH, COMMISSION, and DELIVER
134
166
  - Optional for SPEAK and ADJOURN
135
- `content` must contain your actual message or shell command or the body of your published artifact
136
- `name` is empty unless publishing an artifact or executing a shell command
167
+ `content` must contain your actual message, the body of your published artifact, or the JSON arguments of the tool you are executing
168
+ `name` is empty unless publishing an artifact (artifact name) or executing a tool (tool name)
137
169
 
138
170
  ## Examples
139
171
 
@@ -215,15 +247,45 @@ Correct response:
215
247
  }
216
248
  ```
217
249
 
218
- **Example 7: Executing a shell command**
219
- > Alice speaks to {{agentNickname}}: We need to know a bit more about the structure of this project.
250
+ {{#if availableTools}}
251
+ **Example 7: Executing a tool**
252
+ > Alice speaks to {{agentNickname}}: We need to know what the weather will be like in Paris tomorrow.
220
253
 
221
- Correct response:
254
+ Correct response (assuming you have a tool named "weather_lookup" that takes a "city" argument):
222
255
  ```
223
256
  {
224
257
  "action": "execute",
225
- "targets": ["Alice", "Bob"],
226
- "name": "Directory contents of path/to/something",
227
- "content": "ls -al ./path/to/something"
258
+ "targets": [],
259
+ "name": "weather_lookup",
260
+ "content": "{\"city\": \"Paris\"}"
261
+ }
262
+ ```
263
+ After you receive the tool result, respond audibly (e.g. SPEAK to Alice with the answer).
264
+ {{/if}}
265
+
266
+ **Example 8: Commissioning research from other agents**
267
+ > Alice speaks to {{agentNickname}}: We should compare the two proposals before deciding.
268
+
269
+ Correct response:
270
+ ```
271
+ {
272
+ "action": "commission",
273
+ "targets": ["Bob", "Carol"],
274
+ "name": "",
275
+ "content": "Please each analyze one proposal: Bob takes proposal A, Carol takes proposal B. Summarize strengths, weaknesses, and risks."
276
+ }
277
+ ```
278
+ You will receive both deliverables before the conversation continues, and are expected to respond to them.
279
+
280
+ **Example 9: Delivering a commissioned result**
281
+ > Bob commissions {{agentNickname}}: Please analyze proposal A and summarize its strengths, weaknesses, and risks.
282
+
283
+ Correct response (after doing the work, possibly using EXECUTE or PUBLISH first):
284
+ ```
285
+ {
286
+ "action": "deliver",
287
+ "targets": ["Bob"],
288
+ "name": "",
289
+ "content": "Proposal A analysis: strengths are... weaknesses are... risks are... Full details in the published artifact 'Proposal A Analysis'."
228
290
  }
229
291
  ```
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "update_inventory": {
38
38
  "type": "array",
39
- "description": "List of character inventory updates triggered by this message. Each entry replaces the named character's existing '[name] - Inventory' artifact wholesale. Include an entry only when items have actually been gained, lost, consumed, equipped, or when a notable physical/mental trait or condition has changed (wounded, exhausted, intoxicated, transformed, etc.). Leave empty or omit if nothing changed.",
39
+ "description": "List of character inventory updates triggered by this message. Each entry replaces the named character's existing stored inventory wholesale. Include an entry only when items have actually been gained, lost, consumed, equipped, or when a notable physical/mental trait or condition has changed (wounded, exhausted, intoxicated, transformed, etc.). Leave empty or omit if nothing changed.",
40
40
  "items": {
41
41
  "type": "object",
42
42
  "properties": {
@@ -22,7 +22,7 @@ Filter inappropriate language and content from messages.
22
22
  {{humanAgentName}}
23
23
 
24
24
  ### Character Inventories and Conditions
25
- You have access to each character's `[CharacterName] - Inventory` artifact (visible only to you, the Narrator, and the character themselves). These artifacts list what each character is currently carrying, wearing, or possessing, plus any notable physical or mental conditions (wounded, exhausted, drunk, transformed, etc.). Use these to keep the story self-consistent — when a character refers to "my sword" the inventory should support it, when a character takes damage you should record the wound, etc.
25
+ Each character's current inventory and conditions are provided to you under a "Character Inventories and Conditions" heading in the message below (visible only to you, not to the characters' peers). These list what each character is currently carrying, wearing, or possessing, plus any notable physical or mental conditions (wounded, exhausted, drunk, transformed, etc.). Use these to keep the story self-consistent — when a character refers to "my sword" the inventory should support it, when a character takes damage you should record the wound, etc.
26
26
 
27
27
  {{#if visibleArtifacts}}
28
28
  {{visibleArtifacts}}
@@ -40,10 +40,12 @@ To accomplish your task:
40
40
  - Determine whether the Sender of the recent message is trying to 1) perform an action or 2) only participate in dialog
41
41
 
42
42
  ### The Current Situation is authoritative
43
+ Each message you receive is preceded by a **Current time** line (a 24-hour "HH:MM" clock) and a **Current Situation** line. The time tells you when the scene is taking place; the situation tells you who is present and where.
44
+
43
45
  The **Current Situation** line is the single source of truth about which characters are physically present in the active scene, and where. When routing:
44
46
  - Only characters named in the Current Situation are "present". Other characters are elsewhere and cannot hear or respond unless the Current Situation itself changes.
45
47
  - Do **not** infer that a character is present from vague references in the body of a narration (e.g., "the men outside", "the others", "everyone"). If a character is not named in the Current Situation, treat them as absent — pick a different responder.
46
- - Do **not** assume a scene shift based on body content alone. A scene shift only happens when the Current Situation itself names a different time, place, or set of characters. If the situation still says "Jessica and Mòr in the kitchen", the responder must be one of Jessica, Mòr, or the Narrator — never a character who is miles away in another storyline.
48
+ - Do **not** assume a scene shift based on body content alone. A scene shift only happens when the Current time or Current Situation itself names a different time, place, or set of characters. If the situation still says "Jessica and Mòr in the kitchen", the responder must be one of Jessica, Mòr, or the Narrator — never a character who is miles away in another storyline.
47
49
  - If the narration genuinely describes a character who is not in the Current Situation (e.g., a brief aside about someone elsewhere), keep the responder among the characters who ARE in the Current Situation; do not hand the turn off to the absent character.
48
50
 
49
51
  ### If the Sender is intending to perform an action:
@@ -73,7 +75,7 @@ This request will *not* become part of the readable story, only the narrator's r
73
75
  - Use the character's exact name as it appears in the Available Characters list.
74
76
  - Leave the array empty if no visible appearance changes occurred.
75
77
  - Minor or invisible changes (emotional state alone, unseen actions) do NOT warrant a portrait update.
76
- - `update_inventory`: list of character inventory artifacts that should be rewritten in light of this message. Each entry replaces the named character's `[Name] - Inventory` artifact in full.
78
+ - `update_inventory`: list of character inventories that should be rewritten in light of this message. Each entry replaces the named character's stored inventory in full.
77
79
  - Include an entry when items are gained, lost, consumed, broken, given, taken, equipped, unequipped, OR when a notable physical/mental trait or condition changes (wounded, healed, exhausted, intoxicated, transformed, cursed, blessed, etc.).
78
80
  - The `inventory` field must contain the COMPLETE new inventory body (not a diff). Read the character's current inventory artifact from the context above, apply the change, and return the updated artifact text.
79
81
  - Use this structure (omit a section if it would be empty):
@@ -119,7 +121,7 @@ You must respond with a valid JSON object in the following format:
119
121
  - **Important**:Avoid lengthy conversations that exclude the Human Character completely. Give the Human Character a chance to interact with the story.
120
122
 
121
123
  ### When no character is available to respond — auto-PASS to the Narrator
122
- Sometimes no character in the Current Situation can realistically be the next speaker. The most common case is when the only present character is asleep, unconscious, dead, paralyzed, in a coma, or otherwise narratively unable to speak or act (check their `[Name] - Inventory` artifact's `## Conditions` section). It can also happen when the Current Situation is a transitional beat with no living character actively present.
124
+ Sometimes no character in the Current Situation can realistically be the next speaker. The most common case is when the only present character is asleep, unconscious, dead, paralyzed, in a coma, or otherwise narratively unable to speak or act (check their `## Conditions` section in the Character Inventories and Conditions provided below). It can also happen when the Current Situation is a transitional beat with no living character actively present.
123
125
 
124
126
  In these cases, emit an automatic PASS on the human's behalf, exactly as you would if the Human Character had typed "PASS":
125
127
  - Set `name` to `"Narrator"` — the Narrator can always continue the story.
@@ -246,7 +248,8 @@ Correct Response:
246
248
 
247
249
 
248
250
  ### Example 5b: Narration mentions an absent character, but the Current Situation has NOT shifted
249
- Current Situation: 17:35 - Mike and Jessica are in the kitchen as the evening meal is being prepared
251
+ Current time: 17:35 (24-hour clock)
252
+ Current Situation: Mike and Jessica are in the kitchen as the evening meal is being prepared
250
253
  Recent Message Sender: Narrator
251
254
  Recent Message: The kitchen smells of stew and woodsmoke. Outside, the men are tending to the horses. Somewhere else, Sergei is at his cottage that morning, washing at the basin and turning over what he saw the night before.
252
255
  Correct Response:
@@ -391,7 +394,8 @@ Correct Response:
391
394
 
392
395
 
393
396
  ### Example 12: No character available to respond — auto-PASS to Narrator
394
- Current Situation: 23:50 - Jessica is alone in the small side room at Balmore, having just settled in for the night
397
+ Current time: 23:50 (24-hour clock)
398
+ Current Situation: Jessica is alone in the small side room at Balmore, having just settled in for the night
395
399
  Suppose Jessica's inventory is:
396
400
  ## Items
397
401
  - Wool blanket
@@ -418,3 +422,19 @@ Correct Response:
418
422
  - Jessica stays in `targets` because she's physically present in the scene (and could be woken later), but she is NOT the responder `name`.
419
423
  - "Asleep" is already in her conditions; no inventory update needed.
420
424
 
425
+ ### Example 13: Character has an expectation of privacy
426
+ Current time: 20:30 (24-hour clock)
427
+ Current Situation: Mike is alone in the bathroom getting ready to go out
428
+ Recent Message Sender: Narrator
429
+ Recent Message: Mike borrows Ralph's toothbrush and brushes his teeth because he can't find his own.
430
+ Correct Response:
431
+ {
432
+ "action": "relay",
433
+ "content": "relay",
434
+ "name": "Mike",
435
+ "targets": ["Mike"],
436
+ "update_portrait": [],
437
+ "update_inventory": []
438
+ }
439
+ - Mike is alone and no other character should be able to know that he borrowed Ralph's toothbrush.
440
+ - targets is set to ["Mike"] because Mike is the only character present in the scene.
@@ -250,7 +250,6 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
250
250
  this.debugLogResponse(agent.agentName, responseText);
251
251
  if (jsonSchema) {
252
252
  responseText = this.trimToJson(responseText);
253
- responseText = this.sanitizeJsonString(responseText);
254
253
  }
255
254
  if (response.usage) {
256
255
  this.computeMessageCost(agent, response.usage);
@@ -258,7 +257,7 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
258
257
  let parsedResponse;
259
258
  if (jsonSchema) {
260
259
  try {
261
- parsedResponse = JSON.parse(responseText);
260
+ parsedResponse = this.parseStructuredResponse(responseText);
262
261
  if (saveResponse) {
263
262
  agent.addToConversationHistory(prompt, false);
264
263
  agent.addToConversationHistory(responseText, true);
@@ -44,5 +44,5 @@ export declare class BaseAiService {
44
44
  protected debugLogResponse(agentName: string, response: string): void;
45
45
  trimResponseText(str: string): string;
46
46
  trimToJson(str: string): string;
47
- sanitizeJsonString(str: string): string;
47
+ parseStructuredResponse(text: string): any;
48
48
  }
@@ -51,6 +51,7 @@ const fs = __importStar(require("fs"));
51
51
  const handlebars_1 = require("handlebars");
52
52
  const errors_1 = require("../../common/errors");
53
53
  const logger_1 = require("../../common/logger");
54
+ const jsonrepair_1 = require("jsonrepair");
54
55
  const model_prices_1 = require("../model_prices");
55
56
  const ai_debug_logger_1 = require("../ai-debug-logger");
56
57
  let BaseAiService = class BaseAiService {
@@ -381,51 +382,21 @@ let BaseAiService = class BaseAiService {
381
382
  }
382
383
  return str;
383
384
  }
384
- sanitizeJsonString(str) {
385
- let result = '';
386
- let inString = false;
387
- let escapeNext = false;
388
- for (let i = 0; i < str.length; i++) {
389
- const char = str[i];
390
- if (escapeNext) {
391
- if (char === "'") {
392
- result = result.slice(0, -1) + char;
393
- }
394
- else {
395
- result += char;
396
- }
397
- escapeNext = false;
398
- continue;
399
- }
400
- if (char === '\\') {
401
- result += char;
402
- escapeNext = true;
403
- continue;
404
- }
405
- if (char === '"') {
406
- inString = !inString;
407
- result += char;
408
- continue;
409
- }
410
- if (inString) {
411
- if (char === '\n') {
412
- result += '\\n';
413
- }
414
- else if (char === '\r') {
415
- result += '\\r';
416
- }
417
- else if (char === '\t') {
418
- result += '\\t';
419
- }
420
- else {
421
- result += char;
422
- }
385
+ parseStructuredResponse(text) {
386
+ try {
387
+ return JSON.parse(text);
388
+ }
389
+ catch (firstError) {
390
+ try {
391
+ const repaired = (0, jsonrepair_1.jsonrepair)(text);
392
+ logger_1.logger.warn('Structured response was not valid JSON; recovered via jsonrepair');
393
+ return JSON.parse(repaired);
423
394
  }
424
- else {
425
- result += char;
395
+ catch {
396
+ logger_1.logger.error('Failed to parse structured response even after repair');
397
+ throw firstError;
426
398
  }
427
399
  }
428
- return result;
429
400
  }
430
401
  };
431
402
  exports.BaseAiService = BaseAiService;