briyah 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/data/common/config/image_models.json +141 -21
- package/data/common/config/image_models_full.json +135 -48
- package/data/common/config/markup +1 -1
- package/data/common/config/story_models.json +41 -38
- package/data/common/prompts/character/progress_character.prompt +4 -0
- package/data/common/prompts/character/update_portrait.prompt +31 -0
- package/data/common/prompts/narrator/perceive.prompt +23 -1
- package/data/common/prompts/narrator/progress_plot.prompt +1 -3
- package/data/common/prompts/story_moderator/moderate.json +36 -29
- package/data/common/prompts/story_moderator/moderate.prompt +63 -18
- package/dist-sdk/server/src/ai/LLM/base-ai.service.d.ts +5 -7
- package/dist-sdk/server/src/ai/LLM/base-ai.service.js +7 -1
- package/dist-sdk/server/src/ai/LLM/fal.service.d.ts +5 -1
- package/dist-sdk/server/src/ai/LLM/fal.service.js +93 -21
- package/dist-sdk/server/src/ai/LLM/googleai.service.d.ts +1 -1
- package/dist-sdk/server/src/ai/LLM/googleai.service.js +20 -29
- package/dist-sdk/server/src/ai/LLM/openai.service.d.ts +5 -1
- package/dist-sdk/server/src/ai/LLM/openai.service.js +58 -71
- package/dist-sdk/server/src/ai/LLM/together.service.d.ts +5 -1
- package/dist-sdk/server/src/ai/LLM/together.service.js +57 -31
- package/dist-sdk/server/src/ai/agent-config.d.ts +1 -0
- package/dist-sdk/server/src/ai/agent-store.service.js +4 -0
- package/dist-sdk/server/src/ai/agent.d.ts +8 -1
- package/dist-sdk/server/src/ai/agent.js +21 -3
- package/dist-sdk/server/src/ai/model_prices.js +21 -1
- package/dist-sdk/server/src/app.controller.d.ts +4 -0
- package/dist-sdk/server/src/app.controller.js +51 -1
- package/dist-sdk/server/src/app.service.d.ts +3 -1
- package/dist-sdk/server/src/app.service.js +22 -14
- package/dist-sdk/server/src/room/message.d.ts +1 -0
- package/dist-sdk/server/src/room/message.js +1 -0
- package/dist-sdk/server/src/room/room-store.service.d.ts +1 -0
- package/dist-sdk/server/src/room/room-store.service.js +3 -0
- package/dist-sdk/server/src/room/room.d.ts +3 -0
- package/dist-sdk/server/src/room/room.js +27 -7
- package/dist-sdk/server/src/story/story-store.service.d.ts +1 -0
- package/dist-sdk/server/src/story/story-store.service.js +38 -0
- package/dist-sdk/server/src/story/story.service.d.ts +4 -1
- package/dist-sdk/server/src/story/story.service.js +233 -55
- package/dist-sdk/shared/types/app.types.d.ts +17 -0
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/Agent.html +19 -15
- package/docs/classes/Briyah.html +12 -12
- package/docs/classes/BriyahConfigService.html +5 -5
- package/docs/classes/Room.html +26 -24
- package/docs/classes/RoomMessage.html +11 -10
- package/docs/enums/MessageAction.html +3 -3
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +15 -3
- package/docs/interfaces/AgentInfo.html +2 -2
- package/docs/interfaces/AgentMessagesResponse.html +2 -2
- package/docs/interfaces/AppService.html +128 -113
- package/docs/interfaces/Artifact.html +3 -3
- package/docs/interfaces/ArtifactMetadata.html +2 -2
- package/docs/interfaces/AttachDocumentResponse.html +2 -2
- package/docs/interfaces/BriyahConfigOptions.html +6 -6
- package/docs/interfaces/ChapterInfo.html +2 -2
- package/docs/interfaces/Character.html +2 -2
- package/docs/interfaces/CreateAgentResponse.html +2 -2
- package/docs/interfaces/CreateRoomResponse.html +2 -2
- package/docs/interfaces/CreateStoryResponse.html +2 -2
- package/docs/interfaces/FileList.html +2 -2
- package/docs/interfaces/LoggingOptions.html +5 -5
- package/docs/interfaces/Message.html +2 -2
- package/docs/interfaces/ModelInfo.html +3 -2
- package/docs/interfaces/PreparedPromptResponse.html +2 -2
- package/docs/interfaces/ProcessTextResponse.html +2 -2
- package/docs/interfaces/PromptFile.html +2 -2
- package/docs/interfaces/PromptFileContent.html +2 -2
- package/docs/interfaces/PromptFilesResponse.html +2 -2
- package/docs/interfaces/PromptFolder.html +2 -2
- package/docs/interfaces/PromptFoldersResponse.html +2 -2
- package/docs/interfaces/RoomDetails.html +2 -2
- package/docs/interfaces/RoomInfo.html +2 -2
- package/docs/interfaces/RoomMessagesResponse.html +2 -2
- package/docs/interfaces/StoryErrorEvent.html +3 -3
- package/docs/interfaces/StoryIdea.html +2 -2
- package/docs/interfaces/StoryInfo.html +5 -3
- package/docs/interfaces/StoryIntroduceCharacterEvent.html +3 -3
- package/docs/interfaces/StoryProgressChapterEvent.html +3 -3
- package/docs/interfaces/StoryState.html +5 -5
- package/docs/interfaces/StoryStateEvent.html +3 -3
- package/docs/interfaces/Transaction.html +2 -2
- package/docs/interfaces/TransactionHistoryResponse.html +2 -2
- package/docs/modules.html +1 -1
- package/docs/types/PromptScope.html +1 -1
- package/package.json +1 -1
|
@@ -345,6 +345,44 @@ let StoryStoreService = class StoryStoreService {
|
|
|
345
345
|
return false;
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
|
+
restoreRoomFilesFromChapter(storyId, chapterIndex) {
|
|
349
|
+
const storyFolder = path.join(this.storiesDir, storyId);
|
|
350
|
+
const chapterFolder = path.join(storyFolder, 'chapters', `chapter_${chapterIndex}`);
|
|
351
|
+
try {
|
|
352
|
+
const story = this.getStory(storyId);
|
|
353
|
+
if (!story || !story.roomId) {
|
|
354
|
+
logger_1.logger.error(`Cannot restore room files: story ${storyId} has no room ID`);
|
|
355
|
+
return -1;
|
|
356
|
+
}
|
|
357
|
+
if (!fs.existsSync(chapterFolder)) {
|
|
358
|
+
logger_1.logger.warn(`Chapter ${chapterIndex} folder not found for story ${storyId}`);
|
|
359
|
+
return -1;
|
|
360
|
+
}
|
|
361
|
+
const roomFolder = path.join(storyFolder, 'rooms', story.roomId);
|
|
362
|
+
if (!fs.existsSync(roomFolder)) {
|
|
363
|
+
fs.mkdirSync(roomFolder, { recursive: true });
|
|
364
|
+
}
|
|
365
|
+
const items = fs.readdirSync(chapterFolder);
|
|
366
|
+
let restored = 0;
|
|
367
|
+
for (const item of items) {
|
|
368
|
+
if (item === 'metadata.json' || item === 'agents') {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
const sourcePath = path.join(chapterFolder, item);
|
|
372
|
+
const targetPath = path.join(roomFolder, item);
|
|
373
|
+
if (fs.statSync(sourcePath).isFile()) {
|
|
374
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
375
|
+
restored++;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
logger_1.logger.log(`Restored ${restored} room files from chapter ${chapterIndex} for story ${storyId}`);
|
|
379
|
+
return restored;
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
logger_1.logger.error(`Error restoring room files from chapter ${chapterIndex} for story ${storyId}:`, error);
|
|
383
|
+
return -1;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
348
386
|
async restoreAgentsFromChapter(storyId, chapterIndex, agentStore) {
|
|
349
387
|
const storyFolder = path.join(this.storiesDir, storyId);
|
|
350
388
|
const chapterAgentsFolder = path.join(storyFolder, 'chapters', `chapter_${chapterIndex}`, 'agents');
|
|
@@ -36,7 +36,7 @@ export declare class StoryService {
|
|
|
36
36
|
private getStoryRoom;
|
|
37
37
|
private ensureStoryLoaded;
|
|
38
38
|
getStoryInfo(storyId: string): Promise<StoryInfo | null>;
|
|
39
|
-
createStory(name: string, idea: string, userCharacterDesc: string, otherCharactersDesc: string, storyModel?: string, isImport?: boolean, imageModelName?: string): Promise<StoryInfo>;
|
|
39
|
+
createStory(name: string, idea: string, userCharacterDesc: string, otherCharactersDesc: string, illustrateStory: boolean, storyModel?: string, isImport?: boolean, imageModelName?: string, imageEditModelName?: string): Promise<StoryInfo>;
|
|
40
40
|
private createStoryAsync;
|
|
41
41
|
generateCharacterPortraits(storyInfo: StoryInfo, room: Room): Promise<void>[];
|
|
42
42
|
generateOpeningSceneImage(storyInfo: StoryInfo, room: Room): Promise<{
|
|
@@ -56,6 +56,7 @@ export declare class StoryService {
|
|
|
56
56
|
savePlotPlan(storyId: string, content: string): Promise<void>;
|
|
57
57
|
publishArtifact(storyId: string, name: string, creator: string, body: string, viewers: string[]): Promise<void>;
|
|
58
58
|
respondToStory(storyId: string, content: string): Promise<void>;
|
|
59
|
+
interruptStory(storyId: string): Promise<void>;
|
|
59
60
|
introduceCharacter(storyId: string, characterName: string, characterDescription: string, storyModel?: string, fromNarratorSuggestion?: boolean): Promise<void>;
|
|
60
61
|
declineCharacter(storyId: string, characterName: string): Promise<void>;
|
|
61
62
|
deleteCharacter(storyId: string, characterName: string): Promise<void>;
|
|
@@ -70,6 +71,7 @@ export declare class StoryService {
|
|
|
70
71
|
progressStoryToNextChapter(storyId: string): Promise<{
|
|
71
72
|
chapterIndex: number;
|
|
72
73
|
}>;
|
|
74
|
+
revertStoryChapter(storyId: string): Promise<void>;
|
|
73
75
|
private progressStoryToNextChapterAsync;
|
|
74
76
|
private generateOpeningScene;
|
|
75
77
|
private compactAgentHistories;
|
|
@@ -79,6 +81,7 @@ export declare class StoryService {
|
|
|
79
81
|
private getImageModelConfig;
|
|
80
82
|
private createArtistAgent;
|
|
81
83
|
private generateCharacterPortrait;
|
|
84
|
+
private updateCharacterPortrait;
|
|
82
85
|
private generateSceneIllustration;
|
|
83
86
|
private generateSceneReference;
|
|
84
87
|
private generateStoryImage;
|
|
@@ -191,6 +191,7 @@ let StoryService = class StoryService {
|
|
|
191
191
|
return {
|
|
192
192
|
service: modelConfig.service,
|
|
193
193
|
model: modelConfig.model,
|
|
194
|
+
smallModel: modelConfig.small_model,
|
|
194
195
|
};
|
|
195
196
|
}
|
|
196
197
|
logger_1.logger.warn(`Story model "${storyModel}" not found in story_models.json`);
|
|
@@ -240,6 +241,21 @@ let StoryService = class StoryService {
|
|
|
240
241
|
room.setOnSituationUpdate((situation) => {
|
|
241
242
|
this.updateStorySituation(storyId, situation);
|
|
242
243
|
});
|
|
244
|
+
room.setOnModeratorResponse((message) => {
|
|
245
|
+
if (message.updatePortrait?.length) {
|
|
246
|
+
for (const nickname of message.updatePortrait) {
|
|
247
|
+
const characterAgent = room
|
|
248
|
+
.getAgents()
|
|
249
|
+
.find((a) => a.agentNickname === nickname);
|
|
250
|
+
if (characterAgent) {
|
|
251
|
+
this.updateCharacterPortrait(room, characterAgent, storyId).catch((e) => logger_1.logger.error(`Error updating portrait for ${nickname}:`, e));
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
logger_1.logger.warn(`update_portrait: agent "${nickname}" not found in room`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
});
|
|
243
259
|
if (story.situation) {
|
|
244
260
|
room.setSituation(story.situation);
|
|
245
261
|
}
|
|
@@ -249,7 +265,7 @@ let StoryService = class StoryService {
|
|
|
249
265
|
async getStoryInfo(storyId) {
|
|
250
266
|
return this.storyStore.getStory(storyId);
|
|
251
267
|
}
|
|
252
|
-
async createStory(name, idea, userCharacterDesc, otherCharactersDesc, storyModel, isImport = false, imageModelName) {
|
|
268
|
+
async createStory(name, idea, userCharacterDesc, otherCharactersDesc, illustrateStory, storyModel, isImport = false, imageModelName, imageEditModelName) {
|
|
253
269
|
if (!name || name.trim().length === 0) {
|
|
254
270
|
throw new Error('Story name is required');
|
|
255
271
|
}
|
|
@@ -280,7 +296,18 @@ let StoryService = class StoryService {
|
|
|
280
296
|
moderator.markupRate = 0;
|
|
281
297
|
moderator.save();
|
|
282
298
|
logger_1.logger.log(`Created moderator agent: ${moderator.agentName}`);
|
|
299
|
+
if (illustrateStory) {
|
|
300
|
+
if (!imageModelName)
|
|
301
|
+
imageModelName = process.env.DEFAULT_IMAGE_MODEL;
|
|
302
|
+
if (!imageEditModelName)
|
|
303
|
+
imageEditModelName = process.env.DEFAULT_IMAGE_EDIT_MODEL;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
imageModelName = undefined;
|
|
307
|
+
imageEditModelName = undefined;
|
|
308
|
+
}
|
|
283
309
|
const artist = this.createArtistAgent(storyInfo.id, storyAgentsDir, storyArtifactService, imageModelName);
|
|
310
|
+
const artistEdit = this.createArtistAgent(storyInfo.id, storyAgentsDir, storyArtifactService, imageEditModelName, 'Artist (Edit)');
|
|
284
311
|
let illustrator = null;
|
|
285
312
|
if (artist) {
|
|
286
313
|
illustrator = this.agentFactory.createAgent(process.env.MODERATOR_AI_SERVICE || aiServiceName, `${storyTitle} - Illustrator`, 'Illustrator', 'Visual artist for generating scene illustrations', 'illustrator', process.env.MODERATOR_AI_MODEL || aiModelName, storyAgentsDir, storyArtifactService);
|
|
@@ -295,6 +322,7 @@ let StoryService = class StoryService {
|
|
|
295
322
|
narrator.allowSearch = true;
|
|
296
323
|
narrator.promptCacheTTL = 60;
|
|
297
324
|
narrator.ownerRoomId = storyInfo.id;
|
|
325
|
+
narrator.smallModelName = modelConfig.smallModel;
|
|
298
326
|
narrator.save();
|
|
299
327
|
logger_1.logger.log(`Created narrator agent: ${narrator.agentName}`);
|
|
300
328
|
narrator.disableMarkup = true;
|
|
@@ -348,6 +376,7 @@ let StoryService = class StoryService {
|
|
|
348
376
|
userAgent = this.agentFactory.createAgent(aiServiceName, `${name} - ${userNickname}`, userNickname, userCharacterInfo.description || userCharacterDesc, 'character', aiModelName, storyAgentsDir, storyArtifactService);
|
|
349
377
|
userAgent.isControlledByHuman = true;
|
|
350
378
|
userAgent.ownerRoomId = storyInfo.id;
|
|
379
|
+
userAgent.smallModelName = modelConfig.smallModel;
|
|
351
380
|
userAgent.save();
|
|
352
381
|
logger_1.logger.log(`Created human-controlled character agent: ${userCharacterName}`);
|
|
353
382
|
userAgent.disableMarkup = true;
|
|
@@ -366,6 +395,7 @@ let StoryService = class StoryService {
|
|
|
366
395
|
const agent = this.agentFactory.createAgent(aiServiceName, `${name} - ${characterNickname}`, characterNickname, charInfo.description, 'character', aiModelName, storyAgentsDir, storyArtifactService);
|
|
367
396
|
agent.promptCacheTTL = 60;
|
|
368
397
|
agent.ownerRoomId = storyInfo.id;
|
|
398
|
+
agent.smallModelName = modelConfig.smallModel;
|
|
369
399
|
agent.save();
|
|
370
400
|
logger_1.logger.log(`Created character agent: ${charInfo.name}`);
|
|
371
401
|
agent.disableMarkup = true;
|
|
@@ -409,11 +439,28 @@ let StoryService = class StoryService {
|
|
|
409
439
|
room.setOnSituationUpdate((situation) => {
|
|
410
440
|
this.updateStorySituation(storyInfo.id, situation);
|
|
411
441
|
});
|
|
442
|
+
room.setOnModeratorResponse((message) => {
|
|
443
|
+
if (message.updatePortrait?.length) {
|
|
444
|
+
for (const nickname of message.updatePortrait) {
|
|
445
|
+
const characterAgent = room
|
|
446
|
+
.getAgents()
|
|
447
|
+
.find((a) => a.agentNickname === nickname);
|
|
448
|
+
if (characterAgent) {
|
|
449
|
+
this.updateCharacterPortrait(room, characterAgent, storyInfo.id).catch((e) => logger_1.logger.error(`Error updating portrait for ${nickname}:`, e));
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
logger_1.logger.warn(`update_portrait: agent "${nickname}" not found in room`);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
});
|
|
412
457
|
storyInfo.roomId = roomId;
|
|
413
458
|
storyInfo.moderatorAgentId = moderator.id;
|
|
414
459
|
storyInfo.illustratorAgentId = illustrator?.id;
|
|
415
460
|
storyInfo.artistAgentId = artist?.id;
|
|
461
|
+
storyInfo.artistEditAgentId = artistEdit?.id;
|
|
416
462
|
storyInfo.imageModelName = imageModelName;
|
|
463
|
+
storyInfo.imageEditModelName = imageEditModelName;
|
|
417
464
|
if (userAgent) {
|
|
418
465
|
storyInfo.userAgentId = userAgent.id;
|
|
419
466
|
}
|
|
@@ -936,6 +983,10 @@ let StoryService = class StoryService {
|
|
|
936
983
|
const responseMessage = new message_1.RoomMessage(humanAgent.agentNickname, app_types_1.MessageAction.MODERATE, content, [], null);
|
|
937
984
|
room.addPendingMessage(responseMessage);
|
|
938
985
|
}
|
|
986
|
+
async interruptStory(storyId) {
|
|
987
|
+
const room = await this.getStoryRoom(storyId);
|
|
988
|
+
room.interrupt();
|
|
989
|
+
}
|
|
939
990
|
async introduceCharacter(storyId, characterName, characterDescription, storyModel, fromNarratorSuggestion) {
|
|
940
991
|
const room = await this.getStoryRoom(storyId);
|
|
941
992
|
if (!characterName)
|
|
@@ -970,6 +1021,7 @@ let StoryService = class StoryService {
|
|
|
970
1021
|
const characterNickname = characterName.trim().split(/\s+/)[0];
|
|
971
1022
|
const characterAgent = this.agentFactory.createAgent(aiServiceName, `${storyTitle} - ${characterNickname}`, characterNickname, characterDescription, 'character', aiModelName, storyAgentsDir, storyArtifactService);
|
|
972
1023
|
characterAgent.promptCacheTTL = 60;
|
|
1024
|
+
characterAgent.smallModelName = modelConfig.smallModel;
|
|
973
1025
|
characterAgent.save();
|
|
974
1026
|
room.arrive(characterAgent);
|
|
975
1027
|
const introducedCharArtifacts = room.getArtifacts();
|
|
@@ -1238,6 +1290,49 @@ let StoryService = class StoryService {
|
|
|
1238
1290
|
throw err;
|
|
1239
1291
|
}
|
|
1240
1292
|
}
|
|
1293
|
+
async revertStoryChapter(storyId) {
|
|
1294
|
+
const story = this.storyStore.getStory(storyId);
|
|
1295
|
+
if (!story || !story.roomId) {
|
|
1296
|
+
throw new errors_1.NotFoundError('Story not found');
|
|
1297
|
+
}
|
|
1298
|
+
const room = await this.getStoryRoom(storyId);
|
|
1299
|
+
if (!room) {
|
|
1300
|
+
throw new errors_1.NotFoundError('Story room not found');
|
|
1301
|
+
}
|
|
1302
|
+
if (this.chaptersInProgress.has(storyId)) {
|
|
1303
|
+
throw new errors_1.OperationFailedError('Chapter progression is in progress; cannot revert');
|
|
1304
|
+
}
|
|
1305
|
+
const chapters = this.storyStore.listChapters(storyId);
|
|
1306
|
+
if (chapters.length === 0) {
|
|
1307
|
+
throw new errors_1.OperationFailedError('No previous chapter to revert to');
|
|
1308
|
+
}
|
|
1309
|
+
const liveMessages = room.getLatestRoomMessages(0, true);
|
|
1310
|
+
const nonOpening = liveMessages.filter((m) => m.sender !== 'Opening Scene' || m.action !== app_types_1.MessageAction.SYSTEM);
|
|
1311
|
+
if (nonOpening.length > 0) {
|
|
1312
|
+
throw new errors_1.OperationFailedError('Cannot revert: chapter has progressed past the opening scene');
|
|
1313
|
+
}
|
|
1314
|
+
const targetChapter = Math.max(...chapters.map((c) => c.chapterNum));
|
|
1315
|
+
await this.storyStore.restoreAgentsFromChapter(storyId, targetChapter, this.agentStore);
|
|
1316
|
+
const restoredCount = this.storyStore.restoreRoomFilesFromChapter(storyId, targetChapter);
|
|
1317
|
+
if (restoredCount < 0) {
|
|
1318
|
+
throw new errors_1.OperationFailedError(`Failed to restore room files from chapter ${targetChapter}`);
|
|
1319
|
+
}
|
|
1320
|
+
const storageDir = room.getStorageDir();
|
|
1321
|
+
const messagesPath = path.join(storageDir, story.roomId, 'messages');
|
|
1322
|
+
const restoredMessages = await this.roomStore.readRoomMessagesFromFileAsync(messagesPath);
|
|
1323
|
+
room.setRoomMessages(restoredMessages || []);
|
|
1324
|
+
const restoredArtifacts = this.roomStore.loadArtifactFiles(story.roomId, storageDir);
|
|
1325
|
+
room.setArtifacts(restoredArtifacts);
|
|
1326
|
+
const humanAgent = room.getAgents().find((a) => a.isControlledByHuman);
|
|
1327
|
+
if (humanAgent) {
|
|
1328
|
+
room.setCurrentSpeaker(humanAgent.agentNickname);
|
|
1329
|
+
}
|
|
1330
|
+
const deleted = this.storyStore.deleteChapter(storyId, targetChapter);
|
|
1331
|
+
if (!deleted) {
|
|
1332
|
+
logger_1.logger.warn(`Reverted chapter ${targetChapter} for story ${storyId} but failed to delete backup directory`);
|
|
1333
|
+
}
|
|
1334
|
+
logger_1.logger.log(`Reverted story ${storyId} to chapter ${targetChapter} (${restoredMessages?.length ?? 0} messages, ${restoredArtifacts.length} artifacts)`);
|
|
1335
|
+
}
|
|
1241
1336
|
async progressStoryToNextChapterAsync(storyId) {
|
|
1242
1337
|
let room = null;
|
|
1243
1338
|
let agents = [];
|
|
@@ -1322,12 +1417,12 @@ let StoryService = class StoryService {
|
|
|
1322
1417
|
const artifacts = room.getArtifacts();
|
|
1323
1418
|
const plotPlanArtifact = artifacts.find((a) => a.name === 'Plot Plan');
|
|
1324
1419
|
const currentPlotPlan = plotPlanArtifact ? plotPlanArtifact.body : 'No plot plan found.';
|
|
1325
|
-
const
|
|
1420
|
+
const previousAllowSearch = narrator.allowSearch;
|
|
1421
|
+
narrator.allowSearch = true;
|
|
1326
1422
|
try {
|
|
1327
|
-
const progressPlotResponse = await narrator.preparedPrompt('progress_plot', {
|
|
1423
|
+
const progressPlotResponse = await narrator.withSmallModel(() => narrator.preparedPrompt('progress_plot', {
|
|
1328
1424
|
currentPlotPlan: currentPlotPlan,
|
|
1329
|
-
|
|
1330
|
-
}, false);
|
|
1425
|
+
}, false));
|
|
1331
1426
|
if (progressPlotResponse) {
|
|
1332
1427
|
const cleanedPlotPlan = this.extractMarkdownContent(progressPlotResponse);
|
|
1333
1428
|
room.publishArtifact('Plot Plan', narrator.agentNickname, cleanedPlotPlan, [
|
|
@@ -1340,6 +1435,9 @@ let StoryService = class StoryService {
|
|
|
1340
1435
|
catch (error) {
|
|
1341
1436
|
logger_1.logger.error(`Error updating plot plan:`, error);
|
|
1342
1437
|
}
|
|
1438
|
+
finally {
|
|
1439
|
+
narrator.allowSearch = previousAllowSearch;
|
|
1440
|
+
}
|
|
1343
1441
|
return '';
|
|
1344
1442
|
}
|
|
1345
1443
|
async updateCharacterProfiles(room, characterAgents, plotPlan = '') {
|
|
@@ -1348,21 +1446,22 @@ let StoryService = class StoryService {
|
|
|
1348
1446
|
try {
|
|
1349
1447
|
const profileArtifact = artifacts.find((a) => a.name === `Character Profile - ${character.agentNickname}`);
|
|
1350
1448
|
let currentProfile = profileArtifact ? profileArtifact.body : null;
|
|
1351
|
-
let formattedHistory =
|
|
1449
|
+
let formattedHistory = [];
|
|
1450
|
+
const hasNativeHistory = (character.history?.length ?? 0) > 0;
|
|
1451
|
+
if (!hasNativeHistory) {
|
|
1452
|
+
formattedHistory = room
|
|
1453
|
+
.getLatestRoomMessages(0, true)
|
|
1454
|
+
.map((m) => `${m.sender}: ${m.content}\n`);
|
|
1455
|
+
}
|
|
1352
1456
|
if (!currentProfile) {
|
|
1353
1457
|
currentProfile = `There is not yet a character profile for ${character.agentNickname}. Use the updated plot plan and recent story messages to create a character profile.`;
|
|
1354
|
-
if (!formattedHistory || formattedHistory.length === 0) {
|
|
1355
|
-
formattedHistory = room
|
|
1356
|
-
.getLatestRoomMessages(0, true)
|
|
1357
|
-
.map((m) => `${m.sender}: ${m.content}\n`);
|
|
1358
|
-
}
|
|
1359
1458
|
}
|
|
1360
|
-
const progressCharacterResponse = await character.preparedPrompt('progress_character', {
|
|
1459
|
+
const progressCharacterResponse = await character.withSmallModel(() => character.preparedPrompt('progress_character', {
|
|
1361
1460
|
agentName: character.agentNickname,
|
|
1362
1461
|
currentProfile: currentProfile,
|
|
1363
1462
|
formattedHistory: formattedHistory,
|
|
1364
1463
|
plotPlan,
|
|
1365
|
-
}, false);
|
|
1464
|
+
}, false));
|
|
1366
1465
|
if (progressCharacterResponse.description) {
|
|
1367
1466
|
character.description = progressCharacterResponse.description;
|
|
1368
1467
|
character.save();
|
|
@@ -1375,37 +1474,30 @@ let StoryService = class StoryService {
|
|
|
1375
1474
|
});
|
|
1376
1475
|
await Promise.all(updatePromises);
|
|
1377
1476
|
logger_1.logger.log(`Updated ${characterAgents.length} character profiles in parallel`);
|
|
1378
|
-
const
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1477
|
+
const pathParts = room.getStorageDir().split(path.sep);
|
|
1478
|
+
const storiesIndex = pathParts.findIndex((p) => p === 'stories');
|
|
1479
|
+
const storyId = storiesIndex >= 0 ? pathParts[storiesIndex + 1] : null;
|
|
1480
|
+
if (!storyId) {
|
|
1481
|
+
logger_1.logger.error('Could not extract story ID from room path; skipping portrait updates');
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
const portraitPromises = characterAgents.map(async (characterAgent) => {
|
|
1485
|
+
try {
|
|
1486
|
+
const artifactId = await this.updateCharacterPortrait(room, characterAgent, storyId);
|
|
1487
|
+
return {
|
|
1488
|
+
character: characterAgent.agentNickname,
|
|
1489
|
+
success: !!artifactId,
|
|
1490
|
+
artifactId,
|
|
1491
|
+
};
|
|
1386
1492
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
const oldPortrait = oldArtifacts.find((a) => a.name === oldPortraitName);
|
|
1391
|
-
if (oldPortrait) {
|
|
1392
|
-
storyArtifactService.deleteArtifact(oldPortrait.artifactId);
|
|
1393
|
-
logger_1.logger.log(`Deleted old portrait for ${characterAgent.agentName}`);
|
|
1493
|
+
catch (error) {
|
|
1494
|
+
logger_1.logger.error(`Error updating portrait for ${characterAgent.agentName}:`, error);
|
|
1495
|
+
return { character: characterAgent.agentNickname, success: false, error };
|
|
1394
1496
|
}
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
artifactId,
|
|
1400
|
-
};
|
|
1401
|
-
}
|
|
1402
|
-
catch (error) {
|
|
1403
|
-
logger_1.logger.error(`Error regenerating portrait for ${characterAgent.agentName}:`, error);
|
|
1404
|
-
return { character: characterAgent.agentNickname, success: false, error };
|
|
1405
|
-
}
|
|
1406
|
-
});
|
|
1407
|
-
await Promise.all(portraitPromises);
|
|
1408
|
-
logger_1.logger.log(`Regenerated portraits for ${characterAgents.length} characters`);
|
|
1497
|
+
});
|
|
1498
|
+
await Promise.all(portraitPromises);
|
|
1499
|
+
logger_1.logger.log(`Updated portraits for ${characterAgents.length} characters`);
|
|
1500
|
+
}
|
|
1409
1501
|
}
|
|
1410
1502
|
getImageModelConfig(modelName) {
|
|
1411
1503
|
try {
|
|
@@ -1423,23 +1515,32 @@ let StoryService = class StoryService {
|
|
|
1423
1515
|
logger_1.logger.log(`Images disabled: selected "${modelName}"`);
|
|
1424
1516
|
return null;
|
|
1425
1517
|
}
|
|
1426
|
-
return {
|
|
1518
|
+
return {
|
|
1519
|
+
service: modelConfig.service,
|
|
1520
|
+
model: modelConfig.model,
|
|
1521
|
+
imageProperties: modelConfig.imageProperties,
|
|
1522
|
+
centsPerImage: modelConfig.centsPerImage,
|
|
1523
|
+
};
|
|
1427
1524
|
}
|
|
1428
1525
|
catch (error) {
|
|
1429
1526
|
logger_1.logger.error('Error loading image model config:', error);
|
|
1430
1527
|
return null;
|
|
1431
1528
|
}
|
|
1432
1529
|
}
|
|
1433
|
-
createArtistAgent(storyId, storyAgentsDir, storyArtifactService, imageModelName) {
|
|
1530
|
+
createArtistAgent(storyId, storyAgentsDir, storyArtifactService, imageModelName, nickname = 'Artist') {
|
|
1434
1531
|
const storyInfo = this.storyStore.getStory(storyId);
|
|
1435
1532
|
const imageConfig = this.getImageModelConfig(imageModelName);
|
|
1436
1533
|
if (!imageConfig) {
|
|
1437
|
-
logger_1.logger.log(
|
|
1534
|
+
logger_1.logger.log(`Artist agent creation skipped (${nickname}): images disabled`);
|
|
1438
1535
|
return null;
|
|
1439
1536
|
}
|
|
1440
|
-
const artistAgent = this.agentFactory.createAgent(imageConfig.service, `${storyInfo.name} -
|
|
1537
|
+
const artistAgent = this.agentFactory.createAgent(imageConfig.service, `${storyInfo.name} - ${nickname}`, nickname, 'AI artist for generating character portraits and scene illustrations', 'default', imageConfig.model, storyAgentsDir, storyArtifactService);
|
|
1441
1538
|
artistAgent.maxHistoryMessages = 10;
|
|
1442
1539
|
artistAgent.promptCacheTTL = 0;
|
|
1540
|
+
artistAgent.imageProperties = {
|
|
1541
|
+
...(imageConfig?.imageProperties ?? {}),
|
|
1542
|
+
...(imageConfig?.centsPerImage != null ? { centsPerImage: imageConfig.centsPerImage } : {}),
|
|
1543
|
+
};
|
|
1443
1544
|
artistAgent.save();
|
|
1444
1545
|
logger_1.logger.log(`Created artist agent: ${artistAgent.agentName} (${imageConfig.service}/${imageConfig.model})`);
|
|
1445
1546
|
return artistAgent;
|
|
@@ -1456,11 +1557,13 @@ let StoryService = class StoryService {
|
|
|
1456
1557
|
logger_1.logger.warn(`No profile for ${characterAgent.agentNickname}, skipping portrait`);
|
|
1457
1558
|
return null;
|
|
1458
1559
|
}
|
|
1560
|
+
const storyArtifactService = this.getStoryArtifactService(storyId);
|
|
1459
1561
|
const artistAgent = await this.agentStore.getAgent(storyInfo.artistAgentId);
|
|
1460
1562
|
if (!artistAgent) {
|
|
1461
1563
|
logger_1.logger.warn(`Artist agent not found: ${storyInfo.artistAgentId}`);
|
|
1462
1564
|
return null;
|
|
1463
1565
|
}
|
|
1566
|
+
artistAgent.artifactService = storyArtifactService;
|
|
1464
1567
|
const visualDescription = await characterAgent.preparedPrompt('describe_character', {
|
|
1465
1568
|
characterName: characterAgent.agentNickname,
|
|
1466
1569
|
characterProfile: characterDescription,
|
|
@@ -1470,13 +1573,12 @@ let StoryService = class StoryService {
|
|
|
1470
1573
|
logger_1.logger.warn(`Failed to generate visual description for ${characterAgent.agentNickname}`);
|
|
1471
1574
|
return null;
|
|
1472
1575
|
}
|
|
1473
|
-
const imageResult = await artistAgent.generateImage(visualDescription
|
|
1576
|
+
const imageResult = await artistAgent.generateImage(visualDescription);
|
|
1474
1577
|
if (imageResult.error) {
|
|
1475
1578
|
return null;
|
|
1476
1579
|
}
|
|
1477
1580
|
artistAgent.save();
|
|
1478
1581
|
const artifactId = imageResult.artifactId;
|
|
1479
|
-
let storyArtifactService = this.getStoryArtifactService(storyId);
|
|
1480
1582
|
storyArtifactService.renameArtifact(artifactId, `Portrait - ${characterAgent.agentNickname}`);
|
|
1481
1583
|
storyArtifactService.updateArtifactDescription(artifactId, visualDescription);
|
|
1482
1584
|
logger_1.logger.log(`Generated portrait for ${characterAgent.agentNickname}: ${artifactId}`);
|
|
@@ -1487,7 +1589,66 @@ let StoryService = class StoryService {
|
|
|
1487
1589
|
return null;
|
|
1488
1590
|
}
|
|
1489
1591
|
}
|
|
1490
|
-
async
|
|
1592
|
+
async updateCharacterPortrait(room, characterAgent, storyId) {
|
|
1593
|
+
try {
|
|
1594
|
+
const artifacts = room.getArtifacts();
|
|
1595
|
+
const profileArtifact = artifacts.find((a) => a.name === `Character Profile - ${characterAgent.agentNickname}`);
|
|
1596
|
+
const storyInfo = this.storyStore.getStory(storyId);
|
|
1597
|
+
const scenario = storyInfo?.scenario || '';
|
|
1598
|
+
const character = storyInfo.characters.find((c) => c.name === characterAgent.agentNickname);
|
|
1599
|
+
let characterDescription = profileArtifact?.body || character?.description || '';
|
|
1600
|
+
if (!characterDescription) {
|
|
1601
|
+
logger_1.logger.warn(`No profile for ${characterAgent.agentNickname}, skipping portrait update`);
|
|
1602
|
+
return null;
|
|
1603
|
+
}
|
|
1604
|
+
const storyArtifactService = this.getStoryArtifactService(storyId);
|
|
1605
|
+
if (!storyInfo.artistEditAgentId) {
|
|
1606
|
+
logger_1.logger.warn(`No edit artist configured for story ${storyId}, skipping portrait update`);
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
const artistEditAgent = await this.agentStore.getAgent(storyInfo.artistEditAgentId);
|
|
1610
|
+
if (!artistEditAgent) {
|
|
1611
|
+
logger_1.logger.warn(`Edit artist agent not found: ${storyInfo.artistEditAgentId}`);
|
|
1612
|
+
return null;
|
|
1613
|
+
}
|
|
1614
|
+
artistEditAgent.artifactService = storyArtifactService;
|
|
1615
|
+
const portraitName = `Portrait - ${characterAgent.agentNickname}`;
|
|
1616
|
+
const existingPortrait = storyArtifactService
|
|
1617
|
+
.listArtifacts()
|
|
1618
|
+
.find((a) => a.name === portraitName);
|
|
1619
|
+
if (!existingPortrait) {
|
|
1620
|
+
logger_1.logger.warn(`No existing portrait for ${characterAgent.agentNickname}, cannot update`);
|
|
1621
|
+
return null;
|
|
1622
|
+
}
|
|
1623
|
+
const visualDescription = await characterAgent.preparedPrompt('update_portrait', {
|
|
1624
|
+
characterName: characterAgent.agentNickname,
|
|
1625
|
+
characterProfile: characterDescription,
|
|
1626
|
+
scenario: scenario,
|
|
1627
|
+
}, false);
|
|
1628
|
+
if (!visualDescription || typeof visualDescription !== 'string') {
|
|
1629
|
+
logger_1.logger.warn(`Failed to generate update description for ${characterAgent.agentNickname}`);
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
const imageResult = await artistEditAgent.editImage(visualDescription, [
|
|
1633
|
+
existingPortrait.artifactId,
|
|
1634
|
+
]);
|
|
1635
|
+
if (imageResult.error) {
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
storyArtifactService.deleteArtifact(existingPortrait.artifactId);
|
|
1639
|
+
artistEditAgent.save();
|
|
1640
|
+
const artifactId = imageResult.artifactId;
|
|
1641
|
+
storyArtifactService.renameArtifact(artifactId, portraitName);
|
|
1642
|
+
storyArtifactService.updateArtifactDescription(artifactId, visualDescription);
|
|
1643
|
+
logger_1.logger.log(`Updated portrait for ${characterAgent.agentNickname}: ${artifactId}`);
|
|
1644
|
+
return artifactId;
|
|
1645
|
+
}
|
|
1646
|
+
catch (error) {
|
|
1647
|
+
logger_1.logger.error(`Error updating portrait for ${characterAgent.agentNickname}:`, error);
|
|
1648
|
+
return null;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
async generateSceneIllustration(storyId, situation, allowReference = true) {
|
|
1491
1652
|
try {
|
|
1492
1653
|
const story = this.storyStore.getStory(storyId);
|
|
1493
1654
|
if (!story?.illustratorAgentId) {
|
|
@@ -1529,8 +1690,12 @@ let StoryService = class StoryService {
|
|
|
1529
1690
|
return;
|
|
1530
1691
|
}
|
|
1531
1692
|
if (sceneAnalysis.isReference) {
|
|
1693
|
+
if (!allowReference) {
|
|
1694
|
+
logger_1.logger.warn(`Illustrator requested another reference (${sceneAnalysis.sceneName}) after one was just created; skipping to avoid loop`);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1532
1697
|
await this.generateSceneReference(storyId, sceneAnalysis.sceneName, sceneAnalysis.sceneDescription);
|
|
1533
|
-
await this.generateSceneIllustration(storyId, situation);
|
|
1698
|
+
await this.generateSceneIllustration(storyId, situation, false);
|
|
1534
1699
|
}
|
|
1535
1700
|
else {
|
|
1536
1701
|
await this.generateStoryImage(storyId, story.turnNumber, sceneAnalysis.imageCaption, sceneAnalysis.sceneName, sceneAnalysis.sceneDescription, sceneAnalysis.characterNames);
|
|
@@ -1553,12 +1718,13 @@ let StoryService = class StoryService {
|
|
|
1553
1718
|
logger_1.logger.error(`Artist agent not found: ${storyInfo.artistAgentId}`);
|
|
1554
1719
|
return;
|
|
1555
1720
|
}
|
|
1556
|
-
|
|
1721
|
+
const storyArtifactService = this.getStoryArtifactService(storyId);
|
|
1557
1722
|
if (!storyArtifactService) {
|
|
1558
1723
|
logger_1.logger.error(`Story artifact service not found: ${storyId}`);
|
|
1559
1724
|
return;
|
|
1560
1725
|
}
|
|
1561
|
-
|
|
1726
|
+
artistAgent.artifactService = storyArtifactService;
|
|
1727
|
+
const imageResult = await artistAgent.generateImage(sceneDescription);
|
|
1562
1728
|
if (imageResult.error) {
|
|
1563
1729
|
return;
|
|
1564
1730
|
}
|
|
@@ -1603,9 +1769,16 @@ let StoryService = class StoryService {
|
|
|
1603
1769
|
logger_1.logger.error(`Artist agent not found: ${storyInfo.artistAgentId}`);
|
|
1604
1770
|
return;
|
|
1605
1771
|
}
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1772
|
+
artistAgent.artifactService = storyArtifactService;
|
|
1773
|
+
const editAgent = storyInfo.artistEditAgentId
|
|
1774
|
+
? await this.agentStore.getAgent(storyInfo.artistEditAgentId)
|
|
1775
|
+
: null;
|
|
1776
|
+
if (editAgent) {
|
|
1777
|
+
editAgent.artifactService = storyArtifactService;
|
|
1778
|
+
}
|
|
1779
|
+
const imageResult = referenceImageIds?.length && editAgent
|
|
1780
|
+
? await editAgent.editImage(sceneDescription, referenceImageIds)
|
|
1781
|
+
: await artistAgent.generateImage(sceneDescription);
|
|
1609
1782
|
if (imageResult.error) {
|
|
1610
1783
|
return;
|
|
1611
1784
|
}
|
|
@@ -1654,6 +1827,11 @@ let StoryService = class StoryService {
|
|
|
1654
1827
|
if (introduce) {
|
|
1655
1828
|
let newCharacterName = situation.substring(11).trim();
|
|
1656
1829
|
if (newCharacterName) {
|
|
1830
|
+
const existingAgent = room.getAgents().find((a) => room.checkAgentNicknameMatch(a.agentNickname, newCharacterName));
|
|
1831
|
+
if (existingAgent) {
|
|
1832
|
+
logger_1.logger.log(`INTRODUCE: ${newCharacterName} ignored — character already in story`);
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1657
1835
|
const declinedCharacters = story?.declinedCharacters || [];
|
|
1658
1836
|
if (declinedCharacters.includes(newCharacterName)) {
|
|
1659
1837
|
logger_1.logger.log(`Character ${newCharacterName} was declined, skipping prompt`);
|
|
@@ -101,12 +101,27 @@ export interface ModelInfo {
|
|
|
101
101
|
description: string;
|
|
102
102
|
model: string;
|
|
103
103
|
service: string;
|
|
104
|
+
type?: string;
|
|
104
105
|
}
|
|
105
106
|
export interface StoryModelDefaults {
|
|
106
107
|
selectedStoryModel: string;
|
|
107
108
|
selectedImageModel: string;
|
|
109
|
+
selectedImageEditModel: string;
|
|
108
110
|
enforceDefaultModels: boolean;
|
|
109
111
|
}
|
|
112
|
+
export interface StoryModelEntry {
|
|
113
|
+
name: string;
|
|
114
|
+
description: string;
|
|
115
|
+
service: string;
|
|
116
|
+
model: string;
|
|
117
|
+
small_model?: string;
|
|
118
|
+
cost: string;
|
|
119
|
+
}
|
|
120
|
+
export interface StoryModelConfig {
|
|
121
|
+
service: string;
|
|
122
|
+
model: string;
|
|
123
|
+
smallModel?: string;
|
|
124
|
+
}
|
|
110
125
|
export type PromptScope = 'common' | 'user';
|
|
111
126
|
export interface PromptFolder {
|
|
112
127
|
name: string;
|
|
@@ -234,8 +249,10 @@ export interface StoryInfo {
|
|
|
234
249
|
moderatorAgentId: string;
|
|
235
250
|
illustratorAgentId?: string;
|
|
236
251
|
artistAgentId?: string;
|
|
252
|
+
artistEditAgentId?: string;
|
|
237
253
|
userAgentId?: string;
|
|
238
254
|
imageModelName?: string;
|
|
255
|
+
imageEditModelName?: string;
|
|
239
256
|
isImport: boolean;
|
|
240
257
|
totalCost: number;
|
|
241
258
|
totalInputTokens: number;
|
package/docs/assets/hierarchy.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
window.hierarchyData = "
|
|
1
|
+
window.hierarchyData = "eJx1jTsKwzAQRO8ytRz/sBN0hzRpjQshr2MRWQKtUhndPSg/TCDVwM7beRuC95Ehh76tRoFAsyUdjXcMuaFvqxxOrQSJMzGrK0HgZtwE2XS9wD1YSBgXKcxKE5dv6rDE1UJAW8UMichTkd+KL5rLxdgpkIMc6vrYjUkg58558X799dbN6eN9rhOXO+yv+HVIKT0A/0RQQA=="
|