briyah 1.2.3 → 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 (119) 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/model_prices.json +31 -0
  5. package/data/common/config/story_models.json +31 -11
  6. package/data/common/config/story_models_full.json +25 -7
  7. package/data/common/prompts/character/create_user_character.prompt +3 -12
  8. package/data/common/prompts/character/introduce_character.json +18 -0
  9. package/data/common/prompts/character/introduce_character.mock +4 -0
  10. package/data/common/prompts/character/introduce_character.prompt +58 -0
  11. package/data/common/prompts/character/perceive.prompt +3 -0
  12. package/data/common/prompts/character/progress_character.json +8 -4
  13. package/data/common/prompts/character/progress_character.mock +1 -0
  14. package/data/common/prompts/character/progress_character.prompt +20 -2
  15. package/data/common/prompts/character/update_portrait.json +18 -0
  16. package/data/common/prompts/character/update_portrait.mock +4 -0
  17. package/data/common/prompts/character/update_portrait.prompt +17 -1
  18. package/data/common/prompts/narrator/create_simple_plot.json +0 -0
  19. package/data/common/prompts/narrator/create_simple_plot.mock +13 -0
  20. package/data/common/prompts/narrator/create_simple_plot.prompt +35 -0
  21. package/data/common/prompts/narrator/perceive.prompt +12 -9
  22. package/data/common/prompts/narrator/progress_simple_plot.json +0 -0
  23. package/data/common/prompts/narrator/progress_simple_plot.mock +13 -0
  24. package/data/common/prompts/narrator/progress_simple_plot.prompt +40 -0
  25. package/data/common/prompts/perceive.json +1 -1
  26. package/data/common/prompts/perceive.prompt +82 -20
  27. package/data/common/prompts/story_moderator/moderate.json +1 -1
  28. package/data/common/prompts/story_moderator/moderate.prompt +26 -6
  29. package/dist-sdk/server/src/ai/LLM/anthropic.service.js +6 -4
  30. package/dist-sdk/server/src/ai/LLM/base-ai.service.d.ts +1 -1
  31. package/dist-sdk/server/src/ai/LLM/base-ai.service.js +13 -42
  32. package/dist-sdk/server/src/ai/LLM/deepseek.service.js +10 -1
  33. package/dist-sdk/server/src/ai/LLM/fal.service.js +1 -2
  34. package/dist-sdk/server/src/ai/LLM/googleai.service.js +1 -2
  35. package/dist-sdk/server/src/ai/LLM/grok.service.js +1 -2
  36. package/dist-sdk/server/src/ai/LLM/openai.service.js +1 -2
  37. package/dist-sdk/server/src/ai/LLM/together.service.js +1 -2
  38. package/dist-sdk/server/src/ai/agent-config.d.ts +2 -0
  39. package/dist-sdk/server/src/ai/agent-store.service.js +8 -0
  40. package/dist-sdk/server/src/ai/agent.d.ts +2 -0
  41. package/dist-sdk/server/src/ai/agent.js +2 -0
  42. package/dist-sdk/server/src/ai/model_prices.js +2 -1
  43. package/dist-sdk/server/src/app/user-service-factory.js +7 -3
  44. package/dist-sdk/server/src/app.controller.d.ts +15 -4
  45. package/dist-sdk/server/src/app.controller.js +171 -5
  46. package/dist-sdk/server/src/app.service.d.ts +19 -5
  47. package/dist-sdk/server/src/app.service.js +50 -4
  48. package/dist-sdk/server/src/room/message.js +5 -1
  49. package/dist-sdk/server/src/room/room-factory.d.ts +5 -1
  50. package/dist-sdk/server/src/room/room-factory.js +6 -1
  51. package/dist-sdk/server/src/room/room-store.service.d.ts +5 -1
  52. package/dist-sdk/server/src/room/room-store.service.js +13 -2
  53. package/dist-sdk/server/src/room/room.d.ts +25 -4
  54. package/dist-sdk/server/src/room/room.js +393 -96
  55. package/dist-sdk/server/src/sdk/index.d.ts +1 -1
  56. package/dist-sdk/server/src/story/story.service.d.ts +5 -4
  57. package/dist-sdk/server/src/story/story.service.js +207 -120
  58. package/dist-sdk/server/src/tools/tool-execution.service.d.ts +19 -0
  59. package/dist-sdk/server/src/tools/tool-execution.service.js +100 -0
  60. package/dist-sdk/server/src/tools/tool-store.service.d.ts +17 -0
  61. package/dist-sdk/server/src/tools/tool-store.service.js +143 -0
  62. package/dist-sdk/shared/types/app.types.d.ts +44 -5
  63. package/dist-sdk/shared/types/app.types.js +3 -0
  64. package/docs/assets/hierarchy.js +1 -1
  65. package/docs/assets/highlight.css +0 -7
  66. package/docs/assets/navigation.js +1 -1
  67. package/docs/assets/search.js +1 -1
  68. package/docs/classes/Agent.html +22 -14
  69. package/docs/classes/Briyah.html +10 -10
  70. package/docs/classes/BriyahConfigService.html +5 -5
  71. package/docs/classes/Room.html +32 -26
  72. package/docs/classes/RoomMessage.html +10 -10
  73. package/docs/enums/MessageAction.html +6 -3
  74. package/docs/hierarchy.html +1 -1
  75. package/docs/index.html +12 -5
  76. package/docs/interfaces/AgentInfo.html +3 -2
  77. package/docs/interfaces/AgentMessagesResponse.html +2 -2
  78. package/docs/interfaces/AppService.html +184 -149
  79. package/docs/interfaces/Artifact.html +3 -3
  80. package/docs/interfaces/ArtifactMetadata.html +2 -2
  81. package/docs/interfaces/AttachDocumentResponse.html +2 -2
  82. package/docs/interfaces/BriyahConfigOptions.html +7 -7
  83. package/docs/interfaces/ChapterInfo.html +2 -2
  84. package/docs/interfaces/Character.html +2 -2
  85. package/docs/interfaces/CreateAgentResponse.html +2 -2
  86. package/docs/interfaces/CreateRoomResponse.html +2 -2
  87. package/docs/interfaces/CreateStoryResponse.html +2 -2
  88. package/docs/interfaces/FileList.html +2 -2
  89. package/docs/interfaces/FileMetadata.html +3 -3
  90. package/docs/interfaces/IConfigService.html +3 -3
  91. package/docs/interfaces/LoggingOptions.html +6 -6
  92. package/docs/interfaces/Message.html +2 -2
  93. package/docs/interfaces/ModelInfo.html +2 -3
  94. package/docs/interfaces/PreparedPromptResponse.html +2 -2
  95. package/docs/interfaces/ProcessTextResponse.html +2 -2
  96. package/docs/interfaces/PromptFile.html +2 -2
  97. package/docs/interfaces/PromptFileContent.html +2 -2
  98. package/docs/interfaces/PromptFilesResponse.html +2 -2
  99. package/docs/interfaces/PromptFolder.html +2 -2
  100. package/docs/interfaces/PromptFoldersResponse.html +2 -2
  101. package/docs/interfaces/RoomDetails.html +2 -2
  102. package/docs/interfaces/RoomInfo.html +2 -2
  103. package/docs/interfaces/RoomMessagesResponse.html +2 -2
  104. package/docs/interfaces/StoryErrorEvent.html +3 -3
  105. package/docs/interfaces/StoryIdea.html +2 -2
  106. package/docs/interfaces/StoryInfo.html +5 -4
  107. package/docs/interfaces/StoryIntroduceCharacterEvent.html +3 -3
  108. package/docs/interfaces/StoryProgressChapterEvent.html +3 -3
  109. package/docs/interfaces/StoryState.html +5 -5
  110. package/docs/interfaces/StoryStateEvent.html +3 -3
  111. package/docs/interfaces/ToolDefinition.html +6 -0
  112. package/docs/interfaces/ToolParameter.html +5 -0
  113. package/docs/interfaces/ToolsResponse.html +2 -0
  114. package/docs/interfaces/Transaction.html +2 -2
  115. package/docs/interfaces/TransactionHistoryResponse.html +2 -2
  116. package/docs/modules.html +1 -1
  117. package/docs/types/PromptScope.html +1 -1
  118. package/docs/types/ToolRunResult.html +1 -0
  119. package/package.json +2 -1
@@ -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.
@@ -17,6 +17,7 @@ const base_ai_service_1 = require("./base-ai.service");
17
17
  const model_prices_1 = require("../model_prices");
18
18
  const errors_1 = require("../../common/errors");
19
19
  const logger_1 = require("../../common/logger");
20
+ const ai_debug_logger_1 = require("../ai-debug-logger");
20
21
  let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.BaseAiService {
21
22
  static { AnthropicAiService_1 = this; }
22
23
  anthropic;
@@ -215,7 +216,9 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
215
216
  };
216
217
  if (this.usesEffortConfig(agent.modelName)) {
217
218
  if (agent.reasoningEffort) {
218
- createParams.thinking = { type: 'adaptive' };
219
+ createParams.thinking = ai_debug_logger_1.AiDebugLogger.isEnabled()
220
+ ? { type: 'adaptive', display: 'summarized' }
221
+ : { type: 'adaptive' };
219
222
  createParams.output_config = { effort: agent.reasoningEffort };
220
223
  }
221
224
  }
@@ -247,7 +250,6 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
247
250
  this.debugLogResponse(agent.agentName, responseText);
248
251
  if (jsonSchema) {
249
252
  responseText = this.trimToJson(responseText);
250
- responseText = this.sanitizeJsonString(responseText);
251
253
  }
252
254
  if (response.usage) {
253
255
  this.computeMessageCost(agent, response.usage);
@@ -255,7 +257,7 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
255
257
  let parsedResponse;
256
258
  if (jsonSchema) {
257
259
  try {
258
- parsedResponse = JSON.parse(responseText);
260
+ parsedResponse = this.parseStructuredResponse(responseText);
259
261
  if (saveResponse) {
260
262
  agent.addToConversationHistory(prompt, false);
261
263
  agent.addToConversationHistory(responseText, true);
@@ -316,7 +318,7 @@ let AnthropicAiService = class AnthropicAiService extends base_ai_service_1.Base
316
318
  }
317
319
  throw new Error(`Failed to get valid response after ${maxRetries} attempts. Last error: ${lastError?.message || 'Unknown error'}`);
318
320
  }
319
- static EFFORT_CONFIG_MODEL_VERSIONS = ['4-7', '4-8'];
321
+ static EFFORT_CONFIG_MODEL_VERSIONS = ['4-7', '4-8', 'fable'];
320
322
  usesEffortConfig(modelName) {
321
323
  return AnthropicAiService_1.EFFORT_CONFIG_MODEL_VERSIONS.some((v) => modelName.includes(v));
322
324
  }
@@ -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;
@@ -13,6 +13,7 @@ exports.DeepSeekAiService = void 0;
13
13
  const common_1 = require("@nestjs/common");
14
14
  const deepseek_1 = require("@ai-sdk/deepseek");
15
15
  const ai_1 = require("ai");
16
+ const jsonrepair_1 = require("jsonrepair");
16
17
  const base_ai_service_1 = require("./base-ai.service");
17
18
  const zod_1 = require("zod");
18
19
  const model_prices_1 = require("../model_prices");
@@ -200,7 +201,15 @@ let DeepSeekAiService = class DeepSeekAiService extends base_ai_service_1.BaseAi
200
201
  model: this.deepseekClient(agent.modelName),
201
202
  messages: messages,
202
203
  temperature: 0,
203
- schema: jsonSchema,
204
+ schema: this.jsonSchemaToZod(jsonSchema),
205
+ experimental_repairText: async ({ text }) => {
206
+ try {
207
+ return (0, jsonrepair_1.jsonrepair)(text);
208
+ }
209
+ catch {
210
+ return null;
211
+ }
212
+ },
204
213
  providerOptions: {
205
214
  deepseek: {
206
215
  reasoningEffort: reasoningEffort,
@@ -151,7 +151,6 @@ let FalAiService = class FalAiService extends base_ai_service_1.BaseAiService {
151
151
  estimatedOutputTokens = Math.ceil(responseText.length / 4);
152
152
  if (jsonSchema) {
153
153
  responseText = this.trimToJson(responseText);
154
- responseText = this.sanitizeJsonString(responseText);
155
154
  }
156
155
  else {
157
156
  responseText = this.trimResponseText(responseText);
@@ -179,7 +178,7 @@ let FalAiService = class FalAiService extends base_ai_service_1.BaseAiService {
179
178
  }
180
179
  if (jsonSchema) {
181
180
  try {
182
- return JSON.parse(responseText);
181
+ return this.parseStructuredResponse(responseText);
183
182
  }
184
183
  catch (parseError) {
185
184
  logger_1.logger.error('Failed to parse JSON response:', parseError);
@@ -133,7 +133,6 @@ let GoogleAiService = class GoogleAiService extends base_ai_service_1.BaseAiServ
133
133
  }
134
134
  if (jsonSchema) {
135
135
  responseText = this.trimToJson(responseText);
136
- responseText = this.sanitizeJsonString(responseText);
137
136
  }
138
137
  else {
139
138
  responseText = this.trimResponseText(responseText);
@@ -152,7 +151,7 @@ let GoogleAiService = class GoogleAiService extends base_ai_service_1.BaseAiServ
152
151
  this.addToConversationHistory(agent, responseText, true);
153
152
  }
154
153
  if (jsonSchema) {
155
- return JSON.parse(responseText);
154
+ return this.parseStructuredResponse(responseText);
156
155
  }
157
156
  return responseText;
158
157
  }
@@ -194,7 +194,6 @@ let GrokAiService = class GrokAiService extends base_ai_service_1.BaseAiService
194
194
  }
195
195
  if (jsonSchema) {
196
196
  responseText = this.trimToJson(responseText);
197
- responseText = this.sanitizeJsonString(responseText);
198
197
  }
199
198
  this.debugLogResponse(agent.agentName, responseText);
200
199
  if (response.usage) {
@@ -210,7 +209,7 @@ let GrokAiService = class GrokAiService extends base_ai_service_1.BaseAiService
210
209
  this.addToConversationHistory(agent, responseText, true);
211
210
  }
212
211
  if (jsonSchema)
213
- return JSON.parse(responseText);
212
+ return this.parseStructuredResponse(responseText);
214
213
  return responseText;
215
214
  }
216
215
  addToConversationHistory(agent, message, fromSelf = false, developer = false) {
@@ -211,7 +211,6 @@ let OpenAiService = class OpenAiService extends base_ai_service_1.BaseAiService
211
211
  response = await this.openai.responses.create(requestParams);
212
212
  if (jsonSchema) {
213
213
  responseText = this.trimToJson(response.output_text);
214
- responseText = this.sanitizeJsonString(responseText);
215
214
  }
216
215
  else {
217
216
  responseText = response.output_text;
@@ -230,7 +229,7 @@ let OpenAiService = class OpenAiService extends base_ai_service_1.BaseAiService
230
229
  this.addToConversationHistory(agent, responseText, true);
231
230
  }
232
231
  if (jsonSchema)
233
- return JSON.parse(responseText);
232
+ return this.parseStructuredResponse(responseText);
234
233
  return responseText;
235
234
  }
236
235
  async attachDocument(agent, fileName, fileData) {
@@ -138,7 +138,6 @@ let TogetherAiService = class TogetherAiService extends base_ai_service_1.BaseAi
138
138
  }
139
139
  if (jsonSchema) {
140
140
  responseText = this.trimToJson(responseText);
141
- responseText = this.sanitizeJsonString(responseText);
142
141
  }
143
142
  else {
144
143
  responseText = this.trimResponseText(responseText);
@@ -157,7 +156,7 @@ let TogetherAiService = class TogetherAiService extends base_ai_service_1.BaseAi
157
156
  this.addToConversationHistory(agent, responseText, true);
158
157
  }
159
158
  if (jsonSchema) {
160
- return JSON.parse(responseText);
159
+ return this.parseStructuredResponse(responseText);
161
160
  }
162
161
  return responseText;
163
162
  }
@@ -4,6 +4,7 @@ export interface AgentConfig {
4
4
  agentName: string;
5
5
  agentNickname: string;
6
6
  description: string;
7
+ privateContext?: string;
7
8
  promptFolder: string;
8
9
  systemInstruction: string;
9
10
  modelName: string;
@@ -30,4 +31,5 @@ export interface AgentConfig {
30
31
  beginInstruction?: string;
31
32
  promptCacheTTL?: number;
32
33
  ownerRoomId?: string;
34
+ toolNames?: string[];
33
35
  }
@@ -140,12 +140,14 @@ let AgentStoreService = class AgentStoreService {
140
140
  instance.totalOutputTokens = 0;
141
141
  instance.totalCost = 0;
142
142
  instance.totalMarkup = 0;
143
+ instance.privateContext = template.privateContext;
143
144
  instance.attachedFiles = [...template.attachedFiles];
144
145
  instance.attachedArtifacts = [...template.attachedArtifacts];
145
146
  instance.maxHistoryMessages = template.maxHistoryMessages;
146
147
  instance.promptCacheTTL = template.promptCacheTTL;
147
148
  instance.markupRate = template.markupRate;
148
149
  instance.smallModelName = template.smallModelName;
150
+ instance.toolNames = [...template.toolNames];
149
151
  this.storeAgent(instance);
150
152
  return instanceId;
151
153
  }
@@ -173,6 +175,7 @@ let AgentStoreService = class AgentStoreService {
173
175
  throw new Error(`Instance ${instanceId} does not belong to template ${templateId}`);
174
176
  }
175
177
  instance.description = template.description;
178
+ instance.privateContext = template.privateContext;
176
179
  instance.agentNickname = template.agentNickname;
177
180
  instance.promptFolder = template.promptFolder;
178
181
  instance.systemInstruction = template.systemInstruction;
@@ -188,6 +191,7 @@ let AgentStoreService = class AgentStoreService {
188
191
  instance.maxHistoryMessages = template.maxHistoryMessages;
189
192
  instance.promptCacheTTL = template.promptCacheTTL;
190
193
  instance.markupRate = template.markupRate;
194
+ instance.toolNames = [...template.toolNames];
191
195
  instance.history = [];
192
196
  instance.totalInputTokens = 0;
193
197
  instance.totalOutputTokens = 0;
@@ -236,6 +240,7 @@ let AgentStoreService = class AgentStoreService {
236
240
  const aiService = this.aiFactoryService.createAiService(config.serviceName);
237
241
  const finalArtifactService = artifactService || this.artifactService;
238
242
  const agent = new agent_1.Agent(config.id, this.userPaths, this.configService, this, this.balanceService, finalArtifactService, config.agentName, config.agentNickname || config.agentName, config.description, config.promptFolder, config.systemInstruction, config.history || [], config.modelName, config.serviceName, aiService, config.reasoningEffort, config.allowSearch, config.maxOutputTokens, config.beginInstruction || '', storageDir);
243
+ agent.privateContext = config.privateContext || '';
239
244
  agent.createdAt = new Date(config.createdAt);
240
245
  agent.userPaths = this.userPaths;
241
246
  agent.smallModelName = config.smallModelName;
@@ -255,6 +260,7 @@ let AgentStoreService = class AgentStoreService {
255
260
  agent.beginInstruction = config.beginInstruction || '';
256
261
  agent.maxHistoryMessages = config.maxHistoryMessages || undefined;
257
262
  agent.promptCacheTTL = Number(config.promptCacheTTL) ?? 0;
263
+ agent.toolNames = config.toolNames || [];
258
264
  agent.id = config.id;
259
265
  this.agents.set(config.id, agent);
260
266
  if (config.attachedFiles && config.attachedFiles.length > 0) {
@@ -305,6 +311,7 @@ let AgentStoreService = class AgentStoreService {
305
311
  agentName: agent.agentName,
306
312
  agentNickname: agent.agentNickname,
307
313
  description: agent.description,
314
+ privateContext: agent.privateContext,
308
315
  promptFolder: agent.promptFolder,
309
316
  systemInstruction: agent.systemInstruction,
310
317
  modelName: agent.modelName,
@@ -331,6 +338,7 @@ let AgentStoreService = class AgentStoreService {
331
338
  beginInstruction: agent.beginInstruction,
332
339
  promptCacheTTL: agent.promptCacheTTL,
333
340
  ownerRoomId: agent.ownerRoomId,
341
+ toolNames: agent.toolNames,
334
342
  };
335
343
  const filePath = path.join(storageDir, `${agent.id}.json`);
336
344
  fs.writeFileSync(filePath, JSON.stringify(config, null, 2), 'utf-8');
@@ -36,6 +36,7 @@ export declare class Agent {
36
36
  configService: IConfigService;
37
37
  balanceService?: BalanceService;
38
38
  description: string;
39
+ privateContext: string;
39
40
  promptFolder: string;
40
41
  systemInstruction: string;
41
42
  maxHistoryMessages?: number;
@@ -49,6 +50,7 @@ export declare class Agent {
49
50
  attachedArtifacts: string[];
50
51
  isControlledByHuman: boolean;
51
52
  beginInstruction: string;
53
+ toolNames: string[];
52
54
  promptCacheTTL: number;
53
55
  private onStateChange;
54
56
  storageDir: string;
@@ -34,6 +34,7 @@ class Agent {
34
34
  configService;
35
35
  balanceService;
36
36
  description;
37
+ privateContext = '';
37
38
  promptFolder;
38
39
  systemInstruction;
39
40
  maxHistoryMessages;
@@ -47,6 +48,7 @@ class Agent {
47
48
  attachedArtifacts = [];
48
49
  isControlledByHuman = false;
49
50
  beginInstruction = '';
51
+ toolNames = [];
50
52
  promptCacheTTL = 0;
51
53
  onStateChange = null;
52
54
  storageDir;
@@ -89,5 +89,6 @@ function resolveModelInfo(modelName, prefix) {
89
89
  function isKnownModel(modelName, prefix) {
90
90
  if (resolveModelInfo(modelName, prefix) !== null)
91
91
  return true;
92
- return getImageModels().some((m) => m.model === modelName && m.centsPerImage != null);
92
+ return getImageModels().some((m) => (m.generation?.model === modelName && m.generation?.centsPerImage != null) ||
93
+ (m.editing?.model === modelName && m.editing?.centsPerImage != null));
93
94
  }
@@ -33,6 +33,8 @@ const balance_message_service_1 = require("./balance-message.service");
33
33
  const transaction_service_1 = require("./transaction.service");
34
34
  const agent_factory_1 = require("../ai/agent-factory");
35
35
  const room_factory_1 = require("../room/room-factory");
36
+ const tool_store_service_1 = require("../tools/tool-store.service");
37
+ const tool_execution_service_1 = require("../tools/tool-execution.service");
36
38
  let UserServiceFactory = class UserServiceFactory {
37
39
  aiFactoryService;
38
40
  agentMessageService;
@@ -63,11 +65,13 @@ let UserServiceFactory = class UserServiceFactory {
63
65
  const agentStore = new agent_store_service_1.AgentStoreService(this.aiFactoryService, userPaths, attachedFileService, balanceService, artifactService, this.configService);
64
66
  const agentFactory = new agent_factory_1.AgentFactory(this.aiFactoryService, agentStore, userPaths, balanceService, artifactService, this.configService);
65
67
  const artifactStore = new artifact_store_service_1.ArtifactStoreService();
66
- const roomStore = new room_store_service_1.RoomStoreService(userPaths, agentStore, attachedFileService, artifactStore);
67
- const roomFactory = new room_factory_1.RoomFactory(roomStore);
68
+ const toolStore = new tool_store_service_1.ToolStoreService(userPaths);
69
+ const toolExecution = new tool_execution_service_1.ToolExecutionService(toolStore);
70
+ const roomStore = new room_store_service_1.RoomStoreService(userPaths, agentStore, attachedFileService, artifactStore, toolStore, toolExecution);
71
+ const roomFactory = new room_factory_1.RoomFactory(roomStore, toolStore, toolExecution);
68
72
  const storyStore = new story_store_service_1.StoryStoreService(userPaths, roomStore);
69
73
  const storyService = new story_service_1.StoryService(storyStore, agentStore, roomStore, this.storyProgressService, this.storyMessageService, userPaths, agentFactory, roomFactory);
70
- return new app_service_1.AppService(this.aiFactoryService, agentStore, this.agentMessageService, roomStore, this.roomMessageService, userPaths, attachedFileService, artifactService, storyStore, storyService, this.publishedAgentsService, this.publishedRoomsService, balanceService, this.balanceMessageService, transactionService, agentFactory, roomFactory);
74
+ return new app_service_1.AppService(this.aiFactoryService, agentStore, this.agentMessageService, roomStore, this.roomMessageService, userPaths, attachedFileService, artifactService, storyStore, storyService, this.publishedAgentsService, this.publishedRoomsService, balanceService, this.balanceMessageService, transactionService, agentFactory, roomFactory, toolStore, toolExecution);
71
75
  }
72
76
  };
73
77
  exports.UserServiceFactory = UserServiceFactory;
@@ -5,7 +5,7 @@ import { UserServiceManager } from './app/user-service-manager';
5
5
  import { PublishedAgentsService } from './ai/published-agents.service';
6
6
  import { PublishedRoomsService } from './room/published-rooms.service';
7
7
  import { LibraryService } from './library/library.service';
8
- import { AgentInfo, CreateAgentResponse, UpdateAgentRequest, RoomInfo, RoomDetails, CreateRoomResponse, AgentMessagesResponse, RoomMessagesResponse, FileList, PromptFileContent, PromptFoldersResponse, PromptFilesResponse, PromptScope, CreatePromptFolderRequest, CreatePromptFileRequest, UpdatePromptFileRequest, ProcessTextResponse, PreparedPromptResponse, AttachDocumentResponse, StoryInfo, StoryState, Character, ModelInfo, StoryModelDefaults, ChapterInfo, StoryIdea, LibraryPromptsResponse, LibraryFilesResponse, LibraryFileContent, LibraryDefaultUrlResponse, CopyFromLibraryRequest } from '../../shared/types/app.types';
8
+ import { AgentInfo, CreateAgentResponse, UpdateAgentRequest, RoomInfo, RoomDetails, CreateRoomResponse, AgentMessagesResponse, RoomMessagesResponse, FileList, PromptFileContent, PromptFoldersResponse, PromptFilesResponse, PromptScope, CreatePromptFolderRequest, CreatePromptFileRequest, UpdatePromptFileRequest, ProcessTextResponse, PreparedPromptResponse, AttachDocumentResponse, StoryInfo, StoryState, Character, ModelInfo, ImageModelOption, StoryModelDefaults, ChapterInfo, StoryIdea, LibraryPromptsResponse, LibraryFilesResponse, LibraryFileContent, LibraryDefaultUrlResponse, CopyFromLibraryRequest, ToolDefinition, ToolsResponse, ToolRunResult, ToolTestRequest } from '../../shared/types/app.types';
9
9
  import { RoomMessage } from './room/message';
10
10
  export declare class AppController {
11
11
  private readonly userServiceManager;
@@ -16,9 +16,9 @@ export declare class AppController {
16
16
  private getAppService;
17
17
  listServices(req: ExpressRequest): string[];
18
18
  listModels(req: ExpressRequest, aiServiceName: string): Promise<ModelInfo[]>;
19
- listImageModels(req: ExpressRequest): Promise<ModelInfo[]>;
19
+ listImageModels(req: ExpressRequest): Promise<ImageModelOption[]>;
20
20
  listStoryModels(req: ExpressRequest): Promise<ModelInfo[]>;
21
- listStoryModelDefaults(_req: ExpressRequest): StoryModelDefaults;
21
+ listStoryModelDefaults(req: ExpressRequest): Promise<StoryModelDefaults>;
22
22
  createAgent(req: ExpressRequest, body: {
23
23
  aiServiceName: string;
24
24
  agentName: string;
@@ -46,6 +46,11 @@ export declare class AppController {
46
46
  createPromptFile(req: ExpressRequest, folderName: string, body: CreatePromptFileRequest): Promise<void>;
47
47
  updatePromptFile(req: ExpressRequest, folderName: string, fileName: string, body: UpdatePromptFileRequest): Promise<void>;
48
48
  deletePromptFile(req: ExpressRequest, folderName: string, fileName: string): Promise<void>;
49
+ getTools(req: ExpressRequest): Promise<ToolsResponse>;
50
+ createTool(req: ExpressRequest, body: ToolDefinition): Promise<ToolDefinition>;
51
+ updateTool(req: ExpressRequest, name: string, body: ToolDefinition): Promise<ToolDefinition>;
52
+ deleteTool(req: ExpressRequest, name: string): Promise<void>;
53
+ testTool(req: ExpressRequest, name: string, body: ToolTestRequest): Promise<ToolRunResult>;
49
54
  listLibraryPrompts(): LibraryPromptsResponse;
50
55
  listLibraryFiles(folder: string): LibraryFilesResponse;
51
56
  getLibraryFile(folder: string, file: string): LibraryFileContent;
@@ -155,7 +160,7 @@ export declare class AppController {
155
160
  storyModel?: string;
156
161
  isImport?: boolean;
157
162
  imageModelName?: string;
158
- imageEditModelName?: string;
163
+ skipDetailedPlot?: boolean;
159
164
  }): Promise<StoryInfo>;
160
165
  importStoryZip(req: ExpressRequest, file: Express.Multer.File): Promise<StoryInfo>;
161
166
  deleteStory(req: ExpressRequest, storyId: string): Promise<void>;
@@ -197,6 +202,12 @@ export declare class AppController {
197
202
  saveCharacter(req: ExpressRequest, storyId: string, characterName: string, body: {
198
203
  content: string;
199
204
  }): Promise<void>;
205
+ getCharacterInventory(req: ExpressRequest, storyId: string, characterName: string): Promise<{
206
+ content: string;
207
+ }>;
208
+ saveCharacterInventory(req: ExpressRequest, storyId: string, characterName: string, body: {
209
+ content: string;
210
+ }): Promise<void>;
200
211
  getPlotPlan(req: ExpressRequest, storyId: string): Promise<{
201
212
  content: string;
202
213
  }>;