diff --git a/server/src/llm/backstoryGenerator.ts b/server/src/llm/backstoryGenerator.ts index 0aade55..3f86ed6 100644 --- a/server/src/llm/backstoryGenerator.ts +++ b/server/src/llm/backstoryGenerator.ts @@ -120,7 +120,15 @@ export async function generateBackstoryAndDesires( try { parsed = JSON.parse(result); } catch { - // JSON parse failed — use raw string as backstory fallback + // Try to salvage truncated JSON — extract backstory field even if desires are cut off + const backstoryMatch = result.match(/"backstory"\s*:\s*"((?:[^"\\]|\\.)*)"/); + if (backstoryMatch) { + logService?.log('warning', 'LLM', `JSON truncated for backstory (entity ${entityId}), salvaged backstory field`); + logLlmDebug({ templateName: 'backstoryAndDesires', stage: 'parse_salvaged', response: result }); + world.addComponent(entityId, 'backstory', backstoryMatch[1]); + return; + } + // Truly unparseable — use raw string as backstory fallback logService?.log('warning', 'LLM', `JSON parse failed for backstory (entity ${entityId}), using raw string`); logLlmDebug({ templateName: 'backstoryAndDesires', stage: 'parse_failed', response: result }); world.addComponent(entityId, 'backstory', result); diff --git a/server/src/llm/templates.ts b/server/src/llm/templates.ts index f3ff6c8..a471c73 100644 --- a/server/src/llm/templates.ts +++ b/server/src/llm/templates.ts @@ -75,7 +75,7 @@ export const templates: Record = { 'The backstory should reflect their personality without referencing professions or institutions that do not exist. ' + 'Desires should be grounded in what is achievable or aspirational given the current world state.\n\n' + 'Be concise. Keep backstory under 2 sentences. Keep desire descriptions short (under 10 words).\n\n' + - 'Respond ONLY with a valid JSON object. No explanation, no markdown, just JSON.', + 'Respond ONLY with compact single-line JSON. No newlines, no indentation, no markdown.', userPrompt: 'New settler: {{npcName}}\n' + 'Stats (each ranges 3-18, 10 is average): {{stats}}\n\n' +