← dsh-novel-writer 技术文档 / novel_sentence_config

novel_sentence_config

写作助手开关的查看与修改。读取即返回「总开关 + 18 个工具开关 + 9 个功能开关 + 系统提示词档位、场景与精简工作流 + 风格基线容差 + 原创模式设定 + 语义引擎状态」的生效值action: "set" 时把传入字段增量写入状态文件并强制回读。开关落在 ~/.dsh/dsh-novel-writer/state.json,与 Web GUI 侧边栏读写同一文件(GUI 走插件自带的 POST /api/dsh-novel-writer/state 路由)。本工具自身禁止被关闭

参数

参数类型必填说明
actionstring枚举 get / set默认 get:实现为 args.action === "set" ? "set" : "get",任何非 "set" 的值(含省略)都按查看处理。
enabledboolean写作助手功能总开关。仅布尔值参与写入,非布尔值静默忽略。
autoAnalyzeboolean分析作品时是否主动使用句式分析。仅布尔值参与写入。
systemPromptModestring系统提示词档位:枚举 off(不注入) / brief(精简) / full(完整)。非枚举值静默忽略(不报错、不改盘)。
promptScenestring系统提示词场景:枚举 general / writing / revising / auditing / setup。仅 full 档生效;非枚举值静默忽略。general 是合法取值,用于把场景改回通用档。详见下文「提示词档位与场景」。
leanWorkflowboolean系统提示词精简工作流(v5.1.0 新增,英文标签 Lean workflow):打开后注入 LEAN_TEXT,且优先于档位与场景。默认 false只有真正的布尔值被采用,非法值(字符串 "true" / 1 / null …)静默忽略——与 promptScene 同一套「非法即丢弃、不报错不回显」的口径。详见下文「提示词档位与场景」。
toolsobject各工具开关,形如 { novel_plot: false }。键必须在 ALL_TOOLS 的 18 个名字内,值必须是布尔,其余静默忽略novel_sentence_config 自身的键会被强制剔除。与现有值浅合并
featuresobject功能开关。合法键仅 9 个(见下表),其余键静默忽略;与现有值浅合并。
styleToleranceobject风格基线容差,每维 { low, high }low 为负、high 为正)。low 钳到 [-99, 0]high 钳到 [0, 99],两者须同时为数字且 low ≤ high,否则该维被整体丢弃。传 {}null 表示清除(恢复推荐值)。
creationProfileobject全局原创模式设定,六个字符串键:worldview / characters / forbidden / mainConflict / genre / extra。留空项省略。传 {}null 表示清除。
creationProfilesobject按书专属原创设定,键 = 书名,值结构同上。与现有条目合并(同键覆盖);某书的值传 null 表示删除该书条目;传 {} 表示清除全部书的设定。
参数 schema 不含 bookroot本工具是全局开关表,没有书库作用域;参数 schema 声明为 additionalProperties: false,即 schema 之外不存在任何可传字段。唯一的书库相关字段是只读回显的 creationProfiles(键为书名)。
键白名单是静默的。toolsfeatures 只挑白名单内的键写入,拼错的键名既不报错也不出现在回显里。判断某个键是否被接受,只能读返回体的 tools / features,不能读 updated——只要同一批里有一个合法字段生效,updated 就是 true

输出结构

契约必返字段(output.schema.required):fileenabledautoAnalyzetoolsfeaturesembeddingstyleTolerancecreationProfile。实现中还会恒定返回 sourceupdatedsystemPromptModepromptSceneleanWorkflowcreationProfiles

字段类型内容
filestring状态文件的绝对路径,由 stateFilePath() 给出
enabledboolean生效的总开关(写后回读的结果,非传入值)
autoAnalyzeboolean生效的自动分析开关
systemPromptModestring写后回读的提示词档位:off / brief / full(盘上的非法值已在读取侧回退为默认 brief
promptScenestring写后回读的提示词场景:general / writing / revising / auditing / setup(非法值已回退为默认 general)。回读值与你要写入的值不一致 = 该参数被判为非法而静默丢弃,这是比 updated 可靠的校验方式
leanWorkflowboolean写后回读的精简工作流开关(v5.1.0 新增);盘上非布尔值已在读取侧回退为 false。老状态文件缺该键时同样为 false——即行为与 5.0.0 完全相同
sourcestring生效值来源:state 文件(GUI 开关) / v0.4.0 兼容文件 novel-writer.json / 插件 config / 默认值
updatedboolean本次 set 是否发生了实际写入(patch 为空则为 false)
toolsobject18 个 novel_* 工具名到当前开关的映射,逐个由 toolEnabled 求值
featuresobject9 个功能键到当前开关的映射,逐个由 featureEnabled 求值——恒有 9 个键,与文件里实际存了几个无关
embeddingobject{ available, loaded, error },语义引擎状态,见下文
styleToleranceobject用户自定义容差;未设置为 {}(语义:使用推荐值),不是 null
creationProfileobject全局原创设定;未设置为 {}
creationProfilesobject按书设定;未设置为 {}
没有 brief 精简模式。本工具的参数 schema 为 additionalProperties: false,不含 brief;渲染层也没有精简分支。渲染文本是一份固定格式的开关清单(<path> / <type>novel-sentence-config</type> / <content>),逐行列出总开关、autoAnalyze提示词档位与场景系统提示词: 档位=X 场景=Yfull 档 + 非 general 场景时追加「(按场景注入)」)、来源、18 个工具开关与全部功能开关,体积由开关数量决定,不可再压缩。这里的 brief 指工具自身的精简输出参数,与提示词档位 systemPromptMode: "brief"两回事;也与 leanWorkflow 是两回事——后者只让 novel_style_report / novel_sentence_analysis 在未显式传 brief 时默认精简,本工具的渲染不受它影响

计算原理

1 · 状态文件与读取回退

file = $DSH_NOVEL_WRITER_STATE(非空时) 否则 ~/.dsh/dsh-novel-writer/state.json ← homedir()/.dsh readSentenceState(): 文件不存在 或 JSON 解析失败 → { exists:false, ...SENTENCE_ANALYSIS_DEFAULTS } SENTENCE_ANALYSIS_DEFAULTS = { enabled:true, autoAnalyze:true, systemPromptMode:"brief", promptScene:"general", leanWorkflow:false } 存在 → 逐字段类型校验,不符即回退默认: enabled / autoAnalyze : 非 boolean → 默认值 systemPromptMode : 不在 ["off","brief","full"] → 默认值 "brief" promptScene : 不在 PROMPT_SCENES 五值内(含缺失)→ 默认值 "general" leanWorkflow : 非 boolean(含缺失)→ 默认值 false ← v5.1.0;与 promptScene 同一套「非法即丢弃」口径 tools / features : 非对象 → {} styleTolerance / creationProfile : 非对象 → null creationProfiles : 非对象 → {} lastRoot : 非字符串 → undefined

exists 是读取侧由文件是否存在推导出的派生字段,不落盘(写盘前被显式剔除)。磁盘上真实的 state.json 字段为 enabledautoAnalyzesystemPromptModepromptSceneleanWorkflowtoolsfeaturesstyleTolerancecreationProfilecreationProfileslastRootreadSentenceStateSync(系统提示词回调用的同步版)对这些字段做同样的回退,因此老状态文件在两条读取路径下都落到 brief + general + leanWorkflow:false

2 · 生效值的优先级

返回体里的 enabled / autoAnalyze 不是文件原值,而是 effectiveSentenceAnalysis 的结果:

state.exists === true: enabled = state.enabled ?? true autoAnalyze = state.autoAnalyze ?? true ← 插件 config 与兼容文件全部不再参与 state.exists === false: 兼容文件 ~/.dsh/novel-writer.json 的 stylePattern === true → enabled = true 否则 enabled = config.sentenceAnalysis.enabled ?? config.sentenceAnalysis.stylePattern ?? true autoAnalyze = config.sentenceAnalysis.autoAnalyze ?? true source 文案与之一一对应: exists → "state 文件(GUI 开关)" !exists 且 兼容文件为 true → "v0.4.0 兼容文件 novel-writer.json" !exists 且 config 有该字段 → "插件 config" 其余 → "默认值"
state 文件一旦存在,插件 config 即被完全屏蔽。该文件由 GUI 或本工具的任意一次 set 创建(writeSentenceState 一律整份落盘),因此「配了 config.sentenceAnalysis 却不生效」是预期行为,不是配置写错。

3 · 工具开关(tools

toolEnabled(state, name) = state.tools[name] !== false ← 未登记、null、0、"" 都算「开」;只有显式 false 才算关闭 写侧白名单: for (name of ALL_TOOLS) if (typeof args.tools[name] === "boolean") 收下 delete toolsPatch.novel_sentence_config ← 自身禁止被关 tools = { ...current.tools, ...toolsPatch } ← 浅合并

18 个 ALL_TOOLS 条目:novel_booksnovel_chaptersnovel_readnovel_keywordsnovel_new_chapternovel_chapter_briefnovel_importnovel_sentence_analysisnovel_sentence_confignovel_style_checknovel_fix_plannovel_plotnovel_settingsnovel_summarynovel_continuity_checknovel_semantic_searchnovel_style_reportnovel_outline

关闭一个工具的后果并不统一:18 个工具的 execute 首行各自调用 assertToolEnabled,关闭时抛错(硬拒绝)。两类例外走软降级——novel_sentence_analysis 在总开关 enabled === false 时返回禁用桩(enabled:falsetotalChars:0totalSentences:0 加一段 message);novel_semantic_searchsemanticSearch 关闭或引擎不可用时返回 available:falsemessage 的对象。前者的关闭还会让 novel_style_check 直接报错拒绝执行。

4 · 功能开关(features,9 键)

featureEnabled(state, name): v = state.features[name] return typeof v === "boolean" ? v : FEATURE_DEFAULTS[name] !== false ← 未知键也返回 true
默认作用
emotionCaveattrue情感净化预警
genreThemetrue题材与流派检测
emotionComplexitytrue情感复杂度量化
semanticEmbeddingtrue本地语义增强总闸;关闭后三个 semantic* 子开关一并失效
semanticSearchtrue语义检索(novel_semantic_search
semanticStyletrue衔接检查里的语义距离一路
semanticImplicittrue隐性情感的语义检测
rawWritingfalse非净化直白模式;默认关闭,是唯一默认 false 的键
webnovelVibetrue网文信号检测

三个 semantic* 子开关与总闸是关系(semanticFeatureEnabled 先看 semanticEmbedding 再查子键)。

5 · styleTolerance 与六个维度

clampStyleTolerance(tol): for [key, value] of Object.entries(tol): 非对象 → 该键丢弃 low = typeof value.low === "number" ? clamp(value.low, -99, 0) : undefined high = typeof value.high === "number" ? clamp(value.high, 0, 99) : undefined low 或 high 缺失,或 low > high → 该键整体丢弃 否则收下 { low, high }

合法维度键为 METRIC_ORDER 六项:complexity(句法复杂度)、modifierDensity(修饰密度)、abstractDensity(抽象度)、actionDensity(动作密度)、hedgeDensity(不确定性)、gapIndex(留白指数)。写侧不校验键名,未知维度会落盘但没有任何消费点;读取侧未设置时返回 {}

// 消费点:novel_style_check for (key of METRIC_ORDER): rt = typeof allBaseline[key].recTol === "number" ? allBaseline[key].recTol : 15 tol[key] = { low: -rt, high: rt } for (key of METRIC_ORDER): ut = state.styleTolerance[key] 若 ut.low 与 ut.high 都是 number → tol[key] = { low: ut.low, high: ut.high } judgeAgainstBaseline(本章指标, 排除本章后的基线, tol)

推荐容差底取「目标章的全书每维 recTol」(约作者自身波动 1.5σ,四舍五入到 5 的倍数、下限 10、上限 100),用户自定义只覆盖被点名的维度,未配置的维度不受「排除目标章后样本变少」影响。

6 · 写入路径

writeSentenceState(patch): stateWriteChain 串行化 → 读现状 → 合并 → 剔除派生键 exists enabled / autoAnalyze : 覆盖 systemPromptMode : 仅当 ∈ ["off","brief","full"] 时覆盖,否则忽略 promptScene : 仅当 ∈ PROMPT_SCENES 时覆盖,否则忽略 tools / features : 浅合并 { ...current, ...patch } styleTolerance : 非 null 对象 → clampStyleTolerance();null → 置 null creationProfile : 非 null 对象 → 覆盖;null → 置 null creationProfiles : 空对象或 null → 清除全部; 非空对象 → 合并,值为 null/undefined 的键删除 atomicWriteJson(file, persisted) 返回 { ...next, exists: true } ← 写完必然存在 atomicWriteJson(file, obj): 写 file + ".tmp-" + pid + "-" + Date.now() rename(tmp, file) rename 失败 → 直写 file(跨设备 / 被占用 / 只读的回退) 直写也失败 → 抛 Error,code = "ENOVELWRITEFAIL"

set 成功后强制重读状态文件再计算生效值与 source,避免首写时返回写前快照(旧版曾出现盘上 enabled:false 而返回值仍是 config 的 true)。若本次 patch 含 creationProfiles,还会同步 novels/创作资料/<书名>/创作设定.md主要人物设定.md 的用户段(含空壳目录清理);同步失败不影响设定保存。

7 · rawWriting 的语义与写入位置

写入位置:state.json 的 features.rawWriting (默认 false) 生效位置:DSH 系统提示词 section "novel-writing:raw-writing",order = 151 读 readSentenceStateSync().features.rawWriting === true 时注入 RAW_WRITING_PROMPT 否则返回空串(宿主丢弃空段落,等于不注入)

RAW_WRITING_PROMPT 的文本为「非净化模式已开启(用户已确认)」加四条要求:照原文的细节密度与露骨程度描写血腥 / 暴力 / 成人场景、不回避不委婉化、保持原文用词与动作细节、仅限用户个人创作。GUI 中开启该开关需经过双重确认与承诺输入;通过本工具直接传 { features: { rawWriting: true } } 会跳过这套确认流程,因此只应在用户明确要求时使用。

与之相邻但属于独立维度的是系统提示词档位 systemPromptModeoff / brief / full)与场景 promptScenegeneral / writing / revising / auditing / setup):两者同样落在状态文件里,但只影响「小说写作助手」这一段提示词的注入,与工具能力无关。详见下一节。

8 · 语义引擎状态(embedding

st = embedding.status() ← { modelPresent, loaded, error, lastCacheError },只探测文件与已加载标志,不加载模型 available = features.semanticEmbedding 为真 且 (st.loaded 或 st.modelPresent) loaded = st.loaded error = features.semanticEmbedding 为真 ? (st.error ?? "") : "semanticEmbedding 已关闭"
available: true 不等于「推理可用」。它只表示开关打开且模型文件在位(或已加载)。真正完成 ONNX 会话加载要看 loaded;加载失败时 error 为失败原因的前 300 字,且有 30 秒冷却后自动重试。

提示词档位与场景

本版把系统提示词的注入拆成三个正交维度档位(systemPromptMode)决定「注入多少」,场景(promptScene)决定「注入什么」,精简工作流(leanWorkflow)决定「要不要催促动作」。它们都只影响「小说写作助手」这一段插件系统提示词,不改变任何工具的能力、参数、返回值或开关生效状态

维度取值含义
systemPromptMode
(档位)
off不注入。promptTextFor 返回空串,DSH 侧过滤掉空段落,等于该段完全不存在。
brief精简档(默认):只说明「已挂载 novel_* 工具、详细规范见 novel-writing 技能」,几乎不占上下文。该档与场景无关——不论 promptScene 取什么值,注入的都是同一段 BRIEF_TEXT
full完整档:按场景注入对应的那一套工作流文本(见下表)。
promptScene
(场景)
general通用写作工作流(默认):章节库约定、分析方法、续写流程、导入整理、工具链提示等全量约定。这段文本来自 4.x 的 WORKFLOW_TEXT——结构逐字沿用,但 v5.1.0 把其中的「必做」改成了「按需」:基线由开写包 / 建章直接附带,不必专门去调 novel_style_report;写完建议跑一次 novel_style_check只有偏离明显时才修正(详见下方「出带不等于必改」)。
writing写新章:先取材料(开写包)→ 简述计划 → 读锚段校准语感 → 遵守禁用清单 → 建章节 → 建议跑一次自检(偏离明显才修)→ 收尾按需(不必每章全套)。
revising改稿:先取改稿清单 → 分批改(同段落 / 同类型合并成一次修改,一轮只处理最严重的 3~5 条,只改问题处、不整章重写)→ 不要逐条 mark,也不要反复 verify(一轮改完只跑一次 verify)。
auditing审计:只体检、只报告,不改正文、不写章节、不登记设定;结构 / 风格 / 手法三层各自的工具与「候选而非结论」的输出要求。
setup建资料:只维护创作资料与设定表,不写正文;初始化骨架、登记五张表、登记伏笔、扫描已有正文,最后用结构视图自查。
leanWorkflow
(精简工作流)
false默认:按上面两个维度选择文本,与 5.0.0 行为一致。
true注入 LEAN_TEXT380 字符),且优先于档位与场景——档位与场景取什么值都不改变这一结果。该文本不再罗列流程,只保留最短的必要提醒,用来抑制模型「按流程逐项打勾」的冲动:不再催促每章都做完整套收尾、也不再要求把每条待办都标记一遍或反复复测。任何时候都能切换(不受 full 档限制)。另有两处联动:novel_style_reportnovel_sentence_analysis 在调用方未显式指定 brief 时,默认走精简输出。
生效文本的选择(v5.1.0 在档位 × 场景之前多插一层 leanWorkflow 判定): leanWorkflow === true → LEAN_TEXT(380 字符;优先于档位与场景) promptTextFor(mode, scene): mode === "off" → ""(空串,DSH 丢弃该段) mode === "brief" → BRIEF_TEXT mode === "full" 且 scene ∈ SCENE_TEXTS 四值 → 该场景文本(SCENE_TEXTS[scene]) mode === "full" 且 scene 为 general 或未知/缺失 → WORKFLOW_TEXT SCENE_TEXTS = { writing, revising, auditing, setup } ← general 不在表内,它就是 WORKFLOW_TEXT PROMPT_SCENES = ["general","writing","revising","auditing","setup"] ← 合法枚举(含 general) leanWorkflow = true | false(默认 false,只有真正的布尔值被采用) 生效位置:DSH 系统提示词 section "novel-writing",order = 150 text 是函数 → 每轮组装提示词时实时读状态文件(下一轮生效,无需重启) 读不到状态时回退 BRIEF_TEXT;rawWriting 是相邻的另一段(order = 151),与档位/场景无关

场景只在 full 档下生效。off 档恒为空串、brief 档恒为 BRIEF_TEXT,两者都会忽略 promptScene 的取值。反过来,full 档 + general 就是 4.x 的完整行为(v5.1.0 只把其中三处「必做」放宽成「按需」,见下)——因此「升级到 5.0.0」本身不会改变任何提示词内容,想按场景分流必须显式把 promptScene 改掉。

v5.1.0:三处「必做」改「按需」,出带不等于必改。五个场景文本里有三处硬性要求被放宽:writing 原先要求建完章节立刻做一次风格自检、并把收尾固定成一套动作;revising 原先要求按 severity 一条一条过、每改一批就登记并复测;general 原先把「动笔前先出风格报告」与「每写完一章都做风格自检」写成硬性前提——现在分别改为「写完建议跑一次自检,只有相似度明显偏低或某维偏离超过 2 倍容差时才修正」「收尾按需,不必每章全套」「基线由开写包 / 建章直接附带,不必专门去调工具,建议跑一次自检、偏离明显时才修正」。
新口径:出带不等于必改。只有偏离达到 2 倍容差以上、或那一处读起来确实别扭时才改。理由是六维容差带本身取 1.5σ(约等于作者自身的章节波动),在这个带宽下六维里至少有一维出带是常见现象——正常波动不该被当成缺陷反复打磨,否则改到最后只是把作者的写法磨平、把数字对齐。相应地,「照骨架造句」也一并改口:anchors 只用来校准语感不要照 skeletons 造句、不要套句式模板(骨架仅在写不出该类型句子时参考)。
leanWorkflow 是覆盖层,不是第四个档位。它不改变 systemPromptMode / promptScene 的磁盘值,也不参与「档位」的枚举;打开时只是在文本选择的最前面插一条命中分支。因此关掉它就能原样回到先前那套文本,不需要把档位与场景改回去。它同样不影响任何工具能力——「不要逐条 mark」是提示词对模型的约束,novel_fix_planmark 依然照常可用。
场景只影响提示词内容,不影响工具能力。切到 revising 不会禁用章节工具,切到 auditing 也不会把工具变成只读——「不改正文」是提示词对模型的约束,不是插件的运行时限制。工具开关与总开关仍由上面的 tools / enabled 独立控制,两者互不影响。
向后兼容:没有 promptScene 键的老状态文件落到 general,既有工作流不变。两条读取路径(异步 readSentenceState 与同步 readSentenceStateSync)都以 PROMPT_SCENES.includes(...) 校验,缺失或非法一律回退 generalgeneral 映射到通用档的 WORKFLOW_TEXT(4.x 原文结构,本版在其中补入三条新工具的入口指引共 7 行,v5.1.0 又把三处「必做」放宽为「按需」)。写入侧同理:非枚举值被静默忽略(不写盘、不报错),而 general 是显式合法值,用于把场景从四套流程改回通用档。
向后兼容:没有 leanWorkflow 键的老状态文件落到 false,行为与 5.0.0 相同。读取侧按「只有真正的布尔值被采用」处理:键缺失、为 null、为字符串 "true"、为数字 1 一律落到 false,且静默忽略(不写盘、不报错、不回显失败)——与 promptScene 的非法值口径一致。写入侧同样只接受布尔值。因此这个开关是纯增量的:不打开就等于 5.0.0 的提示词行为,升级本身不会改变任何注入文本。

写入渠道有两个:本工具的 action: "set"systemPromptMode / promptScene / leanWorkflow 参数)与 Web GUI 侧边栏首页开关走的 POST /api/dsh-novel-writer/state(GET 响应里同样回显这三个字段)。两条路径最终都调用同一个 writeSentenceState,写入与校验口径一致。侧边栏「写作助手功能」面板里的精简工作流(英文标签 Lean workflow)一行位于「提示词档位」「提示词场景」下方,与它们并列,任何时候都能切换——不受 full 档限制,brief / off 档下同样可用。

约束与边界

  • 本工具不能被关闭。两条写入路径都强制剔除该键:工具侧写入前 delete toolsPatch.novel_sentence_config,GUI 路由侧同样在写入前删除。因此它通常不出现在 state.jsontools,读取时按 !== false 判定为开。这一设计是为避免「关掉开关后连开启的工具都调不到」的死锁。
  • 白名单之外的一切静默忽略。tools 只认 18 个工具名,features 只认 9 个键,systemPromptMode / promptScene 只认各自的枚举、leanWorkflow 只认布尔;非布尔值、非对象、拼错的键都不会报错也不会回显。updated 只表示「发生过写入」,不能用来确认某个具体键被接受——要确认请读返回体里对应字段的回读值。
  • 非法容差维度是整体丢弃,不是钳到边界。low > high、只给一侧、非数字都会让该维不写入(保持此前磁盘值或推荐值);low / high 本身的越界值会被钳到 [-99, 0] / [0, 99]。未知维度键会落盘但无消费点。
  • {}null 都是「清除」。styleTolerance / creationProfile 传空对象或 null 即清空;creationProfiles 传空对象或 null 表示清除全部书的设定(并触发创作资料里的用户段移除与空壳目录清理)。宿主的 JSON Schema 若不支持 null 类型,一律用 {}
  • set 是增量而非整份替换。未传字段保持原值;tools / features / creationProfiles 为浅合并。creationProfiles 不提供「只删某键但保留该书其余字段」的语义——按书整体替换,值传 null 是删除该书。
  • 生效值与磁盘值可能不同。source 反映的是生效值从哪来:state 文件一旦存在,插件 config.sentenceAnalysis 与 v0.4.0 兼容文件都不再影响 enabled / autoAnalyze,但 styleTolerance 等其余字段本来也只从 state 文件读。
  • 开关的关闭后果不统一。工具开关关闭 → 该工具 execute 抛错(硬拒绝);总开关 enabled=falsenovel_sentence_analysis 返回禁用桩、novel_style_check 抛错;semanticSearch 关闭 → 语义检索返回 available:false 的软降级对象。调用方不能假设「关闭 = 报错」或「关闭 = 空结果」。
  • autoAnalyze 只影响提示词,不影响任何工具返回值。它被写进系统提示词第 4 条(false 时要求「仅在用户明确要求时调用」句式分析);插件本身不据此改变输出。
  • 档位、场景与精简工作流是三个独立维度,且场景只在 full 档生效。off 恒不注入、brief 恒注入精简文本,两者都忽略 promptScene;只有 full 档下 general / writing / revising / auditing / setup 才有区别。full + general 即 4.x 的原始行为。第三个维度 leanWorkflow覆盖层:为 true 时注入 LEAN_TEXT 并优先于前两个维度(与档位是否 full 无关,任何时候都能切换),为 false 时三个维度退回成上面的两维关系。三个字段都不改变工具能力,只换提示词文本。
  • 提示词改动下一轮生效,无需重启。该 section 的 text 是一个函数,在每轮组装系统提示词时现读状态文件;因此改完开关后当前这一轮仍用旧文本。状态读不到时回退精简档 BRIEF_TEXT
  • 跨进程写入不是事务。写入串行化(stateWriteChain)只在单个进程内生效。MCP 服务器是独立进程,它与 DSH 宿主内的 GUI 同时写同一文件时,读-合并-写可能互相覆盖;需要并发写入时应串行化调用而非并行。
  • 写入失败与参数错误可区分。磁盘写不进去时抛出的错误带 code = "ENOVELWRITEFAIL",GUI 路由据此返回 500;其余写入异常在路由层返回 400。首次 set 的返回值取自写后重读,因此不会出现「返回值与盘上状态相反」。
  • 无 brief / 精简模式。参数 schema 为 additionalProperties: false 且不含 brief;需要控制 token 时应减少调用频次,而不是指望该工具压缩输出。
  • 跨版本差异。systemPromptMode 为 v4.0.0 引入的字段,更早的状态文件没有该键,读取侧按默认 brief 处理;promptScene 为 v5.0.0 引入,老状态文件没有该键时按默认 general 处理——general 即 v4.x 的通用工作流(本版仅在其第 3、7 节补入三条新工具的入口指引,共 +7 行;v5.1.0 又把其中三处「必做」放宽为「按需」),既有工作流不变rawWriting 在明确设置前按 FEATURE_DEFAULTSfalse 处理(旧版曾把它误报为 true);leanWorkflow 为 v5.1.0 引入,老状态文件没有该键时按默认 false 处理,行为与 5.0.0 相同

相关工具

  • novel_sentence_analysis —— 受 enabledautoAnalyze 直接约束的分析工具;enabled=false 时返回禁用桩。
  • novel_style_check —— styleTolerance 的唯一消费点,逐维覆盖推荐容差后做基线判定。
  • novel_style_report —— 六维基线与 recTol 的来源;未自定义容差时本工具回显 {},即使用该推荐值。

源码位置

  • lib/index.js —— 工具注册与实现 registerNovelSentenceConfig:参数白名单(tools / features 的合法键列表)、写入分支、source 推导与返回体组装
  • lib/prompts.js —— 系统提示词文本与选择逻辑:RAW_WRITING_PROMPTWORKFLOW_TEXTgeneral 场景的文本)、BRIEF_TEXTLEAN_TEXT(v5.1.0 新增的精简工作流文本,380 字符)、SCENE_TEXTSwriting / revising / auditing / setup 四段)、PROMPT_SCENES(合法场景枚举)、promptTextFor(mode, scene)(档位 × 场景的选择器;leanWorkflow 为真时优先返回 LEAN_TEXT)。
  • lib/client.js —— 侧边栏「写作助手功能」面板的渲染与提交:新增精简工作流Lean workflow)一行,位置在「提示词档位」「提示词场景」下方,与档位 / 场景并列且不受 full 档限制。
  • lib/index.js —— ctx.systemPrompt.section({ name: "novel-writing", order: 150 })text 回调读 readSentenceStateSync() 后调用 promptTextFor;相邻的 novel-writing:raw-writing(order 151)与档位/场景无关。
  • lib/core.js —— SENTENCE_ANALYSIS_DEFAULTS(含 systemPromptMode / promptScene / leanWorkflow 默认值)、ALL_TOOLSFEATURE_DEFAULTSfeatureEnabledtoolEnabledassertToolEnabledstateFilePathreadSentenceState / readSentenceStateSyncwriteSentenceStateatomicWriteJsonclampStyleToleranceeffectiveSentenceAnalysismakeStateRoutes(GUI 侧 GET/POST /api/dsh-novel-writer/state,GET 回显 systemPromptMode / promptScene / leanWorkflow
  • lib/style-metrics.js —— METRIC_ORDER / METRIC_LABELS / computeBaselineFromPerChapterrecTol
  • lib/embedding.js —— status / isAvailableembedding 字段的来源)
  • mcp/server.mjs —— MCP 侧只注入 root,不读写状态文件;因此 MCP 调用与本工具共享同一份 state.json