Rework story engine flow and reorganize project docs
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -14,6 +14,12 @@ import {requestChatMessageContent} from './llmClient';
|
||||
import {parseJsonResponseText} from './llmParsers';
|
||||
import {buildQuestIntentPrompt, QUEST_INTENT_SYSTEM_PROMPT} from './questPrompt';
|
||||
import type {QuestIntent, QuestPreviewRequest} from './questTypes';
|
||||
import {
|
||||
buildFallbackActorNarrativeProfile,
|
||||
normalizeActorNarrativeProfile,
|
||||
} from './storyEngine/actorNarrativeProfile';
|
||||
import { buildThemePackFromWorldProfile } from './storyEngine/themePack';
|
||||
import { buildFallbackWorldStoryGraph } from './storyEngine/worldStoryGraph';
|
||||
|
||||
const QUEST_DIRECTOR_TIMEOUT_MS = 12000;
|
||||
|
||||
@@ -33,6 +39,41 @@ function coerceStringArray(value: unknown, fallback: string[]) {
|
||||
return items.length > 0 ? items : fallback;
|
||||
}
|
||||
|
||||
function resolveIssuerNarrativeProfile(
|
||||
state: GameState,
|
||||
encounter: Encounter,
|
||||
) {
|
||||
if (encounter.narrativeProfile) {
|
||||
return encounter.narrativeProfile;
|
||||
}
|
||||
if (!state.customWorldProfile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const role =
|
||||
state.customWorldProfile.storyNpcs.find((npc) =>
|
||||
npc.id === encounter.id || npc.name === encounter.npcName,
|
||||
)
|
||||
?? state.customWorldProfile.playableNpcs.find((npc) =>
|
||||
npc.id === encounter.id || npc.name === encounter.npcName,
|
||||
);
|
||||
if (!role) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const themePack =
|
||||
state.customWorldProfile.themePack
|
||||
?? buildThemePackFromWorldProfile(state.customWorldProfile);
|
||||
const storyGraph =
|
||||
state.customWorldProfile.storyGraph
|
||||
?? buildFallbackWorldStoryGraph(state.customWorldProfile, themePack);
|
||||
|
||||
return normalizeActorNarrativeProfile(
|
||||
role.narrativeProfile,
|
||||
buildFallbackActorNarrativeProfile(role, storyGraph, themePack),
|
||||
);
|
||||
}
|
||||
|
||||
function sanitizeQuestIntent(rawIntent: unknown, fallback: QuestIntent): QuestIntent {
|
||||
if (!rawIntent || typeof rawIntent !== 'object') {
|
||||
return fallback;
|
||||
@@ -92,10 +133,12 @@ export function buildQuestGenerationContextFromState(params: {
|
||||
const {state, encounter} = params;
|
||||
const issuerNpcId = encounter.id ?? encounter.npcName;
|
||||
const issuerState = state.npcStates[issuerNpcId];
|
||||
const issuerNarrativeProfile = resolveIssuerNarrativeProfile(state, encounter);
|
||||
|
||||
return {
|
||||
worldType: state.worldType,
|
||||
customWorldProfile: state.customWorldProfile ?? null,
|
||||
actState: state.storyEngineMemory?.actState ?? null,
|
||||
currentSceneId: state.currentScenePreset?.id ?? null,
|
||||
currentSceneName: state.currentScenePreset?.name ?? null,
|
||||
currentSceneDescription: state.currentScenePreset?.description ?? null,
|
||||
@@ -103,8 +146,13 @@ export function buildQuestGenerationContextFromState(params: {
|
||||
issuerNpcName: encounter.npcName,
|
||||
issuerNpcContext: encounter.context,
|
||||
issuerAffinity: issuerState?.affinity ?? 0,
|
||||
issuerNarrativeProfile,
|
||||
issuerDisclosureStage: getNpcDisclosureStage(issuerState?.affinity ?? 0),
|
||||
issuerWarmthStage: getNpcWarmthStage(issuerState?.affinity ?? 0),
|
||||
activeThreadIds:
|
||||
state.storyEngineMemory?.activeThreadIds?.slice(0, 4)
|
||||
?? issuerNarrativeProfile?.relatedThreadIds?.slice(0, 4)
|
||||
?? [],
|
||||
encounterKind: encounter.kind ?? 'npc',
|
||||
currentSceneTreasureHintCount: state.currentScenePreset?.treasureHints?.length ?? 0,
|
||||
currentSceneHostileNpcIds: (state.currentScenePreset?.npcs ?? [])
|
||||
|
||||
Reference in New Issue
Block a user