@actalk/inkos-core 1.3.6 → 1.3.7
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/agent/agent-session.d.ts +7 -7
- package/dist/agent/agent-session.d.ts.map +1 -1
- package/dist/agent/agent-session.js +392 -63
- package/dist/agent/agent-session.js.map +1 -1
- package/dist/agent/agent-system-prompt.d.ts.map +1 -1
- package/dist/agent/agent-system-prompt.js +20 -16
- package/dist/agent/agent-system-prompt.js.map +1 -1
- package/dist/agent/agent-tools.d.ts +4 -1
- package/dist/agent/agent-tools.d.ts.map +1 -1
- package/dist/agent/agent-tools.js +81 -64
- package/dist/agent/agent-tools.js.map +1 -1
- package/dist/agents/architect.d.ts +18 -20
- package/dist/agents/architect.d.ts.map +1 -1
- package/dist/agents/architect.js +513 -632
- package/dist/agents/architect.js.map +1 -1
- package/dist/agents/chapter-analyzer.d.ts.map +1 -1
- package/dist/agents/chapter-analyzer.js +10 -6
- package/dist/agents/chapter-analyzer.js.map +1 -1
- package/dist/agents/composer.d.ts +1 -13
- package/dist/agents/composer.d.ts.map +1 -1
- package/dist/agents/composer.js +297 -290
- package/dist/agents/composer.js.map +1 -1
- package/dist/agents/consolidator.d.ts +17 -1
- package/dist/agents/consolidator.d.ts.map +1 -1
- package/dist/agents/consolidator.js +44 -6
- package/dist/agents/consolidator.js.map +1 -1
- package/dist/agents/continuity.d.ts +4 -1
- package/dist/agents/continuity.d.ts.map +1 -1
- package/dist/agents/continuity.js +111 -21
- package/dist/agents/continuity.js.map +1 -1
- package/dist/agents/length-normalizer.d.ts.map +1 -1
- package/dist/agents/length-normalizer.js +1 -4
- package/dist/agents/length-normalizer.js.map +1 -1
- package/dist/agents/planner-context.d.ts +54 -0
- package/dist/agents/planner-context.d.ts.map +1 -0
- package/dist/agents/planner-context.js +245 -0
- package/dist/agents/planner-context.js.map +1 -0
- package/dist/agents/planner-prompts.d.ts +36 -0
- package/dist/agents/planner-prompts.d.ts.map +1 -0
- package/dist/agents/planner-prompts.js +350 -0
- package/dist/agents/planner-prompts.js.map +1 -0
- package/dist/agents/planner.d.ts +39 -11
- package/dist/agents/planner.d.ts.map +1 -1
- package/dist/agents/planner.js +212 -195
- package/dist/agents/planner.js.map +1 -1
- package/dist/agents/polisher.d.ts +33 -0
- package/dist/agents/polisher.d.ts.map +1 -0
- package/dist/agents/polisher.js +122 -0
- package/dist/agents/polisher.js.map +1 -0
- package/dist/agents/post-write-validator.d.ts +1 -0
- package/dist/agents/post-write-validator.d.ts.map +1 -1
- package/dist/agents/post-write-validator.js +13 -0
- package/dist/agents/post-write-validator.js.map +1 -1
- package/dist/agents/reviser.d.ts +6 -2
- package/dist/agents/reviser.d.ts.map +1 -1
- package/dist/agents/reviser.js +379 -98
- package/dist/agents/reviser.js.map +1 -1
- package/dist/agents/rules-reader.d.ts +15 -2
- package/dist/agents/rules-reader.d.ts.map +1 -1
- package/dist/agents/rules-reader.js +49 -6
- package/dist/agents/rules-reader.js.map +1 -1
- package/dist/agents/state-validator.d.ts +9 -1
- package/dist/agents/state-validator.d.ts.map +1 -1
- package/dist/agents/state-validator.js +37 -1
- package/dist/agents/state-validator.js.map +1 -1
- package/dist/agents/writer-prompts.d.ts +1 -0
- package/dist/agents/writer-prompts.d.ts.map +1 -1
- package/dist/agents/writer-prompts.js +272 -29
- package/dist/agents/writer-prompts.js.map +1 -1
- package/dist/agents/writer.d.ts +12 -3
- package/dist/agents/writer.d.ts.map +1 -1
- package/dist/agents/writer.js +77 -107
- package/dist/agents/writer.js.map +1 -1
- package/dist/index.d.ts +20 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -5
- package/dist/index.js.map +1 -1
- package/dist/interaction/book-session-store.d.ts.map +1 -1
- package/dist/interaction/book-session-store.js +84 -69
- package/dist/interaction/book-session-store.js.map +1 -1
- package/dist/interaction/events.d.ts +2 -2
- package/dist/interaction/project-tools.d.ts +1 -0
- package/dist/interaction/project-tools.d.ts.map +1 -1
- package/dist/interaction/project-tools.js +51 -3
- package/dist/interaction/project-tools.js.map +1 -1
- package/dist/interaction/session-transcript-legacy.d.ts +4 -0
- package/dist/interaction/session-transcript-legacy.d.ts.map +1 -0
- package/dist/interaction/session-transcript-legacy.js +100 -0
- package/dist/interaction/session-transcript-legacy.js.map +1 -0
- package/dist/interaction/session-transcript-restore.d.ts +17 -0
- package/dist/interaction/session-transcript-restore.d.ts.map +1 -0
- package/dist/interaction/session-transcript-restore.js +493 -0
- package/dist/interaction/session-transcript-restore.js.map +1 -0
- package/dist/interaction/session-transcript-schema.d.ts +402 -0
- package/dist/interaction/session-transcript-schema.d.ts.map +1 -0
- package/dist/interaction/session-transcript-schema.js +59 -0
- package/dist/interaction/session-transcript-schema.js.map +1 -0
- package/dist/interaction/session-transcript.d.ts +14 -0
- package/dist/interaction/session-transcript.d.ts.map +1 -0
- package/dist/interaction/session-transcript.js +152 -0
- package/dist/interaction/session-transcript.js.map +1 -0
- package/dist/interaction/session.d.ts +10 -10
- package/dist/interaction/session.d.ts.map +1 -1
- package/dist/interaction/session.js +5 -3
- package/dist/interaction/session.js.map +1 -1
- package/dist/llm/provider.d.ts +6 -9
- package/dist/llm/provider.d.ts.map +1 -1
- package/dist/llm/provider.js +255 -63
- package/dist/llm/provider.js.map +1 -1
- package/dist/llm/providers/endpoints/ai360.d.ts +10 -0
- package/dist/llm/providers/endpoints/ai360.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/ai360.js +34 -0
- package/dist/llm/providers/endpoints/ai360.js.map +1 -0
- package/dist/llm/providers/endpoints/anthropic.d.ts +12 -0
- package/dist/llm/providers/endpoints/anthropic.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/anthropic.js +72 -0
- package/dist/llm/providers/endpoints/anthropic.js.map +1 -0
- package/dist/llm/providers/endpoints/astronCodingPlan.d.ts +16 -0
- package/dist/llm/providers/endpoints/astronCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/astronCodingPlan.js +16 -0
- package/dist/llm/providers/endpoints/astronCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/baichuan.d.ts +10 -0
- package/dist/llm/providers/endpoints/baichuan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/baichuan.js +20 -0
- package/dist/llm/providers/endpoints/baichuan.js.map +1 -0
- package/dist/llm/providers/endpoints/bailian.d.ts +25 -0
- package/dist/llm/providers/endpoints/bailian.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/bailian.js +42 -0
- package/dist/llm/providers/endpoints/bailian.js.map +1 -0
- package/dist/llm/providers/endpoints/bailianCodingPlan.d.ts +10 -0
- package/dist/llm/providers/endpoints/bailianCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/bailianCodingPlan.js +22 -0
- package/dist/llm/providers/endpoints/bailianCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/custom.d.ts +16 -0
- package/dist/llm/providers/endpoints/custom.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/custom.js +15 -0
- package/dist/llm/providers/endpoints/custom.js.map +1 -0
- package/dist/llm/providers/endpoints/deepseek.d.ts +17 -0
- package/dist/llm/providers/endpoints/deepseek.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/deepseek.js +20 -0
- package/dist/llm/providers/endpoints/deepseek.js.map +1 -0
- package/dist/llm/providers/endpoints/giteeai.d.ts +10 -0
- package/dist/llm/providers/endpoints/giteeai.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/giteeai.js +33 -0
- package/dist/llm/providers/endpoints/giteeai.js.map +1 -0
- package/dist/llm/providers/endpoints/githubCopilot.d.ts +10 -0
- package/dist/llm/providers/endpoints/githubCopilot.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/githubCopilot.js +35 -0
- package/dist/llm/providers/endpoints/githubCopilot.js.map +1 -0
- package/dist/llm/providers/endpoints/glmCodingPlan.d.ts +9 -0
- package/dist/llm/providers/endpoints/glmCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/glmCodingPlan.js +21 -0
- package/dist/llm/providers/endpoints/glmCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/google.d.ts +12 -0
- package/dist/llm/providers/endpoints/google.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/google.js +41 -0
- package/dist/llm/providers/endpoints/google.js.map +1 -0
- package/dist/llm/providers/endpoints/hunyuan.d.ts +10 -0
- package/dist/llm/providers/endpoints/hunyuan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/hunyuan.js +34 -0
- package/dist/llm/providers/endpoints/hunyuan.js.map +1 -0
- package/dist/llm/providers/endpoints/infiniai.d.ts +10 -0
- package/dist/llm/providers/endpoints/infiniai.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/infiniai.js +64 -0
- package/dist/llm/providers/endpoints/infiniai.js.map +1 -0
- package/dist/llm/providers/endpoints/internlm.d.ts +10 -0
- package/dist/llm/providers/endpoints/internlm.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/internlm.js +20 -0
- package/dist/llm/providers/endpoints/internlm.js.map +1 -0
- package/dist/llm/providers/endpoints/kimiCodingPlan.d.ts +9 -0
- package/dist/llm/providers/endpoints/kimiCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/kimiCodingPlan.js +17 -0
- package/dist/llm/providers/endpoints/kimiCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/longcat.d.ts +9 -0
- package/dist/llm/providers/endpoints/longcat.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/longcat.js +18 -0
- package/dist/llm/providers/endpoints/longcat.js.map +1 -0
- package/dist/llm/providers/endpoints/minimax.d.ts +15 -0
- package/dist/llm/providers/endpoints/minimax.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/minimax.js +26 -0
- package/dist/llm/providers/endpoints/minimax.js.map +1 -0
- package/dist/llm/providers/endpoints/minimaxCodingPlan.d.ts +9 -0
- package/dist/llm/providers/endpoints/minimaxCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/minimaxCodingPlan.js +21 -0
- package/dist/llm/providers/endpoints/minimaxCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/mistral.d.ts +11 -0
- package/dist/llm/providers/endpoints/mistral.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/mistral.js +31 -0
- package/dist/llm/providers/endpoints/mistral.js.map +1 -0
- package/dist/llm/providers/endpoints/modelscope.d.ts +10 -0
- package/dist/llm/providers/endpoints/modelscope.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/modelscope.js +22 -0
- package/dist/llm/providers/endpoints/modelscope.js.map +1 -0
- package/dist/llm/providers/endpoints/moonshot.d.ts +12 -0
- package/dist/llm/providers/endpoints/moonshot.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/moonshot.js +29 -0
- package/dist/llm/providers/endpoints/moonshot.js.map +1 -0
- package/dist/llm/providers/endpoints/newapi.d.ts +14 -0
- package/dist/llm/providers/endpoints/newapi.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/newapi.js +14 -0
- package/dist/llm/providers/endpoints/newapi.js.map +1 -0
- package/dist/llm/providers/endpoints/ollama.d.ts +12 -0
- package/dist/llm/providers/endpoints/ollama.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/ollama.js +63 -0
- package/dist/llm/providers/endpoints/ollama.js.map +1 -0
- package/dist/llm/providers/endpoints/openai.d.ts +12 -0
- package/dist/llm/providers/endpoints/openai.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/openai.js +67 -0
- package/dist/llm/providers/endpoints/openai.js.map +1 -0
- package/dist/llm/providers/endpoints/opencodeCodingPlan.d.ts +9 -0
- package/dist/llm/providers/endpoints/opencodeCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/opencodeCodingPlan.js +23 -0
- package/dist/llm/providers/endpoints/opencodeCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/openrouter.d.ts +15 -0
- package/dist/llm/providers/endpoints/openrouter.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/openrouter.js +74 -0
- package/dist/llm/providers/endpoints/openrouter.js.map +1 -0
- package/dist/llm/providers/endpoints/ppio.d.ts +15 -0
- package/dist/llm/providers/endpoints/ppio.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/ppio.js +73 -0
- package/dist/llm/providers/endpoints/ppio.js.map +1 -0
- package/dist/llm/providers/endpoints/qiniu.d.ts +10 -0
- package/dist/llm/providers/endpoints/qiniu.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/qiniu.js +24 -0
- package/dist/llm/providers/endpoints/qiniu.js.map +1 -0
- package/dist/llm/providers/endpoints/sensenova.d.ts +10 -0
- package/dist/llm/providers/endpoints/sensenova.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/sensenova.js +37 -0
- package/dist/llm/providers/endpoints/sensenova.js.map +1 -0
- package/dist/llm/providers/endpoints/siliconcloud.d.ts +14 -0
- package/dist/llm/providers/endpoints/siliconcloud.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/siliconcloud.js +114 -0
- package/dist/llm/providers/endpoints/siliconcloud.js.map +1 -0
- package/dist/llm/providers/endpoints/spark.d.ts +14 -0
- package/dist/llm/providers/endpoints/spark.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/spark.js +21 -0
- package/dist/llm/providers/endpoints/spark.js.map +1 -0
- package/dist/llm/providers/endpoints/stepfun.d.ts +10 -0
- package/dist/llm/providers/endpoints/stepfun.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/stepfun.js +27 -0
- package/dist/llm/providers/endpoints/stepfun.js.map +1 -0
- package/dist/llm/providers/endpoints/tencentcloud.d.ts +10 -0
- package/dist/llm/providers/endpoints/tencentcloud.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/tencentcloud.js +17 -0
- package/dist/llm/providers/endpoints/tencentcloud.js.map +1 -0
- package/dist/llm/providers/endpoints/volcengine.d.ts +10 -0
- package/dist/llm/providers/endpoints/volcengine.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/volcengine.js +44 -0
- package/dist/llm/providers/endpoints/volcengine.js.map +1 -0
- package/dist/llm/providers/endpoints/volcengineCodingPlan.d.ts +19 -0
- package/dist/llm/providers/endpoints/volcengineCodingPlan.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/volcengineCodingPlan.js +25 -0
- package/dist/llm/providers/endpoints/volcengineCodingPlan.js.map +1 -0
- package/dist/llm/providers/endpoints/wenxin.d.ts +10 -0
- package/dist/llm/providers/endpoints/wenxin.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/wenxin.js +98 -0
- package/dist/llm/providers/endpoints/wenxin.js.map +1 -0
- package/dist/llm/providers/endpoints/xai.d.ts +11 -0
- package/dist/llm/providers/endpoints/xai.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/xai.js +25 -0
- package/dist/llm/providers/endpoints/xai.js.map +1 -0
- package/dist/llm/providers/endpoints/xiaomimimo.d.ts +12 -0
- package/dist/llm/providers/endpoints/xiaomimimo.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/xiaomimimo.js +16 -0
- package/dist/llm/providers/endpoints/xiaomimimo.js.map +1 -0
- package/dist/llm/providers/endpoints/zeroone.d.ts +10 -0
- package/dist/llm/providers/endpoints/zeroone.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/zeroone.js +26 -0
- package/dist/llm/providers/endpoints/zeroone.js.map +1 -0
- package/dist/llm/providers/endpoints/zhipu.d.ts +12 -0
- package/dist/llm/providers/endpoints/zhipu.d.ts.map +1 -0
- package/dist/llm/providers/endpoints/zhipu.js +51 -0
- package/dist/llm/providers/endpoints/zhipu.js.map +1 -0
- package/dist/llm/providers/index.d.ts +5 -0
- package/dist/llm/providers/index.d.ts.map +1 -0
- package/dist/llm/providers/index.js +67 -0
- package/dist/llm/providers/index.js.map +1 -0
- package/dist/llm/providers/lookup.d.ts +16 -0
- package/dist/llm/providers/lookup.d.ts.map +1 -0
- package/dist/llm/providers/lookup.js +68 -0
- package/dist/llm/providers/lookup.js.map +1 -0
- package/dist/llm/providers/probe.d.ts +11 -0
- package/dist/llm/providers/probe.d.ts.map +1 -0
- package/dist/llm/providers/probe.js +24 -0
- package/dist/llm/providers/probe.js.map +1 -0
- package/dist/llm/providers/types.d.ts +71 -0
- package/dist/llm/providers/types.d.ts.map +1 -0
- package/dist/llm/providers/types.js +9 -0
- package/dist/llm/providers/types.js.map +1 -0
- package/dist/llm/providers/verify.d.ts +27 -0
- package/dist/llm/providers/verify.d.ts.map +1 -0
- package/dist/llm/providers/verify.js +77 -0
- package/dist/llm/providers/verify.js.map +1 -0
- package/dist/llm/secrets.d.ts.map +1 -1
- package/dist/llm/secrets.js +27 -2
- package/dist/llm/secrets.js.map +1 -1
- package/dist/llm/service-presets.d.ts +13 -3
- package/dist/llm/service-presets.d.ts.map +1 -1
- package/dist/llm/service-presets.js +78 -42
- package/dist/llm/service-presets.js.map +1 -1
- package/dist/llm/service-resolver.d.ts +1 -1
- package/dist/llm/service-resolver.d.ts.map +1 -1
- package/dist/llm/service-resolver.js +13 -0
- package/dist/llm/service-resolver.js.map +1 -1
- package/dist/models/book-rules.d.ts +23 -1
- package/dist/models/book-rules.d.ts.map +1 -1
- package/dist/models/book-rules.js +54 -2
- package/dist/models/book-rules.js.map +1 -1
- package/dist/models/input-governance.d.ts +20 -244
- package/dist/models/input-governance.d.ts.map +1 -1
- package/dist/models/input-governance.js +7 -51
- package/dist/models/input-governance.js.map +1 -1
- package/dist/models/project.d.ts +29 -28
- package/dist/models/project.d.ts.map +1 -1
- package/dist/models/project.js +11 -9
- package/dist/models/project.js.map +1 -1
- package/dist/models/runtime-state.d.ts +120 -0
- package/dist/models/runtime-state.d.ts.map +1 -1
- package/dist/models/runtime-state.js +12 -0
- package/dist/models/runtime-state.js.map +1 -1
- package/dist/pipeline/agent.d.ts.map +1 -1
- package/dist/pipeline/agent.js +59 -10
- package/dist/pipeline/agent.js.map +1 -1
- package/dist/pipeline/chapter-review-cycle.d.ts +11 -4
- package/dist/pipeline/chapter-review-cycle.d.ts.map +1 -1
- package/dist/pipeline/chapter-review-cycle.js +156 -73
- package/dist/pipeline/chapter-review-cycle.js.map +1 -1
- package/dist/pipeline/chapter-truth-validation.d.ts +2 -1
- package/dist/pipeline/chapter-truth-validation.d.ts.map +1 -1
- package/dist/pipeline/chapter-truth-validation.js +1 -1
- package/dist/pipeline/chapter-truth-validation.js.map +1 -1
- package/dist/pipeline/persisted-governed-plan.d.ts +1 -0
- package/dist/pipeline/persisted-governed-plan.d.ts.map +1 -1
- package/dist/pipeline/persisted-governed-plan.js +181 -66
- package/dist/pipeline/persisted-governed-plan.js.map +1 -1
- package/dist/pipeline/runner.d.ts +20 -17
- package/dist/pipeline/runner.d.ts.map +1 -1
- package/dist/pipeline/runner.js +359 -84
- package/dist/pipeline/runner.js.map +1 -1
- package/dist/state/manager.d.ts.map +1 -1
- package/dist/state/manager.js +44 -4
- package/dist/state/manager.js.map +1 -1
- package/dist/state/memory-db.d.ts +6 -0
- package/dist/state/memory-db.d.ts.map +1 -1
- package/dist/state/memory-db.js.map +1 -1
- package/dist/state/runtime-state-store.d.ts.map +1 -1
- package/dist/state/runtime-state-store.js +4 -1
- package/dist/state/runtime-state-store.js.map +1 -1
- package/dist/state/state-projections.d.ts +3 -1
- package/dist/state/state-projections.d.ts.map +1 -1
- package/dist/state/state-projections.js +58 -15
- package/dist/state/state-projections.js.map +1 -1
- package/dist/utils/book-id.d.ts +4 -0
- package/dist/utils/book-id.d.ts.map +1 -0
- package/dist/utils/book-id.js +27 -0
- package/dist/utils/book-id.js.map +1 -0
- package/dist/utils/chapter-cadence.js +1 -0
- package/dist/utils/chapter-cadence.js.map +1 -1
- package/dist/utils/chapter-memo-parser.d.ts +19 -0
- package/dist/utils/chapter-memo-parser.d.ts.map +1 -0
- package/dist/utils/chapter-memo-parser.js +114 -0
- package/dist/utils/chapter-memo-parser.js.map +1 -0
- package/dist/utils/config-loader.d.ts +7 -11
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +13 -253
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/context-assembly.d.ts +24 -0
- package/dist/utils/context-assembly.d.ts.map +1 -0
- package/dist/utils/context-assembly.js +77 -0
- package/dist/utils/context-assembly.js.map +1 -0
- package/dist/utils/effective-llm-config.d.ts +34 -0
- package/dist/utils/effective-llm-config.d.ts.map +1 -0
- package/dist/utils/effective-llm-config.js +417 -0
- package/dist/utils/effective-llm-config.js.map +1 -0
- package/dist/utils/governed-working-set.js +1 -1
- package/dist/utils/governed-working-set.js.map +1 -1
- package/dist/utils/hook-ledger-validator.d.ts +82 -0
- package/dist/utils/hook-ledger-validator.d.ts.map +1 -0
- package/dist/utils/hook-ledger-validator.js +225 -0
- package/dist/utils/hook-ledger-validator.js.map +1 -0
- package/dist/utils/hook-lifecycle.d.ts +5 -0
- package/dist/utils/hook-lifecycle.d.ts.map +1 -1
- package/dist/utils/hook-lifecycle.js +32 -0
- package/dist/utils/hook-lifecycle.js.map +1 -1
- package/dist/utils/hook-policy.d.ts +0 -17
- package/dist/utils/hook-policy.d.ts.map +1 -1
- package/dist/utils/hook-policy.js +0 -30
- package/dist/utils/hook-policy.js.map +1 -1
- package/dist/utils/hook-promotion.d.ts +83 -0
- package/dist/utils/hook-promotion.d.ts.map +1 -0
- package/dist/utils/hook-promotion.js +241 -0
- package/dist/utils/hook-promotion.js.map +1 -0
- package/dist/utils/hook-stale-detection.d.ts +51 -0
- package/dist/utils/hook-stale-detection.d.ts.map +1 -0
- package/dist/utils/hook-stale-detection.js +125 -0
- package/dist/utils/hook-stale-detection.js.map +1 -0
- package/dist/utils/llm-endpoint-auth.d.ts +5 -0
- package/dist/utils/llm-endpoint-auth.d.ts.map +1 -0
- package/dist/utils/llm-endpoint-auth.js +36 -0
- package/dist/utils/llm-endpoint-auth.js.map +1 -0
- package/dist/utils/llm-env.d.ts +14 -0
- package/dist/utils/llm-env.d.ts.map +1 -0
- package/dist/utils/llm-env.js +53 -0
- package/dist/utils/llm-env.js.map +1 -0
- package/dist/utils/memory-retrieval.d.ts +23 -1
- package/dist/utils/memory-retrieval.d.ts.map +1 -1
- package/dist/utils/memory-retrieval.js +45 -2
- package/dist/utils/memory-retrieval.js.map +1 -1
- package/dist/utils/narrative-control.d.ts +16 -0
- package/dist/utils/narrative-control.d.ts.map +1 -0
- package/dist/utils/narrative-control.js +131 -0
- package/dist/utils/narrative-control.js.map +1 -0
- package/dist/utils/path-safety.d.ts +2 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +11 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/planning-materials.d.ts +35 -0
- package/dist/utils/planning-materials.d.ts.map +1 -0
- package/dist/utils/planning-materials.js +123 -0
- package/dist/utils/planning-materials.js.map +1 -0
- package/dist/utils/proxy-fetch.d.ts +9 -0
- package/dist/utils/proxy-fetch.d.ts.map +1 -0
- package/dist/utils/proxy-fetch.js +31 -0
- package/dist/utils/proxy-fetch.js.map +1 -0
- package/dist/utils/runtime-writer.d.ts +14 -0
- package/dist/utils/runtime-writer.d.ts.map +1 -0
- package/dist/utils/runtime-writer.js +21 -0
- package/dist/utils/runtime-writer.js.map +1 -0
- package/dist/utils/spot-fix-patches.d.ts +7 -0
- package/dist/utils/spot-fix-patches.d.ts.map +1 -1
- package/dist/utils/spot-fix-patches.js +109 -36
- package/dist/utils/spot-fix-patches.js.map +1 -1
- package/dist/utils/story-markdown.d.ts.map +1 -1
- package/dist/utils/story-markdown.js +104 -6
- package/dist/utils/story-markdown.js.map +1 -1
- package/dist/utils/writing-methodology.d.ts +10 -0
- package/dist/utils/writing-methodology.d.ts.map +1 -0
- package/dist/utils/writing-methodology.js +163 -0
- package/dist/utils/writing-methodology.js.map +1 -0
- package/package.json +3 -2
- package/dist/utils/hook-agenda.d.ts +0 -21
- package/dist/utils/hook-agenda.d.ts.map +0 -1
- package/dist/utils/hook-agenda.js +0 -95
- package/dist/utils/hook-agenda.js.map +0 -1
package/dist/pipeline/runner.js
CHANGED
|
@@ -2,7 +2,7 @@ import { chatCompletion, createLLMClient } from "../llm/provider.js";
|
|
|
2
2
|
import { ArchitectAgent } from "../agents/architect.js";
|
|
3
3
|
import { FoundationReviewerAgent } from "../agents/foundation-reviewer.js";
|
|
4
4
|
import { PlannerAgent } from "../agents/planner.js";
|
|
5
|
-
import {
|
|
5
|
+
import { composeGovernedChapter } from "../agents/composer.js";
|
|
6
6
|
import { WriterAgent } from "../agents/writer.js";
|
|
7
7
|
import { LengthNormalizerAgent } from "../agents/length-normalizer.js";
|
|
8
8
|
import { ChapterAnalyzerAgent } from "../agents/chapter-analyzer.js";
|
|
@@ -18,16 +18,17 @@ import { MemoryDB } from "../state/memory-db.js";
|
|
|
18
18
|
import { dispatchNotification, dispatchWebhookEvent } from "../notify/dispatcher.js";
|
|
19
19
|
import { buildLengthSpec, countChapterLength, formatLengthCount, isOutsideHardRange, isOutsideSoftRange, resolveLengthCountingMode } from "../utils/length-metrics.js";
|
|
20
20
|
import { analyzeLongSpanFatigue } from "../utils/long-span-fatigue.js";
|
|
21
|
+
import { buildWritingMethodologySection } from "../utils/writing-methodology.js";
|
|
22
|
+
import { isNewLayoutBook, readCharacterContext, readStoryFrame, readVolumeMap, } from "../utils/outline-paths.js";
|
|
21
23
|
import { loadNarrativeMemorySeed, loadSnapshotCurrentStateFacts } from "../state/runtime-state-store.js";
|
|
22
24
|
import { rewriteStructuredStateFromMarkdown } from "../state/state-bootstrap.js";
|
|
23
25
|
import { readFile, readdir, writeFile, mkdir, rename, rm, stat } from "node:fs/promises";
|
|
24
26
|
import { join } from "node:path";
|
|
25
|
-
import { readStoryFrame, readVolumeMap, readCharacterContext, readCurrentStateWithFallback, isNewLayoutBook } from "../utils/outline-paths.js";
|
|
26
27
|
import { parseStateDegradedReviewNote, resolveStateDegradedBaseStatus, retrySettlementAfterValidationFailure, } from "./chapter-state-recovery.js";
|
|
27
28
|
import { persistChapterArtifacts } from "./chapter-persistence.js";
|
|
28
29
|
import { runChapterReviewCycle } from "./chapter-review-cycle.js";
|
|
29
30
|
import { validateChapterTruthPersistence } from "./chapter-truth-validation.js";
|
|
30
|
-
import { loadPersistedPlan, relativeToBookDir } from "./persisted-governed-plan.js";
|
|
31
|
+
import { loadPersistedPlan, relativeToBookDir, savePersistedPlan } from "./persisted-governed-plan.js";
|
|
31
32
|
const SEQUENCE_LEVEL_CATEGORIES = new Set([
|
|
32
33
|
"Pacing Monotony", "节奏单调",
|
|
33
34
|
"Mood Monotony", "情绪单调",
|
|
@@ -39,6 +40,118 @@ const SEQUENCE_LEVEL_CATEGORIES = new Set([
|
|
|
39
40
|
function isSequenceLevelCategory(category) {
|
|
40
41
|
return SEQUENCE_LEVEL_CATEGORIES.has(category);
|
|
41
42
|
}
|
|
43
|
+
const DEFAULT_IMPORT_FOUNDATION_MAX_FULL_TEXT_CHARS = 80_000;
|
|
44
|
+
const DEFAULT_IMPORT_CHAPTER_EXCERPT_CHARS = 6_000;
|
|
45
|
+
const DEFAULT_IMPORT_TITLE_CATALOG_CHARS = 24_000;
|
|
46
|
+
const DEFAULT_IMPORT_EDGE_CHAPTER_COUNT = 4;
|
|
47
|
+
const DEFAULT_IMPORT_MIDDLE_ANCHOR_COUNT = 8;
|
|
48
|
+
function formatImportedChapter(chapter, index, language, content = chapter.content) {
|
|
49
|
+
return language === "en"
|
|
50
|
+
? `Chapter ${index + 1}: ${chapter.title}\n\n${content}`
|
|
51
|
+
: `第${index + 1}章 ${chapter.title}\n\n${content}`;
|
|
52
|
+
}
|
|
53
|
+
function estimateImportFullTextLength(chapters) {
|
|
54
|
+
return chapters.reduce((total, chapter) => total + chapter.title.length + chapter.content.length + 24, 0);
|
|
55
|
+
}
|
|
56
|
+
function excerptHeadTail(text, maxChars, language) {
|
|
57
|
+
const clean = text.trim();
|
|
58
|
+
if (clean.length <= maxChars)
|
|
59
|
+
return clean;
|
|
60
|
+
const headChars = Math.max(200, Math.floor(maxChars * 0.6));
|
|
61
|
+
const tailChars = Math.max(200, maxChars - headChars);
|
|
62
|
+
const omitted = clean.length - headChars - tailChars;
|
|
63
|
+
const marker = language === "en"
|
|
64
|
+
? `\n\n[... ${omitted} chars omitted for import-context budget ...]\n\n`
|
|
65
|
+
: `\n\n【中间省略 ${omitted} 字,用于控制导入上下文预算】\n\n`;
|
|
66
|
+
return `${clean.slice(0, headChars).trimEnd()}${marker}${clean.slice(-tailChars).trimStart()}`;
|
|
67
|
+
}
|
|
68
|
+
function pickImportAnchorIndexes(chapterCount, edgeChapterCount, middleAnchorCount) {
|
|
69
|
+
const selected = new Set();
|
|
70
|
+
for (let i = 0; i < Math.min(edgeChapterCount, chapterCount); i++)
|
|
71
|
+
selected.add(i);
|
|
72
|
+
for (let i = Math.max(0, chapterCount - edgeChapterCount); i < chapterCount; i++)
|
|
73
|
+
selected.add(i);
|
|
74
|
+
const middleStart = Math.min(edgeChapterCount, chapterCount);
|
|
75
|
+
const middleEnd = Math.max(middleStart, chapterCount - edgeChapterCount);
|
|
76
|
+
const middleSize = middleEnd - middleStart;
|
|
77
|
+
const anchors = Math.min(middleAnchorCount, middleSize);
|
|
78
|
+
for (let i = 0; i < anchors; i++) {
|
|
79
|
+
const offset = Math.floor(((i + 1) * middleSize) / (anchors + 1));
|
|
80
|
+
selected.add(Math.min(chapterCount - 1, middleStart + offset));
|
|
81
|
+
}
|
|
82
|
+
return [...selected].sort((a, b) => a - b);
|
|
83
|
+
}
|
|
84
|
+
function buildTitleCatalog(chapters, language, maxChars) {
|
|
85
|
+
const lines = chapters.map((chapter, index) => language === "en"
|
|
86
|
+
? `- Chapter ${index + 1}: ${chapter.title} (${chapter.content.length} chars)`
|
|
87
|
+
: `- 第${index + 1}章:${chapter.title}(${chapter.content.length}字)`);
|
|
88
|
+
const joined = lines.join("\n");
|
|
89
|
+
if (joined.length <= maxChars)
|
|
90
|
+
return joined;
|
|
91
|
+
const headBudget = Math.floor(maxChars * 0.55);
|
|
92
|
+
const tailBudget = maxChars - headBudget;
|
|
93
|
+
const head = [];
|
|
94
|
+
const tail = [];
|
|
95
|
+
let headChars = 0;
|
|
96
|
+
let tailChars = 0;
|
|
97
|
+
for (const line of lines) {
|
|
98
|
+
if (headChars + line.length + 1 > headBudget)
|
|
99
|
+
break;
|
|
100
|
+
head.push(line);
|
|
101
|
+
headChars += line.length + 1;
|
|
102
|
+
}
|
|
103
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
104
|
+
const line = lines[i];
|
|
105
|
+
if (tailChars + line.length + 1 > tailBudget)
|
|
106
|
+
break;
|
|
107
|
+
tail.unshift(line);
|
|
108
|
+
tailChars += line.length + 1;
|
|
109
|
+
}
|
|
110
|
+
const omitted = lines.length - head.length - tail.length;
|
|
111
|
+
const marker = language === "en"
|
|
112
|
+
? `- ... ${omitted} chapter titles omitted ...`
|
|
113
|
+
: `- ……中间 ${omitted} 个章节标题省略……`;
|
|
114
|
+
return [...head, marker, ...tail].join("\n");
|
|
115
|
+
}
|
|
116
|
+
export function buildImportFoundationSource(chapters, language, options = {}) {
|
|
117
|
+
const maxFullTextChars = options.maxFullTextChars ?? DEFAULT_IMPORT_FOUNDATION_MAX_FULL_TEXT_CHARS;
|
|
118
|
+
const chapterExcerptChars = options.chapterExcerptChars ?? DEFAULT_IMPORT_CHAPTER_EXCERPT_CHARS;
|
|
119
|
+
const titleCatalogChars = options.titleCatalogChars ?? DEFAULT_IMPORT_TITLE_CATALOG_CHARS;
|
|
120
|
+
const edgeChapterCount = options.edgeChapterCount ?? DEFAULT_IMPORT_EDGE_CHAPTER_COUNT;
|
|
121
|
+
const middleAnchorCount = options.middleAnchorCount ?? DEFAULT_IMPORT_MIDDLE_ANCHOR_COUNT;
|
|
122
|
+
if (estimateImportFullTextLength(chapters) <= maxFullTextChars) {
|
|
123
|
+
return chapters.map((chapter, index) => formatImportedChapter(chapter, index, language)).join("\n\n---\n\n");
|
|
124
|
+
}
|
|
125
|
+
const anchorIndexes = pickImportAnchorIndexes(chapters.length, edgeChapterCount, middleAnchorCount);
|
|
126
|
+
const header = language === "en"
|
|
127
|
+
? [
|
|
128
|
+
"## Import foundation source package",
|
|
129
|
+
"",
|
|
130
|
+
`The imported book has ${chapters.length} chapters. To avoid overflowing the LLM context, this package keeps the opening chapters, ending/continuation point, selected middle anchors, and a capped title catalog. Full chapters will still be replayed sequentially after foundation generation to rebuild truth files.`,
|
|
131
|
+
].join("\n")
|
|
132
|
+
: [
|
|
133
|
+
"## 导入基础设定压缩资料包",
|
|
134
|
+
"",
|
|
135
|
+
`本次导入共 ${chapters.length} 章。为避免超出 LLM 上下文,这里保留开篇、结尾续写点、少量中段锚点和标题目录;完整章节将在后续顺序回放中逐章分析并沉淀 truth files。`,
|
|
136
|
+
].join("\n");
|
|
137
|
+
const catalogTitle = language === "en" ? "## Capped chapter title catalog" : "## 章节标题目录(截断)";
|
|
138
|
+
const anchorsTitle = language === "en" ? "## Source excerpts for architecture" : "## 用于反推基础设定的正文摘录";
|
|
139
|
+
const anchorText = anchorIndexes
|
|
140
|
+
.map((index) => {
|
|
141
|
+
const chapter = chapters[index];
|
|
142
|
+
return formatImportedChapter(chapter, index, language, excerptHeadTail(chapter.content, chapterExcerptChars, language));
|
|
143
|
+
})
|
|
144
|
+
.join("\n\n---\n\n");
|
|
145
|
+
return [
|
|
146
|
+
header,
|
|
147
|
+
"",
|
|
148
|
+
catalogTitle,
|
|
149
|
+
buildTitleCatalog(chapters, language, titleCatalogChars),
|
|
150
|
+
"",
|
|
151
|
+
anchorsTitle,
|
|
152
|
+
anchorText,
|
|
153
|
+
].join("\n");
|
|
154
|
+
}
|
|
42
155
|
export class PipelineRunner {
|
|
43
156
|
state;
|
|
44
157
|
config;
|
|
@@ -98,7 +211,7 @@ export class PipelineRunner {
|
|
|
98
211
|
}
|
|
99
212
|
}
|
|
100
213
|
async generateAndReviewFoundation(params) {
|
|
101
|
-
const maxRetries = params.maxRetries ?? 2;
|
|
214
|
+
const maxRetries = params.maxRetries ?? this.config.foundationReviewRetries ?? 2;
|
|
102
215
|
let foundation = await params.generate();
|
|
103
216
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
104
217
|
this.logStage(params.stageLanguage, {
|
|
@@ -207,7 +320,6 @@ export class PipelineRunner {
|
|
|
207
320
|
apiKey,
|
|
208
321
|
model: override.model,
|
|
209
322
|
temperature: base?.temperature ?? 0.7,
|
|
210
|
-
maxTokens: base?.maxTokens ?? 8192,
|
|
211
323
|
thinkingBudget: base?.thinkingBudget ?? 0,
|
|
212
324
|
apiFormat,
|
|
213
325
|
stream,
|
|
@@ -252,12 +364,13 @@ export class PipelineRunner {
|
|
|
252
364
|
const bookDir = this.state.bookDir(book.id);
|
|
253
365
|
const stagingBookDir = join(this.state.booksDir, `.tmp-book-create-${book.id}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`);
|
|
254
366
|
const stageLanguage = await this.resolveBookLanguage(book);
|
|
367
|
+
const effectiveExternalContext = options.externalContext ?? this.config.externalContext;
|
|
255
368
|
this.logStage(stageLanguage, { zh: "生成基础设定", en: "generating foundation" });
|
|
256
369
|
const { profile: gp } = await this.loadGenreProfile(book.genre);
|
|
257
370
|
const reviewer = new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", book.id));
|
|
258
371
|
const resolvedLanguage = (book.language ?? gp.language) === "en" ? "en" : "zh";
|
|
259
372
|
const foundation = await this.generateAndReviewFoundation({
|
|
260
|
-
generate: (reviewFeedback) => architect.generateFoundation(book,
|
|
373
|
+
generate: (reviewFeedback) => architect.generateFoundation(book, effectiveExternalContext, reviewFeedback),
|
|
261
374
|
reviewer,
|
|
262
375
|
mode: "original",
|
|
263
376
|
language: resolvedLanguage,
|
|
@@ -268,8 +381,13 @@ export class PipelineRunner {
|
|
|
268
381
|
await this.state.saveBookConfigAt(stagingBookDir, book);
|
|
269
382
|
this.logStage(stageLanguage, { zh: "写入基础设定文件", en: "writing foundation files" });
|
|
270
383
|
await architect.writeFoundationFiles(stagingBookDir, foundation, gp.numericalSystem, book.language ?? gp.language);
|
|
384
|
+
if (effectiveExternalContext && effectiveExternalContext.trim().length > 0) {
|
|
385
|
+
const storyDir = join(stagingBookDir, "story");
|
|
386
|
+
await mkdir(storyDir, { recursive: true });
|
|
387
|
+
await writeFile(join(storyDir, "brief.md"), effectiveExternalContext, "utf-8");
|
|
388
|
+
}
|
|
271
389
|
this.logStage(stageLanguage, { zh: "初始化控制文档", en: "initializing control documents" });
|
|
272
|
-
await this.state.ensureControlDocumentsAt(stagingBookDir, book.language ?? gp.language, options.authorIntent ??
|
|
390
|
+
await this.state.ensureControlDocumentsAt(stagingBookDir, book.language ?? gp.language, options.authorIntent ?? effectiveExternalContext);
|
|
273
391
|
if (options.currentFocus?.trim()) {
|
|
274
392
|
await writeFile(join(stagingBookDir, "story", "current_focus.md"), options.currentFocus.trimEnd() + "\n", "utf-8");
|
|
275
393
|
}
|
|
@@ -290,32 +408,20 @@ export class PipelineRunner {
|
|
|
290
408
|
}
|
|
291
409
|
}
|
|
292
410
|
/**
|
|
293
|
-
* Revise an existing book
|
|
294
|
-
* 到段落式 / Phase 5 书按 feedback 再次调整细节),把架构稿相关文件备份到
|
|
295
|
-
* story/.backup-<phase4|phase5>-<timestamp>/。
|
|
411
|
+
* Revise an existing book foundation without touching runtime chapter state.
|
|
296
412
|
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
* hint 承诺"升级只改架构稿,不动已写的章节"保持一致。
|
|
301
|
-
*
|
|
302
|
-
* 两种来源:
|
|
303
|
-
* - legacy 书(没有 outline/story_frame.md):读 story_bible.md 等 4 个
|
|
304
|
-
* flat 文件作为原内容
|
|
305
|
-
* - Phase 5 书(outline/story_frame.md 已存在):读 outline/ + roles/ 的
|
|
306
|
-
* 权威内容作为原内容——**不能读 flat 文件**,那些是 shim(只有指针 + 2000
|
|
307
|
-
* 字摘录)会丢信息
|
|
413
|
+
* Legacy books read the flat foundation files as source. Phase 5+ books read
|
|
414
|
+
* the authoritative outline/ and roles/ files instead of the compatibility
|
|
415
|
+
* shims, otherwise large role/story details can be lost during rewrite.
|
|
308
416
|
*/
|
|
309
417
|
async reviseFoundation(bookId, feedback) {
|
|
310
418
|
const bookDir = this.state.bookDir(bookId);
|
|
311
419
|
const storyDir = join(bookDir, "story");
|
|
312
420
|
const isPhase5 = await isNewLayoutBook(bookDir);
|
|
313
|
-
// 1. 备份架构稿相关文件(不包含运行时状态文件,那些不会被动)
|
|
314
421
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
315
422
|
const backupTag = isPhase5 ? "phase5" : "phase4";
|
|
316
423
|
const backupDir = join(storyDir, `.backup-${backupTag}-${timestamp}`);
|
|
317
424
|
await mkdir(backupDir, { recursive: true });
|
|
318
|
-
// 备份 legacy flat 文件(两种书都有这几个——legacy 是权威,Phase 5 是 shim)
|
|
319
425
|
const flatFiles = ["story_bible.md", "volume_outline.md", "book_rules.md", "character_matrix.md"];
|
|
320
426
|
for (const fileName of flatFiles) {
|
|
321
427
|
try {
|
|
@@ -323,33 +429,27 @@ export class PipelineRunner {
|
|
|
323
429
|
await writeFile(join(backupDir, fileName), content, "utf-8");
|
|
324
430
|
}
|
|
325
431
|
catch {
|
|
326
|
-
|
|
432
|
+
// Missing legacy shim files are fine for partially migrated books.
|
|
327
433
|
}
|
|
328
434
|
}
|
|
329
|
-
// Phase 5 书还要备份权威来源:outline/ 和 roles/ 两个目录
|
|
330
435
|
if (isPhase5) {
|
|
331
436
|
await this.copyDirShallow(join(storyDir, "outline"), join(backupDir, "outline"));
|
|
332
437
|
await this.copyDirRecursive(join(storyDir, "roles"), join(backupDir, "roles"));
|
|
333
438
|
}
|
|
334
|
-
// 2. 读原内容作为 reviseFrom 输入 —— 必须从权威源读
|
|
335
439
|
const book = await this.state.loadBookConfig(bookId);
|
|
336
|
-
let oldStoryBible
|
|
440
|
+
let oldStoryBible;
|
|
441
|
+
let oldVolumeOutline;
|
|
442
|
+
let oldBookRules;
|
|
443
|
+
let oldCharacterMatrix;
|
|
337
444
|
if (isPhase5) {
|
|
338
|
-
// Phase 5 书的 story_bible.md / volume_outline.md / character_matrix.md
|
|
339
|
-
// 都是 shim(只有指针 + 摘录),信息不完整。从 outline-paths helper 读
|
|
340
|
-
// 权威文件:outline/story_frame.md / outline/volume_map.md / roles/**/*.md
|
|
341
445
|
[oldStoryBible, oldVolumeOutline, oldCharacterMatrix] = await Promise.all([
|
|
342
446
|
readStoryFrame(bookDir),
|
|
343
447
|
readVolumeMap(bookDir),
|
|
344
448
|
readCharacterContext(bookDir),
|
|
345
449
|
]);
|
|
346
|
-
// book_rules.md 在 Phase 5 下虽然是 shim,但 YAML frontmatter 已经搬到
|
|
347
|
-
// story_frame.md 顶部了(writeFoundationFiles 做的合并),这里读 shim
|
|
348
|
-
// 文件 OK——里面的"叙事指引摘录"部分是唯一遗留信息。
|
|
349
450
|
oldBookRules = await readFile(join(storyDir, "book_rules.md"), "utf-8").catch(() => "");
|
|
350
451
|
}
|
|
351
452
|
else {
|
|
352
|
-
// legacy 书:4 个 flat 文件就是权威
|
|
353
453
|
[oldStoryBible, oldVolumeOutline, oldBookRules, oldCharacterMatrix] = await Promise.all([
|
|
354
454
|
readFile(join(storyDir, "story_bible.md"), "utf-8").catch(() => ""),
|
|
355
455
|
readFile(join(storyDir, "volume_outline.md"), "utf-8").catch(() => ""),
|
|
@@ -357,7 +457,6 @@ export class PipelineRunner {
|
|
|
357
457
|
readFile(join(storyDir, "character_matrix.md"), "utf-8").catch(() => ""),
|
|
358
458
|
]);
|
|
359
459
|
}
|
|
360
|
-
// 3. 架构师按 reviseFrom + feedback 重写
|
|
361
460
|
const architect = new ArchitectAgent(this.agentCtxFor("architect", bookId));
|
|
362
461
|
const foundation = await architect.generateFoundation(book, undefined, undefined, {
|
|
363
462
|
reviseFrom: {
|
|
@@ -368,7 +467,6 @@ export class PipelineRunner {
|
|
|
368
467
|
userFeedback: feedback,
|
|
369
468
|
},
|
|
370
469
|
});
|
|
371
|
-
// 4. 可选 foundation-reviewer 审核——挂了只 warn 不阻断
|
|
372
470
|
const reviewer = new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", bookId));
|
|
373
471
|
const resolvedLanguage = (book.language ?? "zh") === "en" ? "en" : "zh";
|
|
374
472
|
try {
|
|
@@ -378,13 +476,12 @@ export class PipelineRunner {
|
|
|
378
476
|
language: resolvedLanguage,
|
|
379
477
|
});
|
|
380
478
|
if (!review.passed) {
|
|
381
|
-
this.config.logger?.warn?.(`[reviseFoundation]
|
|
479
|
+
this.config.logger?.warn?.(`[reviseFoundation] Foundation review did not pass; accepting rewrite. Feedback: ${review.overallFeedback ?? ""}`);
|
|
382
480
|
}
|
|
383
481
|
}
|
|
384
482
|
catch (error) {
|
|
385
|
-
this.config.logger?.warn?.(`[reviseFoundation]
|
|
483
|
+
this.config.logger?.warn?.(`[reviseFoundation] Foundation review failed and was skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
386
484
|
}
|
|
387
|
-
// 5. 目录补全 → 写新文件(mode="revise" 不动运行时状态 + 清空旧 role 文件)
|
|
388
485
|
const outlineDir = join(storyDir, "outline");
|
|
389
486
|
await mkdir(outlineDir, { recursive: true });
|
|
390
487
|
await mkdir(join(storyDir, "roles", "主要角色"), { recursive: true });
|
|
@@ -392,7 +489,6 @@ export class PipelineRunner {
|
|
|
392
489
|
const { profile: gp } = await this.loadGenreProfile(book.genre);
|
|
393
490
|
await architect.writeFoundationFiles(bookDir, foundation, gp.numericalSystem, book.language ?? gp.language, "revise");
|
|
394
491
|
}
|
|
395
|
-
/** Shallow copy (non-recursive) — used to back up outline/ which has no subdirs. */
|
|
396
492
|
async copyDirShallow(src, dest) {
|
|
397
493
|
try {
|
|
398
494
|
await mkdir(dest, { recursive: true });
|
|
@@ -403,15 +499,14 @@ export class PipelineRunner {
|
|
|
403
499
|
await writeFile(join(dest, entry), content, "utf-8");
|
|
404
500
|
}
|
|
405
501
|
catch {
|
|
406
|
-
|
|
502
|
+
// Skip unreadable files.
|
|
407
503
|
}
|
|
408
504
|
}));
|
|
409
505
|
}
|
|
410
506
|
catch {
|
|
411
|
-
|
|
507
|
+
// Source directory does not exist.
|
|
412
508
|
}
|
|
413
509
|
}
|
|
414
|
-
/** Recursive copy — used to back up roles/ which has 主要角色/ + 次要角色/. */
|
|
415
510
|
async copyDirRecursive(src, dest) {
|
|
416
511
|
try {
|
|
417
512
|
await mkdir(dest, { recursive: true });
|
|
@@ -428,13 +523,13 @@ export class PipelineRunner {
|
|
|
428
523
|
await writeFile(destPath, content, "utf-8");
|
|
429
524
|
}
|
|
430
525
|
catch {
|
|
431
|
-
|
|
526
|
+
// Skip unreadable files.
|
|
432
527
|
}
|
|
433
528
|
}
|
|
434
529
|
}
|
|
435
530
|
}
|
|
436
531
|
catch {
|
|
437
|
-
|
|
532
|
+
// Source directory does not exist.
|
|
438
533
|
}
|
|
439
534
|
}
|
|
440
535
|
/** Import external source material and generate fanfic_canon.md */
|
|
@@ -613,7 +708,7 @@ export class PipelineRunner {
|
|
|
613
708
|
chapterNumber,
|
|
614
709
|
intentPath: relativeToBookDir(bookDir, plan.runtimePath),
|
|
615
710
|
goal: plan.intent.goal,
|
|
616
|
-
conflicts:
|
|
711
|
+
conflicts: [],
|
|
617
712
|
};
|
|
618
713
|
}
|
|
619
714
|
async composeChapter(bookId, context) {
|
|
@@ -629,7 +724,7 @@ export class PipelineRunner {
|
|
|
629
724
|
chapterNumber,
|
|
630
725
|
intentPath: relativeToBookDir(bookDir, plan.runtimePath),
|
|
631
726
|
goal: plan.intent.goal,
|
|
632
|
-
conflicts:
|
|
727
|
+
conflicts: [],
|
|
633
728
|
contextPath: relativeToBookDir(bookDir, composed.contextPath),
|
|
634
729
|
ruleStackPath: relativeToBookDir(bookDir, composed.ruleStackPath),
|
|
635
730
|
tracePath: relativeToBookDir(bookDir, composed.tracePath),
|
|
@@ -723,6 +818,7 @@ export class PipelineRunner {
|
|
|
723
818
|
auditOptions: reviseControlInput
|
|
724
819
|
? {
|
|
725
820
|
chapterIntent: reviseControlInput.plan.intentMarkdown,
|
|
821
|
+
chapterMemo: reviseControlInput.plan.memo,
|
|
726
822
|
contextPackage: reviseControlInput.composed.contextPackage,
|
|
727
823
|
ruleStack: reviseControlInput.composed.ruleStack,
|
|
728
824
|
}
|
|
@@ -751,6 +847,8 @@ export class PipelineRunner {
|
|
|
751
847
|
const reviseOutput = await reviser.reviseChapter(bookDir, content, targetChapter, preRevision.auditResult.issues, mode, book.genre, reviseControlInput
|
|
752
848
|
? {
|
|
753
849
|
chapterIntent: reviseControlInput.plan.intentMarkdown,
|
|
850
|
+
chapterMemo: reviseControlInput.plan.memo,
|
|
851
|
+
chapterIntentData: reviseControlInput.plan.intent,
|
|
754
852
|
contextPackage: reviseControlInput.composed.contextPackage,
|
|
755
853
|
ruleStack: reviseControlInput.composed.ruleStack,
|
|
756
854
|
lengthSpec,
|
|
@@ -776,6 +874,7 @@ export class PipelineRunner {
|
|
|
776
874
|
? {
|
|
777
875
|
temperature: 0,
|
|
778
876
|
chapterIntent: reviseControlInput.plan.intentMarkdown,
|
|
877
|
+
chapterMemo: reviseControlInput.plan.memo,
|
|
779
878
|
contextPackage: reviseControlInput.composed.contextPackage,
|
|
780
879
|
ruleStack: reviseControlInput.composed.ruleStack,
|
|
781
880
|
truthFileOverrides: {
|
|
@@ -914,12 +1013,19 @@ export class PipelineRunner {
|
|
|
914
1013
|
return "(文件不存在)";
|
|
915
1014
|
}
|
|
916
1015
|
};
|
|
1016
|
+
// Phase 5: prefer the new prose outline files; fall back to legacy paths.
|
|
1017
|
+
const readOutline = async (newRel, legacyRel) => {
|
|
1018
|
+
const preferred = await readSafe(join(storyDir, newRel));
|
|
1019
|
+
if (preferred.trim() && preferred !== "(文件不存在)")
|
|
1020
|
+
return preferred;
|
|
1021
|
+
return readSafe(join(storyDir, legacyRel));
|
|
1022
|
+
};
|
|
917
1023
|
const [currentState, particleLedger, pendingHooks, storyBible, volumeOutline, bookRules] = await Promise.all([
|
|
918
1024
|
readSafe(join(storyDir, "current_state.md")),
|
|
919
1025
|
readSafe(join(storyDir, "particle_ledger.md")),
|
|
920
1026
|
readSafe(join(storyDir, "pending_hooks.md")),
|
|
921
|
-
|
|
922
|
-
|
|
1027
|
+
readOutline("outline/story_frame.md", "story_bible.md"),
|
|
1028
|
+
readOutline("outline/volume_map.md", "volume_outline.md"),
|
|
923
1029
|
readSafe(join(storyDir, "book_rules.md")),
|
|
924
1030
|
]);
|
|
925
1031
|
return { currentState, particleLedger, pendingHooks, storyBible, volumeOutline, bookRules };
|
|
@@ -984,6 +1090,8 @@ export class PipelineRunner {
|
|
|
984
1090
|
const reducedControlInput = writeInput.chapterIntent && writeInput.contextPackage && writeInput.ruleStack
|
|
985
1091
|
? {
|
|
986
1092
|
chapterIntent: writeInput.chapterIntent,
|
|
1093
|
+
chapterMemo: writeInput.chapterMemo,
|
|
1094
|
+
chapterIntentData: writeInput.chapterIntentData,
|
|
987
1095
|
contextPackage: writeInput.contextPackage,
|
|
988
1096
|
ruleStack: writeInput.ruleStack,
|
|
989
1097
|
}
|
|
@@ -991,6 +1099,10 @@ export class PipelineRunner {
|
|
|
991
1099
|
const { profile: gp } = await this.loadGenreProfile(book.genre);
|
|
992
1100
|
const pipelineLang = book.language ?? gp.language;
|
|
993
1101
|
const lengthSpec = buildLengthSpec(wordCount ?? book.chapterWordCount, pipelineLang);
|
|
1102
|
+
const { normalizePostWriteSurface, validatePostWrite: postWriteValidate, } = await import("../agents/post-write-validator.js");
|
|
1103
|
+
const { validateHookLedger } = await import("../utils/hook-ledger-validator.js");
|
|
1104
|
+
const { readBookRules } = await import("../agents/rules-reader.js");
|
|
1105
|
+
const parsedBookRules = (await readBookRules(bookDir))?.rules ?? null;
|
|
994
1106
|
// 1. Write chapter
|
|
995
1107
|
const writer = new WriterAgent(this.agentCtxFor("writer", bookId));
|
|
996
1108
|
this.logStage(stageLanguage, { zh: "撰写章节草稿", en: "writing chapter draft" });
|
|
@@ -1024,11 +1136,27 @@ export class PipelineRunner {
|
|
|
1024
1136
|
lengthSpec,
|
|
1025
1137
|
chapterIntent: writeInput.chapterIntent,
|
|
1026
1138
|
}),
|
|
1139
|
+
normalizePostWriteSurface: (chapterContent) => normalizePostWriteSurface(chapterContent, pipelineLang),
|
|
1027
1140
|
assertChapterContentNotEmpty: (content, stage) => this.assertChapterContentNotEmpty(content, chapterNumber, stage),
|
|
1028
1141
|
addUsage: PipelineRunner.addUsage,
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1142
|
+
analyzeAITells: (content) => analyzeAITells(content, pipelineLang),
|
|
1143
|
+
analyzeSensitiveWords: (content) => analyzeSensitiveWords(content, undefined, pipelineLang),
|
|
1144
|
+
runPostWriteChecks: (content) => {
|
|
1145
|
+
const baseIssues = postWriteValidate(content, gp, parsedBookRules, pipelineLang)
|
|
1146
|
+
.filter((v) => v.severity === "error")
|
|
1147
|
+
.map((v) => ({
|
|
1148
|
+
severity: "critical",
|
|
1149
|
+
category: v.rule,
|
|
1150
|
+
description: v.description,
|
|
1151
|
+
suggestion: v.suggestion,
|
|
1152
|
+
}));
|
|
1153
|
+
// Phase 9-3: verify the draft acts on every hook the memo committed to.
|
|
1154
|
+
const memoBody = writeInput.chapterMemo?.body ?? "";
|
|
1155
|
+
const ledgerIssues = memoBody
|
|
1156
|
+
? validateHookLedger(memoBody, content)
|
|
1157
|
+
: [];
|
|
1158
|
+
return [...baseIssues, ...ledgerIssues];
|
|
1159
|
+
},
|
|
1032
1160
|
logWarn: (message) => this.logWarn(pipelineLang, message),
|
|
1033
1161
|
logStage: (message) => this.logStage(stageLanguage, message),
|
|
1034
1162
|
});
|
|
@@ -1039,6 +1167,59 @@ export class PipelineRunner {
|
|
|
1039
1167
|
let auditResult = reviewResult.auditResult;
|
|
1040
1168
|
const postReviseCount = reviewResult.postReviseCount;
|
|
1041
1169
|
const normalizeApplied = reviewResult.normalizeApplied;
|
|
1170
|
+
// 3b. File-layer polish pass — runs AFTER structural audit accepts the
|
|
1171
|
+
// chapter. Polisher only touches sentence craft / paragraph shape /
|
|
1172
|
+
// wording / sensory detail / dialogue naturalness. Plot / character /
|
|
1173
|
+
// mainline stay frozen. Skipped when audit did not produce a passing
|
|
1174
|
+
// chapter (leave the failing draft visible for the next cycle) or when
|
|
1175
|
+
// length is dangerously off-range (normalize should handle it, not polish).
|
|
1176
|
+
if (auditResult.passed) {
|
|
1177
|
+
try {
|
|
1178
|
+
const { PolisherAgent } = await import("../agents/polisher.js");
|
|
1179
|
+
const polisher = new PolisherAgent(this.agentCtxFor("polisher", bookId));
|
|
1180
|
+
this.logStage(stageLanguage, { zh: "文字层润色", en: "polishing prose" });
|
|
1181
|
+
const polishOutput = await polisher.polishChapter({
|
|
1182
|
+
chapterContent: finalContent,
|
|
1183
|
+
chapterNumber,
|
|
1184
|
+
chapterMemo: reducedControlInput?.chapterMemo,
|
|
1185
|
+
language: pipelineLang === "en" ? "en" : "zh",
|
|
1186
|
+
});
|
|
1187
|
+
totalUsage = PipelineRunner.addUsage(totalUsage, polishOutput.tokenUsage);
|
|
1188
|
+
if (polishOutput.changed && polishOutput.polishedContent.trim().length > 0) {
|
|
1189
|
+
finalContent = normalizePostWriteSurface(polishOutput.polishedContent, pipelineLang);
|
|
1190
|
+
finalWordCount = countChapterLength(finalContent, lengthSpec.countingMode);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
catch (error) {
|
|
1194
|
+
this.logWarn(pipelineLang, {
|
|
1195
|
+
zh: `润色阶段失败:${error instanceof Error ? error.message : String(error)}`,
|
|
1196
|
+
en: `polish stage failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
// 3c. Lightweight per-chapter promotion pass — check if any hooks should
|
|
1201
|
+
// be promoted based on advanced_count derived from chapter_summaries.
|
|
1202
|
+
// Runs BEFORE persistence so the reviewer of the NEXT chapter sees the
|
|
1203
|
+
// updated ledger. No LLM calls — pure ledger parse + threshold check.
|
|
1204
|
+
{
|
|
1205
|
+
const { rerunPromotionPass } = await import("../utils/hook-promotion.js");
|
|
1206
|
+
const { parsePendingHooksMarkdown, renderHookSnapshot } = await import("../utils/story-markdown.js");
|
|
1207
|
+
const promotionStoryDir = join(bookDir, "story");
|
|
1208
|
+
const ledgerPath = join(promotionStoryDir, "pending_hooks.md");
|
|
1209
|
+
const ledgerRaw = await readFile(ledgerPath, "utf-8").catch(() => "");
|
|
1210
|
+
if (ledgerRaw.trim()) {
|
|
1211
|
+
const hooks = parsePendingHooksMarkdown(ledgerRaw);
|
|
1212
|
+
if (hooks.length > 0) {
|
|
1213
|
+
const summariesRaw = await readFile(join(promotionStoryDir, "chapter_summaries.md"), "utf-8").catch(() => "");
|
|
1214
|
+
const promotionResult = rerunPromotionPass(hooks, summariesRaw);
|
|
1215
|
+
if (promotionResult.updated) {
|
|
1216
|
+
const ledgerLang = /[\u4e00-\u9fff]/.test(ledgerRaw) ? "zh" : "en";
|
|
1217
|
+
await writeFile(ledgerPath, renderHookSnapshot([...promotionResult.hooks], ledgerLang), "utf-8");
|
|
1218
|
+
this.config.logger?.info(`[promotion] ${promotionResult.flippedCount} hook(s) promoted after chapter ${chapterNumber}`);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1042
1223
|
// 4. Save the final chapter and truth files from a single persistence source
|
|
1043
1224
|
this.logStage(stageLanguage, { zh: "落盘最终章节", en: "persisting final chapter" });
|
|
1044
1225
|
this.logStage(stageLanguage, { zh: "生成最终真相文件", en: "rebuilding final truth files" });
|
|
@@ -1102,10 +1283,13 @@ export class PipelineRunner {
|
|
|
1102
1283
|
// 4.1 Validate settler output before writing
|
|
1103
1284
|
this.logStage(stageLanguage, { zh: "校验真相文件变更", en: "validating truth file updates" });
|
|
1104
1285
|
const storyDir = join(bookDir, "story");
|
|
1105
|
-
const [oldState, oldHooks, oldLedger] = await Promise.all([
|
|
1286
|
+
const [oldState, oldHooks, oldLedger, authorityStoryFrame, authorityBookRules, authorityChapterSummaries] = await Promise.all([
|
|
1106
1287
|
readFile(join(storyDir, "current_state.md"), "utf-8").catch(() => ""),
|
|
1107
1288
|
readFile(join(storyDir, "pending_hooks.md"), "utf-8").catch(() => ""),
|
|
1108
1289
|
readFile(join(storyDir, "particle_ledger.md"), "utf-8").catch(() => ""),
|
|
1290
|
+
readStoryFrame(bookDir).catch(() => ""),
|
|
1291
|
+
readFile(join(storyDir, "book_rules.md"), "utf-8").catch(() => ""),
|
|
1292
|
+
readFile(join(storyDir, "chapter_summaries.md"), "utf-8").catch(() => ""),
|
|
1109
1293
|
]);
|
|
1110
1294
|
const validator = new StateValidatorAgent(this.agentCtxFor("state-validator", bookId));
|
|
1111
1295
|
const truthValidation = await validateChapterTruthPersistence({
|
|
@@ -1123,6 +1307,11 @@ export class PipelineRunner {
|
|
|
1123
1307
|
oldHooks,
|
|
1124
1308
|
oldLedger,
|
|
1125
1309
|
},
|
|
1310
|
+
authorityContext: {
|
|
1311
|
+
storyFrame: authorityStoryFrame,
|
|
1312
|
+
bookRules: authorityBookRules,
|
|
1313
|
+
chapterSummaries: authorityChapterSummaries,
|
|
1314
|
+
},
|
|
1126
1315
|
reducedControlInput,
|
|
1127
1316
|
language: pipelineLang,
|
|
1128
1317
|
logWarn: (message) => this.logWarn(pipelineLang, message),
|
|
@@ -1464,21 +1653,36 @@ export class PipelineRunner {
|
|
|
1464
1653
|
* Also saves the statistical style_profile.json.
|
|
1465
1654
|
*/
|
|
1466
1655
|
async generateStyleGuide(bookId, referenceText, sourceName) {
|
|
1467
|
-
|
|
1468
|
-
|
|
1656
|
+
const sample = referenceText.trim();
|
|
1657
|
+
if (!sample) {
|
|
1658
|
+
throw new Error("Reference text is required for style extraction.");
|
|
1469
1659
|
}
|
|
1470
1660
|
const { analyzeStyle } = await import("../agents/style-analyzer.js");
|
|
1471
1661
|
const bookDir = this.state.bookDir(bookId);
|
|
1472
1662
|
const storyDir = join(bookDir, "story");
|
|
1473
1663
|
await mkdir(storyDir, { recursive: true });
|
|
1474
1664
|
// Statistical fingerprint
|
|
1475
|
-
const profile = analyzeStyle(
|
|
1665
|
+
const profile = analyzeStyle(sample, sourceName);
|
|
1476
1666
|
await writeFile(join(storyDir, "style_profile.json"), JSON.stringify(profile, null, 2), "utf-8");
|
|
1477
|
-
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1667
|
+
const book = await this.state.loadBookConfig(bookId);
|
|
1668
|
+
const { profile: gp } = await this.loadGenreProfile(book.genre);
|
|
1669
|
+
const lang = (book.language ?? gp.language) === "en" ? "en" : "zh";
|
|
1670
|
+
let qualitativeGuide;
|
|
1671
|
+
if (sample.length < 500) {
|
|
1672
|
+
qualitativeGuide = this.buildDeterministicStyleGuide(profile, {
|
|
1673
|
+
language: lang,
|
|
1674
|
+
reason: lang === "en"
|
|
1675
|
+
? `The sample is short (${sample.length} chars), so this guide uses the statistical fingerprint instead of LLM qualitative extraction.`
|
|
1676
|
+
: `样本文本较短(${sample.length}字),本次先使用统计指纹生成文风指南,不强行调用 LLM 做定性拆解。`,
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
else {
|
|
1680
|
+
try {
|
|
1681
|
+
// LLM qualitative extraction
|
|
1682
|
+
const response = await chatCompletion(this.config.client, this.config.model, [
|
|
1683
|
+
{
|
|
1684
|
+
role: "system",
|
|
1685
|
+
content: `你是一位文学风格分析专家。分析参考文本的写作风格,提取可供模仿的定性特征。
|
|
1482
1686
|
|
|
1483
1687
|
输出格式(Markdown):
|
|
1484
1688
|
## 叙事声音与语气
|
|
@@ -1506,14 +1710,76 @@ export class PipelineRunner {
|
|
|
1506
1710
|
(任何值得模仿的个人写作习惯)
|
|
1507
1711
|
|
|
1508
1712
|
分析必须基于原文实际特征,不要泛泛而谈。每个部分用1-2个原文例句佐证。`,
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1713
|
+
},
|
|
1714
|
+
{
|
|
1715
|
+
role: "user",
|
|
1716
|
+
content: `分析以下参考文本的写作风格:\n\n${sample.slice(0, 20000)}`,
|
|
1717
|
+
},
|
|
1718
|
+
], { temperature: 0.3 });
|
|
1719
|
+
qualitativeGuide = response.content.trim()
|
|
1720
|
+
? response.content
|
|
1721
|
+
: this.buildDeterministicStyleGuide(profile, {
|
|
1722
|
+
language: lang,
|
|
1723
|
+
reason: lang === "en"
|
|
1724
|
+
? "The LLM returned empty style analysis; using the statistical fingerprint fallback."
|
|
1725
|
+
: "LLM 未返回有效文风分析,本次使用统计指纹兜底生成文风指南。",
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
catch (error) {
|
|
1729
|
+
qualitativeGuide = this.buildDeterministicStyleGuide(profile, {
|
|
1730
|
+
language: lang,
|
|
1731
|
+
reason: lang === "en"
|
|
1732
|
+
? `LLM qualitative extraction failed: ${error instanceof Error ? error.message : String(error)}. Using the statistical fingerprint fallback.`
|
|
1733
|
+
: `LLM 定性拆解失败:${error instanceof Error ? error.message : String(error)}。本次使用统计指纹兜底生成文风指南。`,
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
const craftMethodology = buildWritingMethodologySection(lang);
|
|
1738
|
+
const fullStyleGuide = `${qualitativeGuide}\n\n${craftMethodology}`;
|
|
1739
|
+
await writeFile(join(storyDir, "style_guide.md"), fullStyleGuide, "utf-8");
|
|
1740
|
+
return fullStyleGuide;
|
|
1741
|
+
}
|
|
1742
|
+
buildDeterministicStyleGuide(profile, options) {
|
|
1743
|
+
if (options.language === "en") {
|
|
1744
|
+
return [
|
|
1745
|
+
"# Style Guide",
|
|
1746
|
+
"",
|
|
1747
|
+
`> ${options.reason}`,
|
|
1748
|
+
"",
|
|
1749
|
+
"## Statistical Fingerprint",
|
|
1750
|
+
`- Source: ${profile.sourceName ?? "unknown"}`,
|
|
1751
|
+
`- Average sentence length: ${profile.avgSentenceLength}`,
|
|
1752
|
+
`- Sentence length variance: ${profile.sentenceLengthStdDev}`,
|
|
1753
|
+
`- Average paragraph length: ${profile.avgParagraphLength}`,
|
|
1754
|
+
`- Vocabulary diversity: ${Math.round(profile.vocabularyDiversity * 100)}%`,
|
|
1755
|
+
profile.topPatterns.length > 0 ? `- Repeated openings: ${profile.topPatterns.join(", ")}` : "- Repeated openings: none obvious in this sample",
|
|
1756
|
+
profile.rhetoricalFeatures.length > 0 ? `- Rhetorical features: ${profile.rhetoricalFeatures.join(", ")}` : "- Rhetorical features: none obvious in this sample",
|
|
1757
|
+
"",
|
|
1758
|
+
"## How To Use",
|
|
1759
|
+
"- Treat this as a lightweight style fingerprint, not a full imitation bible.",
|
|
1760
|
+
"- Keep sentence and paragraph rhythm close to the sample when drafting.",
|
|
1761
|
+
"- If this guide feels too thin, import a longer excerpt later; the file will be replaced.",
|
|
1762
|
+
].join("\n");
|
|
1763
|
+
}
|
|
1764
|
+
return [
|
|
1765
|
+
"# 文风指南",
|
|
1766
|
+
"",
|
|
1767
|
+
`> ${options.reason}`,
|
|
1768
|
+
"",
|
|
1769
|
+
"## 统计风格指纹",
|
|
1770
|
+
`- 来源:${profile.sourceName ?? "unknown"}`,
|
|
1771
|
+
`- 平均句长:${profile.avgSentenceLength}`,
|
|
1772
|
+
`- 句长波动:${profile.sentenceLengthStdDev}`,
|
|
1773
|
+
`- 平均段落长度:${profile.avgParagraphLength}`,
|
|
1774
|
+
`- 词汇多样性:${Math.round(profile.vocabularyDiversity * 100)}%`,
|
|
1775
|
+
profile.topPatterns.length > 0 ? `- 高频句首/模式:${profile.topPatterns.join("、")}` : "- 高频句首/模式:样本内不明显",
|
|
1776
|
+
profile.rhetoricalFeatures.length > 0 ? `- 修辞特征:${profile.rhetoricalFeatures.join("、")}` : "- 修辞特征:样本内不明显",
|
|
1777
|
+
"",
|
|
1778
|
+
"## 使用方式",
|
|
1779
|
+
"- 这是一份轻量文风指纹,不是完整仿写圣经。",
|
|
1780
|
+
"- 后续写作优先参考句长、段落长度、节奏波动和可见修辞。",
|
|
1781
|
+
"- 如果想得到更稳定的定性拆解,后续可以导入更长片段覆盖本文件。",
|
|
1782
|
+
].join("\n");
|
|
1517
1783
|
}
|
|
1518
1784
|
/**
|
|
1519
1785
|
* Import canon from parent book for spinoff writing.
|
|
@@ -1541,15 +1807,22 @@ export class PipelineRunner {
|
|
|
1541
1807
|
}
|
|
1542
1808
|
};
|
|
1543
1809
|
const parentBook = await this.state.loadBookConfig(parentBookId);
|
|
1810
|
+
// Phase 5: parent book may be on the new prose layout; prefer outline/.
|
|
1811
|
+
const readParentOutline = async (newRel, legacyRel) => {
|
|
1812
|
+
const preferred = await readSafe(join(parentDir, "story", newRel));
|
|
1813
|
+
if (preferred.trim() && preferred !== "(无)")
|
|
1814
|
+
return preferred;
|
|
1815
|
+
return readSafe(join(parentDir, "story", legacyRel));
|
|
1816
|
+
};
|
|
1544
1817
|
const [storyBible, currentState, ledger, hooks, summaries, subplots, emotions, matrix] = await Promise.all([
|
|
1545
|
-
|
|
1546
|
-
|
|
1818
|
+
readParentOutline("outline/story_frame.md", "story_bible.md"),
|
|
1819
|
+
readSafe(join(parentDir, "story/current_state.md")),
|
|
1547
1820
|
readSafe(join(parentDir, "story/particle_ledger.md")),
|
|
1548
1821
|
readSafe(join(parentDir, "story/pending_hooks.md")),
|
|
1549
1822
|
readSafe(join(parentDir, "story/chapter_summaries.md")),
|
|
1550
1823
|
readSafe(join(parentDir, "story/subplot_board.md")),
|
|
1551
1824
|
readSafe(join(parentDir, "story/emotional_arcs.md")),
|
|
1552
|
-
|
|
1825
|
+
readSafe(join(parentDir, "story/character_matrix.md")),
|
|
1553
1826
|
]);
|
|
1554
1827
|
const response = await chatCompletion(this.config.client, this.config.model, [
|
|
1555
1828
|
{
|
|
@@ -1679,7 +1952,7 @@ ${matrix}`,
|
|
|
1679
1952
|
* Import existing chapters into a book. Reverse-engineers all truth files
|
|
1680
1953
|
* via sequential replay so the Writer and Auditor can continue naturally.
|
|
1681
1954
|
*
|
|
1682
|
-
* Step 1: Generate foundation (
|
|
1955
|
+
* Step 1: Generate foundation (story_frame, volume_map, book_rules) from all chapters.
|
|
1683
1956
|
* Step 2: Sequentially replay each chapter through ChapterAnalyzer to build truth files.
|
|
1684
1957
|
*/
|
|
1685
1958
|
async importChapters(input) {
|
|
@@ -1697,31 +1970,29 @@ ${matrix}`,
|
|
|
1697
1970
|
zh: `步骤 1:从 ${input.chapters.length} 章生成基础设定...`,
|
|
1698
1971
|
en: `Step 1: Generating foundation from ${input.chapters.length} chapters...`,
|
|
1699
1972
|
}));
|
|
1700
|
-
const
|
|
1701
|
-
? `Chapter ${i + 1}: ${c.title}\n\n${c.content}`
|
|
1702
|
-
: `第${i + 1}章 ${c.title}\n\n${c.content}`).join("\n\n---\n\n");
|
|
1973
|
+
const foundationSource = buildImportFoundationSource(input.chapters, resolvedLanguage);
|
|
1703
1974
|
const architect = new ArchitectAgent(this.agentCtxFor("architect", input.bookId));
|
|
1704
1975
|
const isSeries = input.importMode === "series";
|
|
1705
1976
|
const foundation = isSeries
|
|
1706
1977
|
? await this.generateAndReviewFoundation({
|
|
1707
|
-
generate: (reviewFeedback) => architect.generateFoundationFromImport(book,
|
|
1978
|
+
generate: (reviewFeedback) => architect.generateFoundationFromImport(book, foundationSource, undefined, reviewFeedback, { importMode: "series" }),
|
|
1708
1979
|
reviewer: new FoundationReviewerAgent(this.agentCtxFor("foundation-reviewer", input.bookId)),
|
|
1709
1980
|
mode: "series",
|
|
1710
1981
|
language: resolvedLanguage === "en" ? "en" : "zh",
|
|
1711
1982
|
stageLanguage: resolvedLanguage,
|
|
1712
1983
|
})
|
|
1713
|
-
: await architect.generateFoundationFromImport(book,
|
|
1984
|
+
: await architect.generateFoundationFromImport(book, foundationSource);
|
|
1714
1985
|
await architect.writeFoundationFiles(bookDir, foundation, gp.numericalSystem, resolvedLanguage);
|
|
1715
1986
|
await this.resetImportReplayTruthFiles(bookDir, resolvedLanguage);
|
|
1716
1987
|
await this.state.saveChapterIndex(input.bookId, []);
|
|
1717
1988
|
await this.state.snapshotState(input.bookId, 0);
|
|
1718
1989
|
// Generate style guide from imported chapters
|
|
1719
|
-
if (
|
|
1990
|
+
if (foundationSource.length >= 500) {
|
|
1720
1991
|
log?.info(this.localize(resolvedLanguage, {
|
|
1721
1992
|
zh: "提取原文风格指纹...",
|
|
1722
1993
|
en: "Extracting source style fingerprint...",
|
|
1723
1994
|
}));
|
|
1724
|
-
await this.tryGenerateStyleGuide(input.bookId,
|
|
1995
|
+
await this.tryGenerateStyleGuide(input.bookId, foundationSource, book.title, resolvedLanguage);
|
|
1725
1996
|
}
|
|
1726
1997
|
log?.info(this.localize(resolvedLanguage, {
|
|
1727
1998
|
zh: "基础设定已生成。",
|
|
@@ -1868,9 +2139,10 @@ ${matrix}`,
|
|
|
1868
2139
|
const { plan, composed } = await this.createGovernedArtifacts(book, bookDir, chapterNumber, externalContext, { reuseExistingIntentWhenContextMissing: true });
|
|
1869
2140
|
return {
|
|
1870
2141
|
chapterIntent: plan.intentMarkdown,
|
|
2142
|
+
chapterMemo: plan.memo,
|
|
2143
|
+
chapterIntentData: plan.intent,
|
|
1871
2144
|
contextPackage: composed.contextPackage,
|
|
1872
2145
|
ruleStack: composed.ruleStack,
|
|
1873
|
-
trace: composed.trace,
|
|
1874
2146
|
};
|
|
1875
2147
|
}
|
|
1876
2148
|
async resetImportReplayTruthFiles(bookDir, language) {
|
|
@@ -2367,8 +2639,7 @@ ${matrix}`,
|
|
|
2367
2639
|
}
|
|
2368
2640
|
async createGovernedArtifacts(book, bookDir, chapterNumber, externalContext, options) {
|
|
2369
2641
|
const plan = await this.resolveGovernedPlan(book, bookDir, chapterNumber, externalContext, options);
|
|
2370
|
-
const
|
|
2371
|
-
const composed = await composer.composeChapter({
|
|
2642
|
+
const composed = await composeGovernedChapter({
|
|
2372
2643
|
book,
|
|
2373
2644
|
bookDir,
|
|
2374
2645
|
chapterNumber,
|
|
@@ -2384,12 +2655,16 @@ ${matrix}`,
|
|
|
2384
2655
|
return persisted;
|
|
2385
2656
|
}
|
|
2386
2657
|
const planner = new PlannerAgent(this.agentCtxFor("planner", book.id));
|
|
2387
|
-
|
|
2658
|
+
const plan = await planner.planChapter({
|
|
2388
2659
|
book,
|
|
2389
2660
|
bookDir,
|
|
2390
2661
|
chapterNumber,
|
|
2391
2662
|
externalContext,
|
|
2392
2663
|
});
|
|
2664
|
+
// Persist in the new memo format so subsequent compose/write phases can
|
|
2665
|
+
// skip the planner LLM call when no new context is supplied.
|
|
2666
|
+
await savePersistedPlan(bookDir, plan);
|
|
2667
|
+
return plan;
|
|
2393
2668
|
}
|
|
2394
2669
|
async emitWebhook(event, bookId, chapterNumber, data) {
|
|
2395
2670
|
if (!this.config.notifyChannels || this.config.notifyChannels.length === 0)
|