Jelajahi Sumber

fix: dynamic maxTokens + close N-2/N-3 summary gap

maxTokens scales with chapter word count: creative phase uses
max(8192, targetWords*2), settler uses max(8192, contentLength*0.8).

findRelevantSummaries cutoff changed from chapterNumber-3 to
chapterNumber-1, so N-2 and N-3 chapter summaries are no longer
filtered out (they had no full text and no summary — a context hole).
Ma 7 bulan lalu
induk
melakukan
f1a0c670a1
1 mengubah file dengan 11 tambahan dan 5 penghapusan
  1. 11 5
      packages/core/src/agents/writer.ts

+ 11 - 5
packages/core/src/agents/writer.ts

@@ -111,12 +111,16 @@ export class WriterAgent extends BaseAgent {
 
 
     process.stderr.write(`[writer] Phase 1: creative writing for chapter ${chapterNumber}\n`);
     process.stderr.write(`[writer] Phase 1: creative writing for chapter ${chapterNumber}\n`);
 
 
+    // Scale maxTokens to chapter word count (Chinese ≈ 1.5 tokens/char)
+    const targetWords = input.wordCountOverride ?? book.chapterWordCount;
+    const creativeMaxTokens = Math.max(8192, Math.ceil(targetWords * 2));
+
     const creativeResponse = await this.chat(
     const creativeResponse = await this.chat(
       [
       [
         { role: "system", content: creativeSystemPrompt },
         { role: "system", content: creativeSystemPrompt },
         { role: "user", content: creativeUserPrompt },
         { role: "user", content: creativeUserPrompt },
       ],
       ],
-      { maxTokens: 8192, temperature: creativeTemperature },
+      { maxTokens: creativeMaxTokens, temperature: creativeTemperature },
     );
     );
 
 
     const creative = parseCreativeOutput(chapterNumber, creativeResponse.content);
     const creative = parseCreativeOutput(chapterNumber, creativeResponse.content);
@@ -219,12 +223,15 @@ export class WriterAgent extends BaseAgent {
       volumeOutline: params.volumeOutline,
       volumeOutline: params.volumeOutline,
     });
     });
 
 
+    // Settler outputs all truth files — scale with content size
+    const settlerMaxTokens = Math.max(8192, Math.ceil(params.content.length * 0.8));
+
     const response = await this.chat(
     const response = await this.chat(
       [
       [
         { role: "system", content: settlerSystem },
         { role: "system", content: settlerSystem },
         { role: "user", content: settlerUser },
         { role: "user", content: settlerUser },
       ],
       ],
-      { maxTokens: 8192, temperature: 0.3 },
+      { maxTokens: settlerMaxTokens, temperature: 0.3 },
     );
     );
 
 
     return parseSettlementOutput(response.content, params.genreProfile);
     return parseSettlementOutput(response.content, params.genreProfile);
@@ -559,13 +566,12 @@ ${params.volumeOutline}
       return false;
       return false;
     });
     });
 
 
-    // Skip rows for the current chapter and recent chapters (they're already in context)
-    const recentCutoff = Math.max(1, chapterNumber - 3);
+    // Skip only the last chapter (its full text is already in context via loadRecentChapters)
     const filteredRows = matchedRows.filter((row) => {
     const filteredRows = matchedRows.filter((row) => {
       const chNumMatch = row.match(/\|\s*(\d+)\s*\|/);
       const chNumMatch = row.match(/\|\s*(\d+)\s*\|/);
       if (!chNumMatch) return true;
       if (!chNumMatch) return true;
       const num = parseInt(chNumMatch[1]!, 10);
       const num = parseInt(chNumMatch[1]!, 10);
-      return num < recentCutoff;
+      return num < chapterNumber - 1;
     });
     });
 
 
     return filteredRows.length > 0 ? filteredRows.join("\n") : "";
     return filteredRows.length > 0 ? filteredRows.join("\n") : "";