@narrative-os/engine 0.1.0
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/dist/agents/canonValidator.d.ts +9 -0
- package/dist/agents/canonValidator.js +51 -0
- package/dist/agents/chapterPlanner.d.ts +50 -0
- package/dist/agents/chapterPlanner.js +250 -0
- package/dist/agents/completeness.d.ts +7 -0
- package/dist/agents/completeness.js +51 -0
- package/dist/agents/memoryExtractor.d.ts +12 -0
- package/dist/agents/memoryExtractor.js +82 -0
- package/dist/agents/stateUpdater.d.ts +30 -0
- package/dist/agents/stateUpdater.js +150 -0
- package/dist/agents/storyDirector.d.ts +40 -0
- package/dist/agents/storyDirector.js +213 -0
- package/dist/agents/summarizer.d.ts +8 -0
- package/dist/agents/summarizer.js +56 -0
- package/dist/agents/tensionController.d.ts +68 -0
- package/dist/agents/tensionController.js +197 -0
- package/dist/agents/writer.d.ts +12 -0
- package/dist/agents/writer.js +148 -0
- package/dist/constraints/constraintGraph.d.ts +117 -0
- package/dist/constraints/constraintGraph.js +381 -0
- package/dist/constraints/validator.d.ts +58 -0
- package/dist/constraints/validator.js +236 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +115 -0
- package/dist/llm/client.d.ts +14 -0
- package/dist/llm/client.js +108 -0
- package/dist/memory/canonStore.d.ts +20 -0
- package/dist/memory/canonStore.js +110 -0
- package/dist/memory/memoryRetriever.d.ts +28 -0
- package/dist/memory/memoryRetriever.js +126 -0
- package/dist/memory/stateUpdater.d.ts +49 -0
- package/dist/memory/stateUpdater.js +315 -0
- package/dist/memory/vectorStore.d.ts +41 -0
- package/dist/memory/vectorStore.js +166 -0
- package/dist/pipeline/generateChapter.d.ts +17 -0
- package/dist/pipeline/generateChapter.js +75 -0
- package/dist/story/bible.d.ts +4 -0
- package/dist/story/bible.js +53 -0
- package/dist/story/state.d.ts +3 -0
- package/dist/story/state.js +27 -0
- package/dist/story/structuredState.d.ts +39 -0
- package/dist/story/structuredState.js +159 -0
- package/dist/test/canon.test.d.ts +1 -0
- package/dist/test/canon.test.js +104 -0
- package/dist/test/chapter-planner.test.d.ts +1 -0
- package/dist/test/chapter-planner.test.js +171 -0
- package/dist/test/constraints.test.d.ts +1 -0
- package/dist/test/constraints.test.js +210 -0
- package/dist/test/simple.test.d.ts +1 -0
- package/dist/test/simple.test.js +51 -0
- package/dist/test/state-updater.test.d.ts +1 -0
- package/dist/test/state-updater.test.js +200 -0
- package/dist/test/story-director.test.d.ts +1 -0
- package/dist/test/story-director.test.js +142 -0
- package/dist/test/structured-state.test.d.ts +1 -0
- package/dist/test/structured-state.test.js +144 -0
- package/dist/test/tension-controller.test.d.ts +1 -0
- package/dist/test/tension-controller.test.js +116 -0
- package/dist/test/vector-memory.test.d.ts +1 -0
- package/dist/test/vector-memory.test.js +153 -0
- package/dist/test/world-simulation.test.d.ts +1 -0
- package/dist/test/world-simulation.test.js +152 -0
- package/dist/types/index.d.ts +79 -0
- package/dist/types/index.js +3 -0
- package/dist/world/characterAgent.d.ts +73 -0
- package/dist/world/characterAgent.js +232 -0
- package/dist/world/eventResolver.d.ts +52 -0
- package/dist/world/eventResolver.js +205 -0
- package/dist/world/worldState.d.ts +93 -0
- package/dist/world/worldState.js +258 -0
- package/package.json +43 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stateUpdater = exports.StateUpdater = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const STATE_UPDATE_PROMPT = `You are a narrative state tracker. Analyze the chapter and extract state changes.
|
|
6
|
+
|
|
7
|
+
## Story Bible
|
|
8
|
+
|
|
9
|
+
**Title:** {{title}}
|
|
10
|
+
**Genre:** {{genre}}
|
|
11
|
+
|
|
12
|
+
## Characters
|
|
13
|
+
|
|
14
|
+
{{characters}}
|
|
15
|
+
|
|
16
|
+
## Current Plot Threads
|
|
17
|
+
|
|
18
|
+
{{plotThreads}}
|
|
19
|
+
|
|
20
|
+
## Chapter Content
|
|
21
|
+
|
|
22
|
+
**Chapter {{chapterNumber}}: {{chapterTitle}}**
|
|
23
|
+
|
|
24
|
+
{{chapterContent}}
|
|
25
|
+
|
|
26
|
+
## Current Unresolved Questions
|
|
27
|
+
|
|
28
|
+
{{unresolvedQuestions}}
|
|
29
|
+
|
|
30
|
+
## Task
|
|
31
|
+
|
|
32
|
+
Analyze what changed in this chapter. Output JSON with:
|
|
33
|
+
|
|
34
|
+
1. **characterUpdates**: How characters changed (emotion, location, knowledge, relationships)
|
|
35
|
+
2. **plotThreadUpdates**: How plot threads progressed (status, tension)
|
|
36
|
+
3. **newQuestions**: New mysteries or questions raised
|
|
37
|
+
4. **resolvedQuestions**: Which current questions were answered
|
|
38
|
+
5. **recentEvents**: Key events that happened (2-3 bullet points)
|
|
39
|
+
|
|
40
|
+
Example output:
|
|
41
|
+
{
|
|
42
|
+
"characterUpdates": [
|
|
43
|
+
{
|
|
44
|
+
"name": "Alice",
|
|
45
|
+
"emotionalState": "anxious",
|
|
46
|
+
"location": "the abandoned warehouse",
|
|
47
|
+
"newKnowledge": ["the code is 8472"],
|
|
48
|
+
"relationshipChanges": [{"with": "Bob", "status": "distrustful"}],
|
|
49
|
+
"development": "Alice realizes she can't trust her mentor"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"plotThreadUpdates": [
|
|
53
|
+
{
|
|
54
|
+
"id": "missing_brother",
|
|
55
|
+
"status": "escalating",
|
|
56
|
+
"tensionChange": 0.1,
|
|
57
|
+
"summary": "Discovered brother was kidnapped by the syndicate"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"newQuestions": ["Who is the mysterious informant?"],
|
|
61
|
+
"resolvedQuestions": ["Where was the brother taken?"],
|
|
62
|
+
"recentEvents": ["Alice broke into the warehouse", "Found the hidden room"]
|
|
63
|
+
}`;
|
|
64
|
+
class StateUpdater {
|
|
65
|
+
async extractStateChanges(chapter, bible, currentState) {
|
|
66
|
+
const characters = Object.values(currentState.characters)
|
|
67
|
+
.map(c => `- ${c.name}: currently ${c.emotionalState}, at ${c.location}`)
|
|
68
|
+
.join('\n') || 'No characters tracked yet.';
|
|
69
|
+
const plotThreads = Object.values(currentState.plotThreads)
|
|
70
|
+
.map(t => `- ${t.name} (${t.status}, tension: ${Math.round(t.tension * 100)}%): ${t.summary}`)
|
|
71
|
+
.join('\n') || 'No active plot threads.';
|
|
72
|
+
const unresolvedQuestions = currentState.unresolvedQuestions.length > 0
|
|
73
|
+
? currentState.unresolvedQuestions.map(q => `- ${q}`).join('\n')
|
|
74
|
+
: 'None';
|
|
75
|
+
const prompt = STATE_UPDATE_PROMPT
|
|
76
|
+
.replace('{{title}}', bible.title)
|
|
77
|
+
.replace('{{genre}}', bible.genre)
|
|
78
|
+
.replace('{{characters}}', characters)
|
|
79
|
+
.replace('{{plotThreads}}', plotThreads)
|
|
80
|
+
.replace('{{chapterNumber}}', chapter.number.toString())
|
|
81
|
+
.replace('{{chapterTitle}}', chapter.title)
|
|
82
|
+
.replace('{{chapterContent}}', chapter.content.substring(0, 6000))
|
|
83
|
+
.replace('{{unresolvedQuestions}}', unresolvedQuestions);
|
|
84
|
+
const result = await (0, client_js_1.getLLM)().completeJSON(prompt, {
|
|
85
|
+
temperature: 0.3,
|
|
86
|
+
maxTokens: 2000,
|
|
87
|
+
});
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
applyUpdates(state, updates, chapterNumber) {
|
|
91
|
+
let newState = { ...state };
|
|
92
|
+
// Apply character updates
|
|
93
|
+
for (const update of updates.characterUpdates) {
|
|
94
|
+
if (newState.characters[update.name]) {
|
|
95
|
+
const char = newState.characters[update.name];
|
|
96
|
+
if (update.emotionalState) {
|
|
97
|
+
char.emotionalState = update.emotionalState;
|
|
98
|
+
}
|
|
99
|
+
if (update.location) {
|
|
100
|
+
char.location = update.location;
|
|
101
|
+
}
|
|
102
|
+
if (update.newKnowledge) {
|
|
103
|
+
char.knowledge = [...char.knowledge, ...update.newKnowledge];
|
|
104
|
+
}
|
|
105
|
+
if (update.relationshipChanges) {
|
|
106
|
+
for (const rel of update.relationshipChanges) {
|
|
107
|
+
char.relationships[rel.with] = rel.status;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (update.development) {
|
|
111
|
+
char.development = [...char.development, update.development];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Apply plot thread updates
|
|
116
|
+
for (const update of updates.plotThreadUpdates) {
|
|
117
|
+
if (newState.plotThreads[update.id]) {
|
|
118
|
+
const thread = newState.plotThreads[update.id];
|
|
119
|
+
if (update.status) {
|
|
120
|
+
thread.status = update.status;
|
|
121
|
+
}
|
|
122
|
+
if (update.tensionChange !== undefined) {
|
|
123
|
+
thread.tension = Math.max(0, Math.min(1, thread.tension + update.tensionChange));
|
|
124
|
+
}
|
|
125
|
+
if (update.summary) {
|
|
126
|
+
thread.summary = update.summary;
|
|
127
|
+
}
|
|
128
|
+
thread.lastChapter = chapterNumber;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Add new questions
|
|
132
|
+
for (const question of updates.newQuestions) {
|
|
133
|
+
if (!newState.unresolvedQuestions.includes(question)) {
|
|
134
|
+
newState.unresolvedQuestions = [...newState.unresolvedQuestions, question];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Remove resolved questions
|
|
138
|
+
for (const question of updates.resolvedQuestions) {
|
|
139
|
+
newState.unresolvedQuestions = newState.unresolvedQuestions.filter(q => q !== question);
|
|
140
|
+
}
|
|
141
|
+
// Add recent events
|
|
142
|
+
for (const event of updates.recentEvents) {
|
|
143
|
+
newState.recentEvents = [...newState.recentEvents, event].slice(-10);
|
|
144
|
+
}
|
|
145
|
+
return newState;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
exports.StateUpdater = StateUpdater;
|
|
149
|
+
exports.stateUpdater = new StateUpdater();
|
|
150
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGVVcGRhdGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50cy9zdGF0ZVVwZGF0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZ0RBQTBDO0FBd0IxQyxNQUFNLG1CQUFtQixHQUFHOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBMEQxQixDQUFDO0FBRUgsTUFBYSxZQUFZO0lBQ3ZCLEtBQUssQ0FBQyxtQkFBbUIsQ0FDdkIsT0FBZ0IsRUFDaEIsS0FBaUIsRUFDakIsWUFBa0M7UUFFbEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDO2FBQ3RELEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksZUFBZSxDQUFDLENBQUMsY0FBYyxRQUFRLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQzthQUN4RSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksNEJBQTRCLENBQUM7UUFFOUMsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDO2FBQ3hELEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsTUFBTSxjQUFjLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7YUFDN0YsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLHlCQUF5QixDQUFDO1FBRTNDLE1BQU0sbUJBQW1CLEdBQUcsWUFBWSxDQUFDLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQ3JFLENBQUMsQ0FBQyxZQUFZLENBQUMsbUJBQW1CLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxF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SSxPQUFPLENBQUMsWUFBWSxFQUFFLENBQUM7WUFDekMsUUFBUSxDQUFDLFlBQVksR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN2RSxDQUFDO1FBRUQsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztDQUNGO0FBekdELG9DQXlHQztBQUVZLFFBQUEsWUFBWSxHQUFHLElBQUksWUFBWSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBnZXRMTE0gfSBmcm9tICcuLi9sbG0vY2xpZW50LmpzJztcclxuaW1wb3J0IHR5cGUgeyBDaGFwdGVyLCBTdG9yeUJpYmxlIH0gZnJvbSAnLi4vdHlwZXMvaW5kZXguanMnO1xyXG5pbXBvcnQgdHlwZSB7IFN0b3J5U3RydWN0dXJlZFN0YXRlLCBDaGFyYWN0ZXJTdGF0ZSwgUGxvdFRocmVhZFN0YXRlIH0gZnJvbSAnLi4vc3Rvcnkvc3RydWN0dXJlZFN0YXRlLmpzJztcclxuXHJcbmludGVyZmFjZSBTdGF0ZVVwZGF0ZU91dHB1dCB7XHJcbiAgY2hhcmFjdGVyVXBkYXRlczogQXJyYXk8e1xyXG4gICAgbmFtZTogc3RyaW5nO1xyXG4gICAgZW1vdGlvbmFsU3RhdGU/OiBzdHJpbmc7XHJcbiAgICBsb2NhdGlvbj86IHN0cmluZztcclxuICAgIG5ld0tub3dsZWRnZT86IHN0cmluZ1tdO1xyXG4gICAgcmVsYXRpb25zaGlwQ2hhbmdlcz86IEFycmF5PHsgd2l0aDogc3RyaW5nOyBzdGF0dXM6IHN0cmluZyB9PjtcclxuICAgIGRldmVsb3BtZW50Pzogc3RyaW5nO1xyXG4gIH0+O1xyXG4gIHBsb3RUaHJlYWRVcGRhdGVzOiBBcnJheTx7XHJcbiAgICBpZDogc3RyaW5nO1xyXG4gICAgc3RhdHVzPzogJ2Rvcm1hbnQnIHwgJ2FjdGl2ZScgfCAnZXNjYWxhdGluZycgfCAncmVzb2x2ZWQnO1xyXG4gICAgdGVuc2lvbkNoYW5nZT86IG51bWJlcjsgLy8gLTAuMSB0byArMC4xXHJcbiAgICBzdW1tYXJ5Pzogc3RyaW5nO1xyXG4gIH0+O1xyXG4gIG5ld1F1ZXN0aW9uczogc3RyaW5nW107XHJcbiAgcmVzb2x2ZWRRdWVzdGlvbnM6IHN0cmluZ1tdO1xyXG4gIHJlY2VudEV2ZW50czogc3RyaW5nW107XHJcbn1cclxuXHJcbmNvbnN0IFNUQVRFX1VQREFURV9QUk9NUFQgPSBgWW91IGFyZSBhIG5hcnJhdGl2ZSBzdGF0ZSB0cmFja2VyLiBBbmFseXplIHRoZSBjaGFwdGVyIGFuZCBleHRyYWN0IHN0YXRlIGNoYW5nZXMuXHJcblxyXG4jIyBTdG9yeSBCaWJsZVxyXG5cclxuKipUaXRsZToqKiB7e3RpdGxlfX1cclxuKipHZW5yZToqKiB7e2dlbnJlfX1cclxuXHJcbiMjIENoYXJhY3RlcnNcclxuXHJcbnt7Y2hhcmFjdGVyc319XHJcblxyXG4jIyBDdXJyZW50IFBsb3QgVGhyZWFkc1xyXG5cclxue3twbG90VGhyZWFkc319XHJcblxyXG4jIyBDaGFwdGVyIENvbnRlbnRcclxuXHJcbioqQ2hhcHRlciB7e2NoYXB0ZXJOdW1iZXJ9fToge3tjaGFwdGVyVGl0bGV9fSoqXHJcblxyXG57e2NoYXB0ZXJDb250ZW50fX1cclxuXHJcbiMjIEN1cnJlbnQgVW5yZXNvbHZlZCBRdWVzdGlvbnNcclxuXHJcbnt7dW5yZXNvbHZlZFF1ZXN0aW9uc319XHJcblxyXG4jIyBUYXNrXHJcblxyXG5BbmFseXplIHdoYXQgY2hhbmdlZCBpbiB0aGlzIGNoYXB0ZXIuIE91dHB1dCBKU09OIHdpdGg6XHJcblxyXG4xLiAqKmNoYXJhY3RlclVwZGF0ZXMqKjogSG93IGNoYXJhY3RlcnMgY2hhbmdlZCAoZW1vdGlvbiwgbG9jYXRpb24sIGtub3dsZWRnZSwgcmVsYXRpb25zaGlwcylcclxuMi4gKipwbG90VGhyZWFkVXBkYXRlcyoqOiBIb3cgcGxvdCB0aHJlYWRzIHByb2dyZXNzZWQgKHN0YXR1cywgdGVuc2lvbilcclxuMy4gKipuZXdRdWVzdGlvbnMqKjogTmV3IG15c3RlcmllcyBvciBxdWVzdGlvbnMgcmFpc2VkXHJcbjQuICoqcmVzb2x2ZWRRdWVzdGlvbnMqKjogV2hpY2ggY3VycmVudCBxdWVzdGlvbnMgd2VyZSBhbnN3ZXJlZFxyXG41LiAqKnJlY2VudEV2ZW50cyoqOiBLZXkgZXZlbnRzIHRoYXQgaGFwcGVuZWQgKDItMyBidWxsZXQgcG9pbnRzKVxyXG5cclxuRXhhbXBsZSBvdXRwdXQ6XHJcbntcclxuICBcImNoYXJhY3RlclVwZGF0ZXNcIjogW1xyXG4gICAge1xyXG4gICAgICBcIm5hbWVcIjogXCJBbGljZVwiLFxyXG4gICAgICBcImVtb3Rpb25hbFN0YXRlXCI6IFwiYW54aW91c1wiLFxyXG4gICAgICBcImxvY2F0aW9uXCI6IFwidGhlIGFiYW5kb25lZCB3YXJlaG91c2VcIixcclxuICAgICAgXCJuZXdLbm93bGVkZ2VcIjogW1widGhlIGNvZGUgaXMgODQ3MlwiXSxcclxuICAgICAgXCJyZWxhdGlvbnNoaXBDaGFuZ2VzXCI6IFt7XCJ3aXRoXCI6IFwiQm9iXCIsIFwic3RhdHVzXCI6IFwiZGlzdHJ1c3RmdWxcIn1dLFxyXG4gICAgICBcImRldmVsb3BtZW50XCI6IFwiQWxpY2UgcmVhbGl6ZXMgc2hlIGNhbid0IHRydXN0IGhlciBtZW50b3JcIlxyXG4gICAgfVxyXG4gIF0sXHJcbiAgXCJwbG90VGhyZWFkVXBkYXRlc1wiOiBbXHJcbiAgICB7XHJcbiAgICAgIFwiaWRcIjogXCJtaXNzaW5nX2Jyb3RoZXJcIixcclxuICAgICAgXCJzdGF0dXNcIjogXCJlc2NhbGF0aW5nXCIsXHJcbiAgICAgIFwidGVuc2lvbkNoYW5nZVwiOiAwLjEsXHJcbiAgICAgIFwic3VtbWFyeVwiOiBcIkRpc2NvdmVyZWQgYnJvdGhlciB3YXMga2lkbmFwcGVkIGJ5IHRoZSBzeW5kaWNhdGVcIlxyXG4gICAgfVxyXG4gIF0sXHJcbiAgXCJuZXdRdWVzdGlvbnNcIjogW1wiV2hvIGlzIHRoZSBteXN0ZXJpb3VzIGluZm9ybWFudD9cIl0sXHJcbiAgXCJyZXNvbHZlZFF1ZXN0aW9uc1wiOiBbXCJXaGVyZSB3YXMgdGhlIGJyb3RoZXIgdGFrZW4/XCJdLFxyXG4gIFwicmVjZW50RXZlbnRzXCI6IFtcIkFsaWNlIGJyb2tlIGludG8gdGhlIHdhcmVob3VzZVwiLCBcIkZvdW5kIHRoZSBoaWRkZW4gcm9vbVwiXVxyXG59YDtcclxuXHJcbmV4cG9ydCBjbGFzcyBTdGF0ZVVwZGF0ZXIge1xyXG4gIGFzeW5jIGV4dHJhY3RTdGF0ZUNoYW5nZXMoXHJcbiAgICBjaGFwdGVyOiBDaGFwdGVyLFxyXG4gICAgYmlibGU6IFN0b3J5QmlibGUsXHJcbiAgICBjdXJyZW50U3RhdGU6IFN0b3J5U3RydWN0dXJlZFN0YXRlXHJcbiAgKTogUHJvbWlzZTxTdGF0ZVVwZGF0ZU91dHB1dD4ge1xyXG4gICAgY29uc3QgY2hhcmFjdGVycyA9IE9iamVjdC52YWx1ZXMoY3VycmVudFN0YXRlLmNoYXJhY3RlcnMpXHJcbiAgICAgIC5tYXAoYyA9PiBgLSAke2MubmFtZX06IGN1cnJlbnRseSAke2MuZW1vdGlvbmFsU3RhdGV9LCBhdCAke2MubG9jYXRpb259YClcclxuICAgICAgLmpvaW4oJ1xcbicpIHx8ICdObyBjaGFyYWN0ZXJzIHRyYWNrZWQgeWV0Lic7XHJcblxyXG4gICAgY29uc3QgcGxvdFRocmVhZHMgPSBPYmplY3QudmFsdWVzKGN1cnJlbnRTdGF0ZS5wbG90VGhyZWFkcylcclxuICAgICAgLm1hcCh0ID0+IGAtICR7dC5uYW1lfSAoJHt0LnN0YXR1c30sIHRlbnNpb246ICR7TWF0aC5yb3VuZCh0LnRlbnNpb24gKiAxMDApfSUpOiAke3Quc3VtbWFyeX1gKVxyXG4gICAgICAuam9pbignXFxuJykgfHwgJ05vIGFjdGl2ZSBwbG90IHRocmVhZHMuJztcclxuXHJcbiAgICBjb25zdCB1bnJlc29sdmVkUXVlc3Rpb25zID0gY3VycmVudFN0YXRlLnVucmVzb2x2ZWRRdWVzdGlvbnMubGVuZ3RoID4gMFxyXG4gICAgICA/IGN1cnJlbnRTdGF0ZS51bnJlc29sdmVkUXVlc3Rpb25zLm1hcChxID0+IGAtICR7cX1gKS5qb2luKCdcXG4nKVxyXG4gICAgICA6ICdOb25lJztcclxuXHJcbiAgICBjb25zdCBwcm9tcHQgPSBTVEFURV9VUERBVEVfUFJPTVBUXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RpdGxlfX0nLCBiaWJsZS50aXRsZSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Z2VucmV9fScsIGJpYmxlLmdlbnJlKVxyXG4gICAgICAucmVwbGFjZSgne3tjaGFyYWN0ZXJzfX0nLCBjaGFyYWN0ZXJzKVxyXG4gICAgICAucmVwbGFjZSgne3twbG90VGhyZWFkc319JywgcGxvdFRocmVhZHMpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2NoYXB0ZXJOdW1iZXJ9fScsIGNoYXB0ZXIubnVtYmVyLnRvU3RyaW5nKCkpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2NoYXB0ZXJUaXRsZX19JywgY2hhcHRlci50aXRsZSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Y2hhcHRlckNvbnRlbnR9fScsIGNoYXB0ZXIuY29udGVudC5zdWJzdHJpbmcoMCwgNjAwMCkpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3VucmVzb2x2ZWRRdWVzdGlvbnN9fScsIHVucmVzb2x2ZWRRdWVzdGlvbnMpO1xyXG5cclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdldExMTSgpLmNvbXBsZXRlSlNPTjxTdGF0ZVVwZGF0ZU91dHB1dD4ocHJvbXB0LCB7XHJcbiAgICAgIHRlbXBlcmF0dXJlOiAwLjMsXHJcbiAgICAgIG1heFRva2VuczogMjAwMCxcclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfVxyXG5cclxuICBhcHBseVVwZGF0ZXMoXHJcbiAgICBzdGF0ZTogU3RvcnlTdHJ1Y3R1cmVkU3RhdGUsXHJcbiAgICB1cGRhdGVzOiBTdGF0ZVVwZGF0ZU91dHB1dCxcclxuICAgIGNoYXB0ZXJOdW1iZXI6IG51bWJlclxyXG4gICk6IFN0b3J5U3RydWN0dXJlZFN0YXRlIHtcclxuICAgIGxldCBuZXdTdGF0ZSA9IHsgLi4uc3RhdGUgfTtcclxuXHJcbiAgICAvLyBBcHBseSBjaGFyYWN0ZXIgdXBkYXRlc1xyXG4gICAgZm9yIChjb25zdCB1cGRhdGUgb2YgdXBkYXRlcy5jaGFyYWN0ZXJVcGRhdGVzKSB7XHJcbiAgICAgIGlmIChuZXdTdGF0ZS5jaGFyYWN0ZXJzW3VwZGF0ZS5uYW1lXSkge1xyXG4gICAgICAgIGNvbnN0IGNoYXIgPSBuZXdTdGF0ZS5jaGFyYWN0ZXJzW3VwZGF0ZS5uYW1lXTtcclxuICAgICAgICBcclxuICAgICAgICBpZiAodXBkYXRlLmVtb3Rpb25hbFN0YXRlKSB7XHJcbiAgICAgICAgICBjaGFyLmVtb3Rpb25hbFN0YXRlID0gdXBkYXRlLmVtb3Rpb25hbFN0YXRlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlLmxvY2F0aW9uKSB7XHJcbiAgICAgICAgICBjaGFyLmxvY2F0aW9uID0gdXBkYXRlLmxvY2F0aW9uO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlLm5ld0tub3dsZWRnZSkge1xyXG4gICAgICAgICAgY2hhci5rbm93bGVkZ2UgPSBbLi4uY2hhci5rbm93bGVkZ2UsIC4uLnVwZGF0ZS5uZXdLbm93bGVkZ2VdO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlLnJlbGF0aW9uc2hpcENoYW5nZXMpIHtcclxuICAgICAgICAgIGZvciAoY29uc3QgcmVsIG9mIHVwZGF0ZS5yZWxhdGlvbnNoaXBDaGFuZ2VzKSB7XHJcbiAgICAgICAgICAgIGNoYXIucmVsYXRpb25zaGlwc1tyZWwud2l0aF0gPSByZWwuc3RhdHVzO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlLmRldmVsb3BtZW50KSB7XHJcbiAgICAgICAgICBjaGFyLmRldmVsb3BtZW50ID0gWy4uLmNoYXIuZGV2ZWxvcG1lbnQsIHVwZGF0ZS5kZXZlbG9wbWVudF07XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXBwbHkgcGxvdCB0aHJlYWQgdXBkYXRlc1xyXG4gICAgZm9yIChjb25zdCB1cGRhdGUgb2YgdXBkYXRlcy5wbG90VGhyZWFkVXBkYXRlcykge1xyXG4gICAgICBpZiAobmV3U3RhdGUucGxvdFRocmVhZHNbdXBkYXRlLmlkXSkge1xyXG4gICAgICAgIGNvbnN0IHRocmVhZCA9IG5ld1N0YXRlLnBsb3RUaHJlYWRzW3VwZGF0ZS5pZF07XHJcbiAgICAgICAgXHJcbiAgICAgICAgaWYgKHVwZGF0ZS5zdGF0dXMpIHtcclxuICAgICAgICAgIHRocmVhZC5zdGF0dXMgPSB1cGRhdGUuc3RhdHVzO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodXBkYXRlLnRlbnNpb25DaGFuZ2UgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgdGhyZWFkLnRlbnNpb24gPSBNYXRoLm1heCgwLCBNYXRoLm1pbigxLCB0aHJlYWQudGVuc2lvbiArIHVwZGF0ZS50ZW5zaW9uQ2hhbmdlKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh1cGRhdGUuc3VtbWFyeSkge1xyXG4gICAgICAgICAgdGhyZWFkLnN1bW1hcnkgPSB1cGRhdGUuc3VtbWFyeTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhyZWFkLmxhc3RDaGFwdGVyID0gY2hhcHRlck51bWJlcjtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCBuZXcgcXVlc3Rpb25zXHJcbiAgICBmb3IgKGNvbnN0IHF1ZXN0aW9uIG9mIHVwZGF0ZXMubmV3UXVlc3Rpb25zKSB7XHJcbiAgICAgIGlmICghbmV3U3RhdGUudW5yZXNvbHZlZFF1ZXN0aW9ucy5pbmNsdWRlcyhxdWVzdGlvbikpIHtcclxuICAgICAgICBuZXdTdGF0ZS51bnJlc29sdmVkUXVlc3Rpb25zID0gWy4uLm5ld1N0YXRlLnVucmVzb2x2ZWRRdWVzdGlvbnMsIHF1ZXN0aW9uXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbW92ZSByZXNvbHZlZCBxdWVzdGlvbnNcclxuICAgIGZvciAoY29uc3QgcXVlc3Rpb24gb2YgdXBkYXRlcy5yZXNvbHZlZFF1ZXN0aW9ucykge1xyXG4gICAgICBuZXdTdGF0ZS51bnJlc29sdmVkUXVlc3Rpb25zID0gbmV3U3RhdGUudW5yZXNvbHZlZFF1ZXN0aW9ucy5maWx0ZXIocSA9PiBxICE9PSBxdWVzdGlvbik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWRkIHJlY2VudCBldmVudHNcclxuICAgIGZvciAoY29uc3QgZXZlbnQgb2YgdXBkYXRlcy5yZWNlbnRFdmVudHMpIHtcclxuICAgICAgbmV3U3RhdGUucmVjZW50RXZlbnRzID0gWy4uLm5ld1N0YXRlLnJlY2VudEV2ZW50cywgZXZlbnRdLnNsaWNlKC0xMCk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG5ld1N0YXRlO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGNvbnN0IHN0YXRlVXBkYXRlciA9IG5ldyBTdGF0ZVVwZGF0ZXIoKTtcclxuIl19
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { StoryBible, StoryState, ChapterSummary } from '../types/index.js';
|
|
2
|
+
import type { StoryStructuredState } from '../story/structuredState.js';
|
|
3
|
+
import type { TensionGuidance } from './tensionController.js';
|
|
4
|
+
export interface ChapterObjective {
|
|
5
|
+
id: string;
|
|
6
|
+
description: string;
|
|
7
|
+
priority: 'critical' | 'high' | 'medium' | 'low';
|
|
8
|
+
type: 'plot' | 'character' | 'world' | 'tension' | 'resolution';
|
|
9
|
+
relatedPlotThreadId?: string;
|
|
10
|
+
relatedCharacter?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DirectorOutput {
|
|
13
|
+
chapterNumber: number;
|
|
14
|
+
overallGoal: string;
|
|
15
|
+
objectives: ChapterObjective[];
|
|
16
|
+
focusCharacters: string[];
|
|
17
|
+
suggestedScenes: string[];
|
|
18
|
+
tone: string;
|
|
19
|
+
notes: string;
|
|
20
|
+
}
|
|
21
|
+
export interface DirectorContext {
|
|
22
|
+
bible: StoryBible;
|
|
23
|
+
state: StoryState;
|
|
24
|
+
structuredState: StoryStructuredState;
|
|
25
|
+
tensionGuidance: TensionGuidance;
|
|
26
|
+
previousSummaries: ChapterSummary[];
|
|
27
|
+
}
|
|
28
|
+
export declare class StoryDirector {
|
|
29
|
+
direct(context: DirectorContext): Promise<DirectorOutput>;
|
|
30
|
+
private buildPrompt;
|
|
31
|
+
/**
|
|
32
|
+
* Format director output for writer prompt
|
|
33
|
+
*/
|
|
34
|
+
formatForPrompt(output: DirectorOutput): string;
|
|
35
|
+
/**
|
|
36
|
+
* Get quick objectives without LLM call (for testing/fallback)
|
|
37
|
+
*/
|
|
38
|
+
generateFallbackObjectives(state: StoryState, structuredState: StoryStructuredState): DirectorOutput;
|
|
39
|
+
}
|
|
40
|
+
export declare const storyDirector: StoryDirector;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.storyDirector = exports.StoryDirector = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const STORY_DIRECTOR_PROMPT = `You are the Story Director for a narrative AI system. Your job is to decide what the next chapter should accomplish.
|
|
6
|
+
|
|
7
|
+
## Story Bible
|
|
8
|
+
|
|
9
|
+
**Title:** {{title}}
|
|
10
|
+
**Genre:** {{genre}}
|
|
11
|
+
**Theme:** {{theme}}
|
|
12
|
+
**Premise:** {{premise}}
|
|
13
|
+
|
|
14
|
+
## Current Story State
|
|
15
|
+
|
|
16
|
+
**Chapter:** {{currentChapter}} / {{totalChapters}}
|
|
17
|
+
**Story Tension:** {{storyTension}}%
|
|
18
|
+
**Target Tension:** {{targetTension}}%
|
|
19
|
+
|
|
20
|
+
### Active Plot Threads
|
|
21
|
+
{{plotThreads}}
|
|
22
|
+
|
|
23
|
+
### Character States
|
|
24
|
+
{{characters}}
|
|
25
|
+
|
|
26
|
+
### Unresolved Questions
|
|
27
|
+
{{questions}}
|
|
28
|
+
|
|
29
|
+
### Recent Events
|
|
30
|
+
{{recentEvents}}
|
|
31
|
+
|
|
32
|
+
## Tension Guidance
|
|
33
|
+
|
|
34
|
+
{{tensionGuidance}}
|
|
35
|
+
|
|
36
|
+
## Previous Chapter Summaries
|
|
37
|
+
{{summaries}}
|
|
38
|
+
|
|
39
|
+
## Your Task
|
|
40
|
+
|
|
41
|
+
Based on all the above information, decide what Chapter {{nextChapter}} should accomplish. Consider:
|
|
42
|
+
|
|
43
|
+
1. **Plot Progression**: Which plot threads need advancement?
|
|
44
|
+
2. **Character Development**: Which characters need focus or growth?
|
|
45
|
+
3. **Tension Management**: How should tension change based on target?
|
|
46
|
+
4. **Unresolved Questions**: Which mysteries should be addressed?
|
|
47
|
+
5. **Story Arc**: Where are we in the overall narrative (setup/rising action/climax/resolution)?
|
|
48
|
+
|
|
49
|
+
Output a JSON object with:
|
|
50
|
+
|
|
51
|
+
{
|
|
52
|
+
"chapterNumber": {{nextChapter}},
|
|
53
|
+
"overallGoal": "One-sentence description of what this chapter achieves",
|
|
54
|
+
"objectives": [
|
|
55
|
+
{
|
|
56
|
+
"id": "unique-id",
|
|
57
|
+
"description": "What needs to happen",
|
|
58
|
+
"priority": "critical|high|medium|low",
|
|
59
|
+
"type": "plot|character|world|tension|resolution",
|
|
60
|
+
"relatedPlotThreadId": "thread-id or omit",
|
|
61
|
+
"relatedCharacter": "character name or omit"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"focusCharacters": ["Character names that should be central"],
|
|
65
|
+
"suggestedScenes": ["Scene ideas that could achieve objectives"],
|
|
66
|
+
"tone": "emotional tone for this chapter",
|
|
67
|
+
"notes": "Additional guidance for the writer"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Be specific and actionable. The writer will use your direction to craft the chapter.`;
|
|
71
|
+
class StoryDirector {
|
|
72
|
+
async direct(context) {
|
|
73
|
+
const { bible, state, structuredState, tensionGuidance, previousSummaries } = context;
|
|
74
|
+
const prompt = this.buildPrompt(bible, state, structuredState, tensionGuidance, previousSummaries);
|
|
75
|
+
const result = await (0, client_js_1.getLLM)().completeJSON(prompt, {
|
|
76
|
+
temperature: 0.4,
|
|
77
|
+
maxTokens: 2000,
|
|
78
|
+
});
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
buildPrompt(bible, state, structuredState, tensionGuidance, summaries) {
|
|
82
|
+
const currentTension = Math.round(structuredState.tension * 100);
|
|
83
|
+
const targetTension = Math.round(tensionGuidance.targetTension * 100);
|
|
84
|
+
// Format plot threads
|
|
85
|
+
const activeThreads = Object.values(structuredState.plotThreads)
|
|
86
|
+
.filter(t => t.status !== 'resolved')
|
|
87
|
+
.map(t => `- **${t.name}** (${t.status}, ${Math.round(t.tension * 100)}% tension): ${t.summary}`)
|
|
88
|
+
.join('\n') || 'No active plot threads.';
|
|
89
|
+
// Format characters
|
|
90
|
+
const characters = Object.values(structuredState.characters)
|
|
91
|
+
.map(c => `- **${c.name}**: ${c.emotionalState}, at ${c.location}`)
|
|
92
|
+
.join('\n') || 'No character data.';
|
|
93
|
+
// Format questions
|
|
94
|
+
const questions = structuredState.unresolvedQuestions.length > 0
|
|
95
|
+
? structuredState.unresolvedQuestions.map(q => `- ${q}`).join('\n')
|
|
96
|
+
: 'None';
|
|
97
|
+
// Format recent events
|
|
98
|
+
const recentEvents = structuredState.recentEvents.length > 0
|
|
99
|
+
? structuredState.recentEvents.slice(-5).map(e => `- ${e}`).join('\n')
|
|
100
|
+
: 'None';
|
|
101
|
+
// Format tension guidance
|
|
102
|
+
const tensionText = `Target: ${targetTension}%
|
|
103
|
+
Guidance: ${tensionGuidance.guidance}
|
|
104
|
+
Scene Types: ${tensionGuidance.sceneTypes.join(', ')}
|
|
105
|
+
Pacing: ${tensionGuidance.pacingNotes}`;
|
|
106
|
+
// Format summaries (last 3)
|
|
107
|
+
const recentSummaries = summaries.slice(-3);
|
|
108
|
+
const summariesText = recentSummaries.length > 0
|
|
109
|
+
? recentSummaries.map(s => `Chapter ${s.chapterNumber}: ${s.summary}`).join('\n')
|
|
110
|
+
: 'No previous chapters.';
|
|
111
|
+
return STORY_DIRECTOR_PROMPT
|
|
112
|
+
.replace('{{title}}', bible.title)
|
|
113
|
+
.replace('{{genre}}', bible.genre)
|
|
114
|
+
.replace('{{theme}}', bible.theme)
|
|
115
|
+
.replace('{{premise}}', bible.premise)
|
|
116
|
+
.replace('{{currentChapter}}', state.currentChapter.toString())
|
|
117
|
+
.replace('{{totalChapters}}', state.totalChapters.toString())
|
|
118
|
+
.replace('{{storyTension}}', currentTension.toString())
|
|
119
|
+
.replace('{{targetTension}}', targetTension.toString())
|
|
120
|
+
.replace('{{plotThreads}}', activeThreads)
|
|
121
|
+
.replace('{{characters}}', characters)
|
|
122
|
+
.replace('{{questions}}', questions)
|
|
123
|
+
.replace('{{recentEvents}}', recentEvents)
|
|
124
|
+
.replace('{{tensionGuidance}}', tensionText)
|
|
125
|
+
.replace('{{summaries}}', summariesText)
|
|
126
|
+
.replace(/{{nextChapter}}/g, (state.currentChapter + 1).toString());
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Format director output for writer prompt
|
|
130
|
+
*/
|
|
131
|
+
formatForPrompt(output) {
|
|
132
|
+
const lines = ['## Chapter Direction'];
|
|
133
|
+
lines.push(`\n**Chapter ${output.chapterNumber} Goal:** ${output.overallGoal}`);
|
|
134
|
+
lines.push(`\n**Tone:** ${output.tone}`);
|
|
135
|
+
if (output.focusCharacters.length > 0) {
|
|
136
|
+
lines.push(`\n**Focus Characters:** ${output.focusCharacters.join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
if (output.objectives.length > 0) {
|
|
139
|
+
lines.push('\n**Objectives (in priority order):**');
|
|
140
|
+
const sorted = [...output.objectives].sort((a, b) => {
|
|
141
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
142
|
+
return priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
143
|
+
});
|
|
144
|
+
for (const obj of sorted) {
|
|
145
|
+
const emoji = { critical: '🔴', high: '🟠', medium: '🟡', low: '🟢' }[obj.priority];
|
|
146
|
+
lines.push(`${emoji} **[${obj.type.toUpperCase()}]** ${obj.description}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (output.suggestedScenes.length > 0) {
|
|
150
|
+
lines.push('\n**Suggested Scenes:**');
|
|
151
|
+
for (const scene of output.suggestedScenes) {
|
|
152
|
+
lines.push(`- ${scene}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (output.notes) {
|
|
156
|
+
lines.push(`\n**Director's Notes:** ${output.notes}`);
|
|
157
|
+
}
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Get quick objectives without LLM call (for testing/fallback)
|
|
162
|
+
*/
|
|
163
|
+
generateFallbackObjectives(state, structuredState) {
|
|
164
|
+
const nextChapter = state.currentChapter + 1;
|
|
165
|
+
const objectives = [];
|
|
166
|
+
// Add plot thread objectives
|
|
167
|
+
const activeThreads = Object.values(structuredState.plotThreads)
|
|
168
|
+
.filter(t => t.status === 'active' || t.status === 'escalating');
|
|
169
|
+
for (const thread of activeThreads.slice(0, 2)) {
|
|
170
|
+
objectives.push({
|
|
171
|
+
id: `plot-${thread.id}`,
|
|
172
|
+
description: `Advance the "${thread.name}" plot thread`,
|
|
173
|
+
priority: 'high',
|
|
174
|
+
type: 'plot',
|
|
175
|
+
relatedPlotThreadId: thread.id,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
// Add character objective
|
|
179
|
+
const characters = Object.values(structuredState.characters);
|
|
180
|
+
if (characters.length > 0) {
|
|
181
|
+
const char = characters[nextChapter % characters.length];
|
|
182
|
+
objectives.push({
|
|
183
|
+
id: `char-${char.name}`,
|
|
184
|
+
description: `Develop ${char.name}'s character arc`,
|
|
185
|
+
priority: 'medium',
|
|
186
|
+
type: 'character',
|
|
187
|
+
relatedCharacter: char.name,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// Add tension objective if needed
|
|
191
|
+
const targetTension = 4 * (nextChapter / state.totalChapters) * (1 - nextChapter / state.totalChapters);
|
|
192
|
+
if (structuredState.tension < targetTension - 0.2) {
|
|
193
|
+
objectives.push({
|
|
194
|
+
id: 'tension-escalate',
|
|
195
|
+
description: 'Escalate tension toward target level',
|
|
196
|
+
priority: 'high',
|
|
197
|
+
type: 'tension',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
chapterNumber: nextChapter,
|
|
202
|
+
overallGoal: `Advance the story toward chapter ${nextChapter} with focus on active plot threads`,
|
|
203
|
+
objectives,
|
|
204
|
+
focusCharacters: characters.slice(0, 2).map(c => c.name),
|
|
205
|
+
suggestedScenes: ['Opening scene establishing current situation', 'Development of main plot thread', 'Character interaction moment'],
|
|
206
|
+
tone: 'dramatic',
|
|
207
|
+
notes: 'Auto-generated objectives based on current story state',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.StoryDirector = StoryDirector;
|
|
212
|
+
exports.storyDirector = new StoryDirector();
|
|
213
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RvcnlEaXJlY3Rvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZ2VudHMvc3RvcnlEaXJlY3Rvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnREFBMEM7QUFnQzFDLE1BQU0scUJBQXFCLEdBQUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O3FGQWlFdUQsQ0FBQztBQUV0RixNQUFhLGFBQWE7SUFDeEIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxPQUF3QjtRQUNuQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsT0FBTyxDQUFDO1FBRXRGLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxlQUFlLEVBQUUsZUFBZSxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFFbkcsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFBLGtCQUFNLEdBQUUsQ0FBQyxZQUFZLENBQWlCLE1BQU0sRUFBRTtZQUNqRSxXQUFXLEVBQUUsR0FBRztZQUNoQixTQUFTLEVBQUUsSUFBSTtTQUNoQixDQUFDLENBQUM7UUFFSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRU8sV0FBVyxDQUNqQixLQUFpQixFQUNqQixLQUFpQixFQUNqQixlQUFxQyxFQUNyQyxlQUFnQyxFQUNoQyxTQUEyQjtRQUUzQixNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLGVBQWUsQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLENBQUM7UUFDakUsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsYUFBYSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBRXRFLHNCQUFzQjtRQUN0QixNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsTUFBTSxD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LGtCQUFrQjtnQkFDbkQsUUFBUSxFQUFFLFFBQVE7Z0JBQ2xCLElBQUksRUFBRSxXQUFXO2dCQUNqQixnQkFBZ0IsRUFBRSxJQUFJLENBQUMsSUFBSTthQUM1QixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsa0NBQWtDO1FBQ2xDLE1BQU0sYUFBYSxHQUFHLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUMsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsV0FBVyxHQUFHLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN4RyxJQUFJLGVBQWUsQ0FBQyxPQUFPLEdBQUcsYUFBYSxHQUFHLEdBQUcsRUFBRSxDQUFDO1lBQ2xELFVBQVUsQ0FBQyxJQUFJLENBQUM7Z0JBQ2QsRUFBRSxFQUFFLGtCQUFrQjtnQkFDdEIsV0FBVyxFQUFFLHNDQUFzQztnQkFDbkQsUUFBUSxFQUFFLE1BQU07Z0JBQ2hCLElBQUksRUFBRSxTQUFTO2FBQ2hCLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxPQUFPO1lBQ0wsYUFBYSxFQUFFLFdBQVc7WUFDMUIsV0FBVyxFQUFFLG9DQUFvQyxXQUFXLG9DQUFvQztZQUNoRyxVQUFVO1lBQ1YsZUFBZSxFQUFFLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFDeEQsZUFBZSxFQUFFLENBQUMsOENBQThDLEVBQUUsaUNBQWlDLEVBQUUsOEJBQThCLENBQUM7WUFDcEksSUFBSSxFQUFFLFVBQVU7WUFDaEIsS0FBSyxFQUFFLHdEQUF3RDtTQUNoRSxDQUFDO0lBQ0osQ0FBQztDQUNGO0FBN0tELHNDQTZLQztBQUVZLFFBQUEsYUFBYSxHQUFHLElBQUksYUFBYSxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBnZXRMTE0gfSBmcm9tICcuLi9sbG0vY2xpZW50LmpzJztcclxuaW1wb3J0IHR5cGUgeyBTdG9yeUJpYmxlLCBTdG9yeVN0YXRlLCBDaGFwdGVyU3VtbWFyeSB9IGZyb20gJy4uL3R5cGVzL2luZGV4LmpzJztcclxuaW1wb3J0IHR5cGUgeyBTdG9yeVN0cnVjdHVyZWRTdGF0ZSB9IGZyb20gJy4uL3N0b3J5L3N0cnVjdHVyZWRTdGF0ZS5qcyc7XHJcbmltcG9ydCB0eXBlIHsgVGVuc2lvbkd1aWRhbmNlIH0gZnJvbSAnLi90ZW5zaW9uQ29udHJvbGxlci5qcyc7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIENoYXB0ZXJPYmplY3RpdmUge1xyXG4gIGlkOiBzdHJpbmc7XHJcbiAgZGVzY3JpcHRpb246IHN0cmluZztcclxuICBwcmlvcml0eTogJ2NyaXRpY2FsJyB8ICdoaWdoJyB8ICdtZWRpdW0nIHwgJ2xvdyc7XHJcbiAgdHlwZTogJ3Bsb3QnIHwgJ2NoYXJhY3RlcicgfCAnd29ybGQnIHwgJ3RlbnNpb24nIHwgJ3Jlc29sdXRpb24nO1xyXG4gIHJlbGF0ZWRQbG90VGhyZWFkSWQ/OiBzdHJpbmc7XHJcbiAgcmVsYXRlZENoYXJhY3Rlcj86IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBEaXJlY3Rvck91dHB1dCB7XHJcbiAgY2hhcHRlck51bWJlcjogbnVtYmVyO1xyXG4gIG92ZXJhbGxHb2FsOiBzdHJpbmc7XHJcbiAgb2JqZWN0aXZlczogQ2hhcHRlck9iamVjdGl2ZVtdO1xyXG4gIGZvY3VzQ2hhcmFjdGVyczogc3RyaW5nW107XHJcbiAgc3VnZ2VzdGVkU2NlbmVzOiBzdHJpbmdbXTtcclxuICB0b25lOiBzdHJpbmc7XHJcbiAgbm90ZXM6IHN0cmluZztcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBEaXJlY3RvckNvbnRleHQge1xyXG4gIGJpYmxlOiBTdG9yeUJpYmxlO1xyXG4gIHN0YXRlOiBTdG9yeVN0YXRlO1xyXG4gIHN0cnVjdHVyZWRTdGF0ZTogU3RvcnlTdHJ1Y3R1cmVkU3RhdGU7XHJcbiAgdGVuc2lvbkd1aWRhbmNlOiBUZW5zaW9uR3VpZGFuY2U7XHJcbiAgcHJldmlvdXNTdW1tYXJpZXM6IENoYXB0ZXJTdW1tYXJ5W107XHJcbn1cclxuXHJcbmNvbnN0IFNUT1JZX0RJUkVDVE9SX1BST01QVCA9IGBZb3UgYXJlIHRoZSBTdG9yeSBEaXJlY3RvciBmb3IgYSBuYXJyYXRpdmUgQUkgc3lzdGVtLiBZb3VyIGpvYiBpcyB0byBkZWNpZGUgd2hhdCB0aGUgbmV4dCBjaGFwdGVyIHNob3VsZCBhY2NvbXBsaXNoLlxyXG5cclxuIyMgU3RvcnkgQmlibGVcclxuXHJcbioqVGl0bGU6Kioge3t0aXRsZX19XHJcbioqR2VucmU6Kioge3tnZW5yZX19XHJcbioqVGhlbWU6Kioge3t0aGVtZX19XHJcbioqUHJlbWlzZToqKiB7e3ByZW1pc2V9fVxyXG5cclxuIyMgQ3VycmVudCBTdG9yeSBTdGF0ZVxyXG5cclxuKipDaGFwdGVyOioqIHt7Y3VycmVudENoYXB0ZXJ9fSAvIHt7dG90YWxDaGFwdGVyc319XHJcbioqU3RvcnkgVGVuc2lvbjoqKiB7e3N0b3J5VGVuc2lvbn19JVxyXG4qKlRhcmdldCBUZW5zaW9uOioqIHt7dGFyZ2V0VGVuc2lvbn19JVxyXG5cclxuIyMjIEFjdGl2ZSBQbG90IFRocmVhZHNcclxue3twbG90VGhyZWFkc319XHJcblxyXG4jIyMgQ2hhcmFjdGVyIFN0YXRlc1xyXG57e2NoYXJhY3RlcnN9fVxyXG5cclxuIyMjIFVucmVzb2x2ZWQgUXVlc3Rpb25zXHJcbnt7cXVlc3Rpb25zfX1cclxuXHJcbiMjIyBSZWNlbnQgRXZlbnRzXHJcbnt7cmVjZW50RXZlbnRzfX1cclxuXHJcbiMjIFRlbnNpb24gR3VpZGFuY2VcclxuXHJcbnt7dGVuc2lvbkd1aWRhbmNlfX1cclxuXHJcbiMjIFByZXZpb3VzIENoYXB0ZXIgU3VtbWFyaWVzXHJcbnt7c3VtbWFyaWVzfX1cclxuXHJcbiMjIFlvdXIgVGFza1xyXG5cclxuQmFzZWQgb24gYWxsIHRoZSBhYm92ZSBpbmZvcm1hdGlvbiwgZGVjaWRlIHdoYXQgQ2hhcHRlciB7e25leHRDaGFwdGVyfX0gc2hvdWxkIGFjY29tcGxpc2guIENvbnNpZGVyOlxyXG5cclxuMS4gKipQbG90IFByb2dyZXNzaW9uKio6IFdoaWNoIHBsb3QgdGhyZWFkcyBuZWVkIGFkdmFuY2VtZW50P1xyXG4yLiAqKkNoYXJhY3RlciBEZXZlbG9wbWVudCoqOiBXaGljaCBjaGFyYWN0ZXJzIG5lZWQgZm9jdXMgb3IgZ3Jvd3RoP1xyXG4zLiAqKlRlbnNpb24gTWFuYWdlbWVudCoqOiBIb3cgc2hvdWxkIHRlbnNpb24gY2hhbmdlIGJhc2VkIG9uIHRhcmdldD9cclxuNC4gKipVbnJlc29sdmVkIFF1ZXN0aW9ucyoqOiBXaGljaCBteXN0ZXJpZXMgc2hvdWxkIGJlIGFkZHJlc3NlZD9cclxuNS4gKipTdG9yeSBBcmMqKjogV2hlcmUgYXJlIHdlIGluIHRoZSBvdmVyYWxsIG5hcnJhdGl2ZSAoc2V0dXAvcmlzaW5nIGFjdGlvbi9jbGltYXgvcmVzb2x1dGlvbik/XHJcblxyXG5PdXRwdXQgYSBKU09OIG9iamVjdCB3aXRoOlxyXG5cclxue1xyXG4gIFwiY2hhcHRlck51bWJlclwiOiB7e25leHRDaGFwdGVyfX0sXHJcbiAgXCJvdmVyYWxsR29hbFwiOiBcIk9uZS1zZW50ZW5jZSBkZXNjcmlwdGlvbiBvZiB3aGF0IHRoaXMgY2hhcHRlciBhY2hpZXZlc1wiLFxyXG4gIFwib2JqZWN0aXZlc1wiOiBbXHJcbiAgICB7XHJcbiAgICAgIFwiaWRcIjogXCJ1bmlxdWUtaWRcIixcclxuICAgICAgXCJkZXNjcmlwdGlvblwiOiBcIldoYXQgbmVlZHMgdG8gaGFwcGVuXCIsXHJcbiAgICAgIFwicHJpb3JpdHlcIjogXCJjcml0aWNhbHxoaWdofG1lZGl1bXxsb3dcIixcclxuICAgICAgXCJ0eXBlXCI6IFwicGxvdHxjaGFyYWN0ZXJ8d29ybGR8dGVuc2lvbnxyZXNvbHV0aW9uXCIsXHJcbiAgICAgIFwicmVsYXRlZFBsb3RUaHJlYWRJZFwiOiBcInRocmVhZC1pZCBvciBvbWl0XCIsXHJcbiAgICAgIFwicmVsYXRlZENoYXJhY3RlclwiOiBcImNoYXJhY3RlciBuYW1lIG9yIG9taXRcIlxyXG4gICAgfVxyXG4gIF0sXHJcbiAgXCJmb2N1c0NoYXJhY3RlcnNcIjogW1wiQ2hhcmFjdGVyIG5hbWVzIHRoYXQgc2hvdWxkIGJlIGNlbnRyYWxcIl0sXHJcbiAgXCJzdWdnZXN0ZWRTY2VuZXNcIjogW1wiU2NlbmUgaWRlYXMgdGhhdCBjb3VsZCBhY2hpZXZlIG9iamVjdGl2ZXNcIl0sXHJcbiAgXCJ0b25lXCI6IFwiZW1vdGlvbmFsIHRvbmUgZm9yIHRoaXMgY2hhcHRlclwiLFxyXG4gIFwibm90ZXNcIjogXCJBZGRpdGlvbmFsIGd1aWRhbmNlIGZvciB0aGUgd3JpdGVyXCJcclxufVxyXG5cclxuQmUgc3BlY2lmaWMgYW5kIGFjdGlvbmFibGUuIFRoZSB3cml0ZXIgd2lsbCB1c2UgeW91ciBkaXJlY3Rpb24gdG8gY3JhZnQgdGhlIGNoYXB0ZXIuYDtcclxuXHJcbmV4cG9ydCBjbGFzcyBTdG9yeURpcmVjdG9yIHtcclxuICBhc3luYyBkaXJlY3QoY29udGV4dDogRGlyZWN0b3JDb250ZXh0KTogUHJvbWlzZTxEaXJlY3Rvck91dHB1dD4ge1xyXG4gICAgY29uc3QgeyBiaWJsZSwgc3RhdGUsIHN0cnVjdHVyZWRTdGF0ZSwgdGVuc2lvbkd1aWRhbmNlLCBwcmV2aW91c1N1bW1hcmllcyB9ID0gY29udGV4dDtcclxuICAgIFxyXG4gICAgY29uc3QgcHJvbXB0ID0gdGhpcy5idWlsZFByb21wdChiaWJsZSwgc3RhdGUsIHN0cnVjdHVyZWRTdGF0ZSwgdGVuc2lvbkd1aWRhbmNlLCBwcmV2aW91c1N1bW1hcmllcyk7XHJcbiAgICBcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdldExMTSgpLmNvbXBsZXRlSlNPTjxEaXJlY3Rvck91dHB1dD4ocHJvbXB0LCB7XHJcbiAgICAgIHRlbXBlcmF0dXJlOiAwLjQsXHJcbiAgICAgIG1heFRva2VuczogMjAwMCxcclxuICAgIH0pO1xyXG4gICAgXHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuICBcclxuICBwcml2YXRlIGJ1aWxkUHJvbXB0KFxyXG4gICAgYmlibGU6IFN0b3J5QmlibGUsXHJcbiAgICBzdGF0ZTogU3RvcnlTdGF0ZSxcclxuICAgIHN0cnVjdHVyZWRTdGF0ZTogU3RvcnlTdHJ1Y3R1cmVkU3RhdGUsXHJcbiAgICB0ZW5zaW9uR3VpZGFuY2U6IFRlbnNpb25HdWlkYW5jZSxcclxuICAgIHN1bW1hcmllczogQ2hhcHRlclN1bW1hcnlbXVxyXG4gICk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBjdXJyZW50VGVuc2lvbiA9IE1hdGgucm91bmQoc3RydWN0dXJlZFN0YXRlLnRlbnNpb24gKiAxMDApO1xyXG4gICAgY29uc3QgdGFyZ2V0VGVuc2lvbiA9IE1hdGgucm91bmQodGVuc2lvbkd1aWRhbmNlLnRhcmdldFRlbnNpb24gKiAxMDApO1xyXG4gICAgXHJcbiAgICAvLyBGb3JtYXQgcGxvdCB0aHJlYWRzXHJcbiAgICBjb25zdCBhY3RpdmVUaHJlYWRzID0gT2JqZWN0LnZhbHVlcyhzdHJ1Y3R1cmVkU3RhdGUucGxvdFRocmVhZHMpXHJcbiAgICAgIC5maWx0ZXIodCA9PiB0LnN0YXR1cyAhPT0gJ3Jlc29sdmVkJylcclxuICAgICAgLm1hcCh0ID0+IGAtICoqJHt0Lm5hbWV9KiogKCR7dC5zdGF0dXN9LCAke01hdGgucm91bmQodC50ZW5zaW9uICogMTAwKX0lIHRlbnNpb24pOiAke3Quc3VtbWFyeX1gKVxyXG4gICAgICAuam9pbignXFxuJykgfHwgJ05vIGFjdGl2ZSBwbG90IHRocmVhZHMuJztcclxuICAgIFxyXG4gICAgLy8gRm9ybWF0IGNoYXJhY3RlcnNcclxuICAgIGNvbnN0IGNoYXJhY3RlcnMgPSBPYmplY3QudmFsdWVzKHN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzKVxyXG4gICAgICAubWFwKGMgPT4gYC0gKioke2MubmFtZX0qKjogJHtjLmVtb3Rpb25hbFN0YXRlfSwgYXQgJHtjLmxvY2F0aW9ufWApXHJcbiAgICAgIC5qb2luKCdcXG4nKSB8fCAnTm8gY2hhcmFjdGVyIGRhdGEuJztcclxuICAgIFxyXG4gICAgLy8gRm9ybWF0IHF1ZXN0aW9uc1xyXG4gICAgY29uc3QgcXVlc3Rpb25zID0gc3RydWN0dXJlZFN0YXRlLnVucmVzb2x2ZWRRdWVzdGlvbnMubGVuZ3RoID4gMFxyXG4gICAgICA/IHN0cnVjdHVyZWRTdGF0ZS51bnJlc29sdmVkUXVlc3Rpb25zLm1hcChxID0+IGAtICR7cX1gKS5qb2luKCdcXG4nKVxyXG4gICAgICA6ICdOb25lJztcclxuICAgIFxyXG4gICAgLy8gRm9ybWF0IHJlY2VudCBldmVudHNcclxuICAgIGNvbnN0IHJlY2VudEV2ZW50cyA9IHN0cnVjdHVyZWRTdGF0ZS5yZWNlbnRFdmVudHMubGVuZ3RoID4gMFxyXG4gICAgICA/IHN0cnVjdHVyZWRTdGF0ZS5yZWNlbnRFdmVudHMuc2xpY2UoLTUpLm1hcChlID0+IGAtICR7ZX1gKS5qb2luKCdcXG4nKVxyXG4gICAgICA6ICdOb25lJztcclxuICAgIFxyXG4gICAgLy8gRm9ybWF0IHRlbnNpb24gZ3VpZGFuY2VcclxuICAgIGNvbnN0IHRlbnNpb25UZXh0ID0gYFRhcmdldDogJHt0YXJnZXRUZW5zaW9ufSVcclxuR3VpZGFuY2U6ICR7dGVuc2lvbkd1aWRhbmNlLmd1aWRhbmNlfVxyXG5TY2VuZSBUeXBlczogJHt0ZW5zaW9uR3VpZGFuY2Uuc2NlbmVUeXBlcy5qb2luKCcsICcpfVxyXG5QYWNpbmc6ICR7dGVuc2lvbkd1aWRhbmNlLnBhY2luZ05vdGVzfWA7XHJcbiAgICBcclxuICAgIC8vIEZvcm1hdCBzdW1tYXJpZXMgKGxhc3QgMylcclxuICAgIGNvbnN0IHJlY2VudFN1bW1hcmllcyA9IHN1bW1hcmllcy5zbGljZSgtMyk7XHJcbiAgICBjb25zdCBzdW1tYXJpZXNUZXh0ID0gcmVjZW50U3VtbWFyaWVzLmxlbmd0aCA+IDBcclxuICAgICAgPyByZWNlbnRTdW1tYXJpZXMubWFwKHMgPT4gYENoYXB0ZXIgJHtzLmNoYXB0ZXJOdW1iZXJ9OiAke3Muc3VtbWFyeX1gKS5qb2luKCdcXG4nKVxyXG4gICAgICA6ICdObyBwcmV2aW91cyBjaGFwdGVycy4nO1xyXG4gICAgXHJcbiAgICByZXR1cm4gU1RPUllfRElSRUNUT1JfUFJPTVBUXHJcbiAgICAgIC5yZXBsYWNlKCd7e3RpdGxlfX0nLCBiaWJsZS50aXRsZSlcclxuICAgICAgLnJlcGxhY2UoJ3t7Z2VucmV9fScsIGJpYmxlLmdlbnJlKVxyXG4gICAgICAucmVwbGFjZSgne3t0aGVtZX19JywgYmlibGUudGhlbWUpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3ByZW1pc2V9fScsIGJpYmxlLnByZW1pc2UpXHJcbiAgICAgIC5yZXBsYWNlKCd7e2N1cnJlbnRDaGFwdGVyfX0nLCBzdGF0ZS5jdXJyZW50Q2hhcHRlci50b1N0cmluZygpKVxyXG4gICAgICAucmVwbGFjZSgne3t0b3RhbENoYXB0ZXJzfX0nLCBzdGF0ZS50b3RhbENoYXB0ZXJzLnRvU3RyaW5nKCkpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3N0b3J5VGVuc2lvbn19JywgY3VycmVudFRlbnNpb24udG9TdHJpbmcoKSlcclxuICAgICAgLnJlcGxhY2UoJ3t7dGFyZ2V0VGVuc2lvbn19JywgdGFyZ2V0VGVuc2lvbi50b1N0cmluZygpKVxyXG4gICAgICAucmVwbGFjZSgne3twbG90VGhyZWFkc319JywgYWN0aXZlVGhyZWFkcylcclxuICAgICAgLnJlcGxhY2UoJ3t7Y2hhcmFjdGVyc319JywgY2hhcmFjdGVycylcclxuICAgICAgLnJlcGxhY2UoJ3t7cXVlc3Rpb25zfX0nLCBxdWVzdGlvbnMpXHJcbiAgICAgIC5yZXBsYWNlKCd7e3JlY2VudEV2ZW50c319JywgcmVjZW50RXZlbnRzKVxyXG4gICAgICAucmVwbGFjZSgne3t0ZW5zaW9uR3VpZGFuY2V9fScsIHRlbnNpb25UZXh0KVxyXG4gICAgICAucmVwbGFjZSgne3tzdW1tYXJpZXN9fScsIHN1bW1hcmllc1RleHQpXHJcbiAgICAgIC5yZXBsYWNlKC97e25leHRDaGFwdGVyfX0vZywgKHN0YXRlLmN1cnJlbnRDaGFwdGVyICsgMSkudG9TdHJpbmcoKSk7XHJcbiAgfVxyXG4gIFxyXG4gIC8qKlxyXG4gICAqIEZvcm1hdCBkaXJlY3RvciBvdXRwdXQgZm9yIHdyaXRlciBwcm9tcHRcclxuICAgKi9cclxuICBmb3JtYXRGb3JQcm9tcHQob3V0cHV0OiBEaXJlY3Rvck91dHB1dCk6IHN0cmluZyB7XHJcbiAgICBjb25zdCBsaW5lczogc3RyaW5nW10gPSBbJyMjIENoYXB0ZXIgRGlyZWN0aW9uJ107XHJcbiAgICBcclxuICAgIGxpbmVzLnB1c2goYFxcbioqQ2hhcHRlciAke291dHB1dC5jaGFwdGVyTnVtYmVyfSBHb2FsOioqICR7b3V0cHV0Lm92ZXJhbGxHb2FsfWApO1xyXG4gICAgbGluZXMucHVzaChgXFxuKipUb25lOioqICR7b3V0cHV0LnRvbmV9YCk7XHJcbiAgICBcclxuICAgIGlmIChvdXRwdXQuZm9jdXNDaGFyYWN0ZXJzLmxlbmd0aCA+IDApIHtcclxuICAgICAgbGluZXMucHVzaChgXFxuKipGb2N1cyBDaGFyYWN0ZXJzOioqICR7b3V0cHV0LmZvY3VzQ2hhcmFjdGVycy5qb2luKCcsICcpfWApO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBpZiAob3V0cHV0Lm9iamVjdGl2ZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICBsaW5lcy5wdXNoKCdcXG4qKk9iamVjdGl2ZXMgKGluIHByaW9yaXR5IG9yZGVyKToqKicpO1xyXG4gICAgICBjb25zdCBzb3J0ZWQgPSBbLi4ub3V0cHV0Lm9iamVjdGl2ZXNdLnNvcnQoKGEsIGIpID0+IHtcclxuICAgICAgICBjb25zdCBwcmlvcml0eU9yZGVyID0geyBjcml0aWNhbDogMCwgaGlnaDogMSwgbWVkaXVtOiAyLCBsb3c6IDMgfTtcclxuICAgICAgICByZXR1cm4gcHJpb3JpdHlPcmRlclthLnByaW9yaXR5XSAtIHByaW9yaXR5T3JkZXJbYi5wcmlvcml0eV07XHJcbiAgICAgIH0pO1xyXG4gICAgICBcclxuICAgICAgZm9yIChjb25zdCBvYmogb2Ygc29ydGVkKSB7XHJcbiAgICAgICAgY29uc3QgZW1vamkgPSB7IGNyaXRpY2FsOiAn8J+UtCcsIGhpZ2g6ICfwn5+gJywgbWVkaXVtOiAn8J+foScsIGxvdzogJ/Cfn6InIH1bb2JqLnByaW9yaXR5XTtcclxuICAgICAgICBsaW5lcy5wdXNoKGAke2Vtb2ppfSAqKlske29iai50eXBlLnRvVXBwZXJDYXNlKCl9XSoqICR7b2JqLmRlc2NyaXB0aW9ufWApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBcclxuICAgIGlmIChvdXRwdXQuc3VnZ2VzdGVkU2NlbmVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgbGluZXMucHVzaCgnXFxuKipTdWdnZXN0ZWQgU2NlbmVzOioqJyk7XHJcbiAgICAgIGZvciAoY29uc3Qgc2NlbmUgb2Ygb3V0cHV0LnN1Z2dlc3RlZFNjZW5lcykge1xyXG4gICAgICAgIGxpbmVzLnB1c2goYC0gJHtzY2VuZX1gKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgXHJcbiAgICBpZiAob3V0cHV0Lm5vdGVzKSB7XHJcbiAgICAgIGxpbmVzLnB1c2goYFxcbioqRGlyZWN0b3IncyBOb3RlczoqKiAke291dHB1dC5ub3Rlc31gKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xyXG4gIH1cclxuICBcclxuICAvKipcclxuICAgKiBHZXQgcXVpY2sgb2JqZWN0aXZlcyB3aXRob3V0IExMTSBjYWxsIChmb3IgdGVzdGluZy9mYWxsYmFjaylcclxuICAgKi9cclxuICBnZW5lcmF0ZUZhbGxiYWNrT2JqZWN0aXZlcyhcclxuICAgIHN0YXRlOiBTdG9yeVN0YXRlLFxyXG4gICAgc3RydWN0dXJlZFN0YXRlOiBTdG9yeVN0cnVjdHVyZWRTdGF0ZVxyXG4gICk6IERpcmVjdG9yT3V0cHV0IHtcclxuICAgIGNvbnN0IG5leHRDaGFwdGVyID0gc3RhdGUuY3VycmVudENoYXB0ZXIgKyAxO1xyXG4gICAgY29uc3Qgb2JqZWN0aXZlczogQ2hhcHRlck9iamVjdGl2ZVtdID0gW107XHJcbiAgICBcclxuICAgIC8vIEFkZCBwbG90IHRocmVhZCBvYmplY3RpdmVzXHJcbiAgICBjb25zdCBhY3RpdmVUaHJlYWRzID0gT2JqZWN0LnZhbHVlcyhzdHJ1Y3R1cmVkU3RhdGUucGxvdFRocmVhZHMpXHJcbiAgICAgIC5maWx0ZXIodCA9PiB0LnN0YXR1cyA9PT0gJ2FjdGl2ZScgfHwgdC5zdGF0dXMgPT09ICdlc2NhbGF0aW5nJyk7XHJcbiAgICBcclxuICAgIGZvciAoY29uc3QgdGhyZWFkIG9mIGFjdGl2ZVRocmVhZHMuc2xpY2UoMCwgMikpIHtcclxuICAgICAgb2JqZWN0aXZlcy5wdXNoKHtcclxuICAgICAgICBpZDogYHBsb3QtJHt0aHJlYWQuaWR9YCxcclxuICAgICAgICBkZXNjcmlwdGlvbjogYEFkdmFuY2UgdGhlIFwiJHt0aHJlYWQubmFtZX1cIiBwbG90IHRocmVhZGAsXHJcbiAgICAgICAgcHJpb3JpdHk6ICdoaWdoJyxcclxuICAgICAgICB0eXBlOiAncGxvdCcsXHJcbiAgICAgICAgcmVsYXRlZFBsb3RUaHJlYWRJZDogdGhyZWFkLmlkLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLy8gQWRkIGNoYXJhY3RlciBvYmplY3RpdmVcclxuICAgIGNvbnN0IGNoYXJhY3RlcnMgPSBPYmplY3QudmFsdWVzKHN0cnVjdHVyZWRTdGF0ZS5jaGFyYWN0ZXJzKTtcclxuICAgIGlmIChjaGFyYWN0ZXJzLmxlbmd0aCA+IDApIHtcclxuICAgICAgY29uc3QgY2hhciA9IGNoYXJhY3RlcnNbbmV4dENoYXB0ZXIgJSBjaGFyYWN0ZXJzLmxlbmd0aF07XHJcbiAgICAgIG9iamVjdGl2ZXMucHVzaCh7XHJcbiAgICAgICAgaWQ6IGBjaGFyLSR7Y2hhci5uYW1lfWAsXHJcbiAgICAgICAgZGVzY3JpcHRpb246IGBEZXZlbG9wICR7Y2hhci5uYW1lfSdzIGNoYXJhY3RlciBhcmNgLFxyXG4gICAgICAgIHByaW9yaXR5OiAnbWVkaXVtJyxcclxuICAgICAgICB0eXBlOiAnY2hhcmFjdGVyJyxcclxuICAgICAgICByZWxhdGVkQ2hhcmFjdGVyOiBjaGFyLm5hbWUsXHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAvLyBBZGQgdGVuc2lvbiBvYmplY3RpdmUgaWYgbmVlZGVkXHJcbiAgICBjb25zdCB0YXJnZXRUZW5zaW9uID0gNCAqIChuZXh0Q2hhcHRlciAvIHN0YXRlLnRvdGFsQ2hhcHRlcnMpICogKDEgLSBuZXh0Q2hhcHRlciAvIHN0YXRlLnRvdGFsQ2hhcHRlcnMpO1xyXG4gICAgaWYgKHN0cnVjdHVyZWRTdGF0ZS50ZW5zaW9uIDwgdGFyZ2V0VGVuc2lvbiAtIDAuMikge1xyXG4gICAgICBvYmplY3RpdmVzLnB1c2goe1xyXG4gICAgICAgIGlkOiAndGVuc2lvbi1lc2NhbGF0ZScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFc2NhbGF0ZSB0ZW5zaW9uIHRvd2FyZCB0YXJnZXQgbGV2ZWwnLFxyXG4gICAgICAgIHByaW9yaXR5OiAnaGlnaCcsXHJcbiAgICAgICAgdHlwZTogJ3RlbnNpb24nLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgY2hhcHRlck51bWJlcjogbmV4dENoYXB0ZXIsXHJcbiAgICAgIG92ZXJhbGxHb2FsOiBgQWR2YW5jZSB0aGUgc3RvcnkgdG93YXJkIGNoYXB0ZXIgJHtuZXh0Q2hhcHRlcn0gd2l0aCBmb2N1cyBvbiBhY3RpdmUgcGxvdCB0aHJlYWRzYCxcclxuICAgICAgb2JqZWN0aXZlcyxcclxuICAgICAgZm9jdXNDaGFyYWN0ZXJzOiBjaGFyYWN0ZXJzLnNsaWNlKDAsIDIpLm1hcChjID0+IGMubmFtZSksXHJcbiAgICAgIHN1Z2dlc3RlZFNjZW5lczogWydPcGVuaW5nIHNjZW5lIGVzdGFibGlzaGluZyBjdXJyZW50IHNpdHVhdGlvbicsICdEZXZlbG9wbWVudCBvZiBtYWluIHBsb3QgdGhyZWFkJywgJ0NoYXJhY3RlciBpbnRlcmFjdGlvbiBtb21lbnQnXSxcclxuICAgICAgdG9uZTogJ2RyYW1hdGljJyxcclxuICAgICAgbm90ZXM6ICdBdXRvLWdlbmVyYXRlZCBvYmplY3RpdmVzIGJhc2VkIG9uIGN1cnJlbnQgc3Rvcnkgc3RhdGUnLFxyXG4gICAgfTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBjb25zdCBzdG9yeURpcmVjdG9yID0gbmV3IFN0b3J5RGlyZWN0b3IoKTtcclxuIl19
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ChapterSummary } from '../types/index.js';
|
|
2
|
+
export declare class ChapterSummarizer {
|
|
3
|
+
private promptTemplate;
|
|
4
|
+
constructor();
|
|
5
|
+
summarize(chapterText: string, chapterNumber: number): Promise<ChapterSummary>;
|
|
6
|
+
private extractKeyEvents;
|
|
7
|
+
}
|
|
8
|
+
export declare const summarizer: ChapterSummarizer;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.summarizer = exports.ChapterSummarizer = void 0;
|
|
4
|
+
const client_js_1 = require("../llm/client.js");
|
|
5
|
+
const SUMMARIZER_PROMPT = `Summarize the following chapter in under 120 tokens.
|
|
6
|
+
|
|
7
|
+
Focus on:
|
|
8
|
+
- Major events that occurred
|
|
9
|
+
- Plot progress made
|
|
10
|
+
- Important character changes or revelations
|
|
11
|
+
|
|
12
|
+
## Chapter Text
|
|
13
|
+
|
|
14
|
+
{{chapterText}}
|
|
15
|
+
|
|
16
|
+
## Summary`;
|
|
17
|
+
class ChapterSummarizer {
|
|
18
|
+
promptTemplate;
|
|
19
|
+
constructor() {
|
|
20
|
+
this.promptTemplate = SUMMARIZER_PROMPT;
|
|
21
|
+
}
|
|
22
|
+
async summarize(chapterText, chapterNumber) {
|
|
23
|
+
const prompt = this.promptTemplate.replace('{{chapterText}}', chapterText);
|
|
24
|
+
const summary = await (0, client_js_1.getLLM)().complete(prompt, {
|
|
25
|
+
temperature: 0.3,
|
|
26
|
+
maxTokens: 200,
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
chapterNumber,
|
|
30
|
+
summary: summary.trim(),
|
|
31
|
+
keyEvents: this.extractKeyEvents(chapterText),
|
|
32
|
+
characterChanges: {},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
extractKeyEvents(text) {
|
|
36
|
+
const sentences = text.match(/[^.!?]+[.!?]+/g) || [];
|
|
37
|
+
const events = [];
|
|
38
|
+
for (const sentence of sentences.slice(0, 20)) {
|
|
39
|
+
const lower = sentence.toLowerCase();
|
|
40
|
+
if (lower.includes('discovered') ||
|
|
41
|
+
lower.includes('realized') ||
|
|
42
|
+
lower.includes('decided') ||
|
|
43
|
+
lower.includes('arrived') ||
|
|
44
|
+
lower.includes('found') ||
|
|
45
|
+
lower.includes('learned')) {
|
|
46
|
+
events.push(sentence.trim());
|
|
47
|
+
}
|
|
48
|
+
if (events.length >= 3)
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
return events;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.ChapterSummarizer = ChapterSummarizer;
|
|
55
|
+
exports.summarizer = new ChapterSummarizer();
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VtbWFyaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZ2VudHMvc3VtbWFyaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSxnREFBMEM7QUFHMUMsTUFBTSxpQkFBaUIsR0FBRzs7Ozs7Ozs7Ozs7V0FXZixDQUFDO0FBRVosTUFBYSxpQkFBaUI7SUFDcEIsY0FBYyxDQUFTO0lBRS9CO1FBQ0UsSUFBSSxDQUFDLGNBQWMsR0FBRyxpQkFBaUIsQ0FBQztJQUMxQyxDQUFDO0lBRUQsS0FBSyxDQUFDLFNBQVMsQ0FBQyxXQUFtQixFQUFFLGFBQXFCO1FBQ3hELE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLGlCQUFpQixFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRTNFLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBQSxrQkFBTSxHQUFFLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRTtZQUM5QyxXQUFXLEVBQUUsR0FBRztZQUNoQixTQUFTLEVBQUUsR0FBRztTQUNmLENBQUMsQ0FBQztRQUVILE9BQU87WUFDTCxhQUFhO1lBQ2IsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLEVBQUU7WUFDdkIsU0FBUyxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUM7WUFDN0MsZ0JBQWdCLEVBQUUsRUFBRTtTQUNyQixDQUFDO0lBQ0osQ0FBQztJQUVPLGdCQUFnQixDQUFDLElBQVk7UUFDbkMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNyRCxNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7UUFFNUIsS0FBSyxNQUFNLFFBQVEsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQzlDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQyxJQUNFLEtBQUssQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDO2dCQUM1QixLQUFLLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQztnQkFDMUIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUM7Z0JBQ3pCLEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDO2dCQUN6QixLQUFLLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQztnQkFDdkIsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsRUFDekIsQ0FBQztnQkFDRCxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLENBQUM7WUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLElBQUksQ0FBQztnQkFBRSxNQUFNO1FBQ2hDLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0NBQ0Y7QUE1Q0QsOENBNENDO0FBRVksUUFBQSxVQUFVLEdBQUcsSUFBSSxpQkFBaUIsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZ2V0TExNIH0gZnJvbSAnLi4vbGxtL2NsaWVudC5qcyc7XHJcbmltcG9ydCB0eXBlIHsgQ2hhcHRlclN1bW1hcnkgfSBmcm9tICcuLi90eXBlcy9pbmRleC5qcyc7XHJcblxyXG5jb25zdCBTVU1NQVJJWkVSX1BST01QVCA9IGBTdW1tYXJpemUgdGhlIGZvbGxvd2luZyBjaGFwdGVyIGluIHVuZGVyIDEyMCB0b2tlbnMuXHJcblxyXG5Gb2N1cyBvbjpcclxuLSBNYWpvciBldmVudHMgdGhhdCBvY2N1cnJlZFxyXG4tIFBsb3QgcHJvZ3Jlc3MgbWFkZVxyXG4tIEltcG9ydGFudCBjaGFyYWN0ZXIgY2hhbmdlcyBvciByZXZlbGF0aW9uc1xyXG5cclxuIyMgQ2hhcHRlciBUZXh0XHJcblxyXG57e2NoYXB0ZXJUZXh0fX1cclxuXHJcbiMjIFN1bW1hcnlgO1xyXG5cclxuZXhwb3J0IGNsYXNzIENoYXB0ZXJTdW1tYXJpemVyIHtcclxuICBwcml2YXRlIHByb21wdFRlbXBsYXRlOiBzdHJpbmc7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5wcm9tcHRUZW1wbGF0ZSA9IFNVTU1BUklaRVJfUFJPTVBUO1xyXG4gIH1cclxuXHJcbiAgYXN5bmMgc3VtbWFyaXplKGNoYXB0ZXJUZXh0OiBzdHJpbmcsIGNoYXB0ZXJOdW1iZXI6IG51bWJlcik6IFByb21pc2U8Q2hhcHRlclN1bW1hcnk+IHtcclxuICAgIGNvbnN0IHByb21wdCA9IHRoaXMucHJvbXB0VGVtcGxhdGUucmVwbGFjZSgne3tjaGFwdGVyVGV4dH19JywgY2hhcHRlclRleHQpO1xyXG5cclxuICAgIGNvbnN0IHN1bW1hcnkgPSBhd2FpdCBnZXRMTE0oKS5jb21wbGV0ZShwcm9tcHQsIHtcclxuICAgICAgdGVtcGVyYXR1cmU6IDAuMyxcclxuICAgICAgbWF4VG9rZW5zOiAyMDAsXHJcbiAgICB9KTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBjaGFwdGVyTnVtYmVyLFxyXG4gICAgICBzdW1tYXJ5OiBzdW1tYXJ5LnRyaW0oKSxcclxuICAgICAga2V5RXZlbnRzOiB0aGlzLmV4dHJhY3RLZXlFdmVudHMoY2hhcHRlclRleHQpLFxyXG4gICAgICBjaGFyYWN0ZXJDaGFuZ2VzOiB7fSxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGV4dHJhY3RLZXlFdmVudHModGV4dDogc3RyaW5nKTogc3RyaW5nW10ge1xyXG4gICAgY29uc3Qgc2VudGVuY2VzID0gdGV4dC5tYXRjaCgvW14uIT9dK1suIT9dKy9nKSB8fCBbXTtcclxuICAgIGNvbnN0IGV2ZW50czogc3RyaW5nW10gPSBbXTtcclxuICAgIFxyXG4gICAgZm9yIChjb25zdCBzZW50ZW5jZSBvZiBzZW50ZW5jZXMuc2xpY2UoMCwgMjApKSB7XHJcbiAgICAgIGNvbnN0IGxvd2VyID0gc2VudGVuY2UudG9Mb3dlckNhc2UoKTtcclxuICAgICAgaWYgKFxyXG4gICAgICAgIGxvd2VyLmluY2x1ZGVzKCdkaXNjb3ZlcmVkJykgfHxcclxuICAgICAgICBsb3dlci5pbmNsdWRlcygncmVhbGl6ZWQnKSB8fFxyXG4gICAgICAgIGxvd2VyLmluY2x1ZGVzKCdkZWNpZGVkJykgfHxcclxuICAgICAgICBsb3dlci5pbmNsdWRlcygnYXJyaXZlZCcpIHx8XHJcbiAgICAgICAgbG93ZXIuaW5jbHVkZXMoJ2ZvdW5kJykgfHxcclxuICAgICAgICBsb3dlci5pbmNsdWRlcygnbGVhcm5lZCcpXHJcbiAgICAgICkge1xyXG4gICAgICAgIGV2ZW50cy5wdXNoKHNlbnRlbmNlLnRyaW0oKSk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGV2ZW50cy5sZW5ndGggPj0gMykgYnJlYWs7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIHJldHVybiBldmVudHM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgY29uc3Qgc3VtbWFyaXplciA9IG5ldyBDaGFwdGVyU3VtbWFyaXplcigpO1xyXG4iXX0=
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Chapter, StoryState } from '../types/index.js';
|
|
2
|
+
import type { StoryStructuredState } from '../story/structuredState.js';
|
|
3
|
+
export interface TensionAnalysis {
|
|
4
|
+
currentTension: number;
|
|
5
|
+
targetTension: number;
|
|
6
|
+
tensionGap: number;
|
|
7
|
+
recommendedAction: 'escalate' | 'maintain' | 'resolve' | 'climax';
|
|
8
|
+
reasoning: string;
|
|
9
|
+
}
|
|
10
|
+
export interface TensionGuidance {
|
|
11
|
+
targetTension: number;
|
|
12
|
+
guidance: string;
|
|
13
|
+
sceneTypes: string[];
|
|
14
|
+
pacingNotes: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Calculate target tension using parabolic curve
|
|
18
|
+
* Formula: targetTension = 4 * progress * (1 - progress)
|
|
19
|
+
*
|
|
20
|
+
* This creates a natural dramatic arc:
|
|
21
|
+
* - Chapter 0: 0% tension (setup)
|
|
22
|
+
* - Middle chapters: ~100% tension (peak drama)
|
|
23
|
+
* - Final chapter: 0% tension (resolution)
|
|
24
|
+
*/
|
|
25
|
+
export declare function calculateTargetTension(currentChapter: number, totalChapters: number): number;
|
|
26
|
+
/**
|
|
27
|
+
* Calculate tension for next chapter based on ideal arc
|
|
28
|
+
*/
|
|
29
|
+
export declare function calculateNextChapterTension(currentChapter: number, totalChapters: number): number;
|
|
30
|
+
/**
|
|
31
|
+
* Analyze current tension vs target and provide guidance
|
|
32
|
+
*/
|
|
33
|
+
export declare function analyzeTension(storyState: StoryState, structuredState: StoryStructuredState): TensionAnalysis;
|
|
34
|
+
/**
|
|
35
|
+
* Generate tension guidance for the writer
|
|
36
|
+
*/
|
|
37
|
+
export declare function generateTensionGuidance(analysis: TensionAnalysis, storyState: StoryState): TensionGuidance;
|
|
38
|
+
/**
|
|
39
|
+
* Format tension guidance for writer prompt
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatTensionForPrompt(guidance: TensionGuidance): string;
|
|
42
|
+
/**
|
|
43
|
+
* Calculate tension based on chapter content analysis
|
|
44
|
+
* This is a heuristic for estimating tension from text
|
|
45
|
+
*/
|
|
46
|
+
export declare function estimateTensionFromChapter(chapter: Chapter): number;
|
|
47
|
+
/**
|
|
48
|
+
* TensionController class for managing story tension
|
|
49
|
+
*/
|
|
50
|
+
export declare class TensionController {
|
|
51
|
+
/**
|
|
52
|
+
* Analyze current story state and provide tension guidance
|
|
53
|
+
*/
|
|
54
|
+
analyze(storyState: StoryState, structuredState: StoryStructuredState): TensionAnalysis;
|
|
55
|
+
/**
|
|
56
|
+
* Generate guidance for the next chapter
|
|
57
|
+
*/
|
|
58
|
+
generateGuidance(storyState: StoryState, structuredState: StoryStructuredState): TensionGuidance;
|
|
59
|
+
/**
|
|
60
|
+
* Calculate what the tension should be for a specific chapter
|
|
61
|
+
*/
|
|
62
|
+
calculateTarget(chapterNumber: number, totalChapters: number): number;
|
|
63
|
+
/**
|
|
64
|
+
* Estimate tension from chapter content
|
|
65
|
+
*/
|
|
66
|
+
estimateFromContent(chapter: Chapter): number;
|
|
67
|
+
}
|
|
68
|
+
export declare const tensionController: TensionController;
|