codebee 0.1.81 → 0.1.82
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/CHANGELOG.md +6 -0
- package/README.md +4 -3
- package/app/core/flows.py +11 -0
- package/app/core/pipeline.py +26 -8
- package/app/core/store.py +4 -0
- package/app/ui/app.js +7 -1
- package/app/ui/i18n.js +2 -0
- package/app/ui/index.html +1 -0
- package/app/ui/style.css +7086 -7086
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,12 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
|
|
|
6
6
|
|
|
7
7
|
## 未发布
|
|
8
8
|
|
|
9
|
+
## v0.1.82(2026-10-04)
|
|
10
|
+
|
|
11
|
+
- **连载「多线剧情推演」开放到界面**:任务表单与流程编辑器都能设 1-3 路分支——起草前先让智能体推演几条剧情走向、择优再动笔(比同章多稿赛马省一个数量级 token)。此前该能力只能手拼 API,而且流程里配好的推演数会被任务创建/保存流程静默冲掉。
|
|
12
|
+
- **赛马复赛不再白烧**:容量受限通道上同章赛马首轮全挂后,复赛此前照发同一份全量提示词再烧一遍 N×2400 秒——现在复赛与重试同口径按身份收缩(经验库→4K、圣经保整段),首轮仍发全量先给一次机会。
|
|
13
|
+
- **降级发生可对账**:起草重试/赛马复赛触发降级时,运行页步骤说明会写明降了哪几层(如「降级:经验库→4K;模块库→边界截断」),提示词为什么变小不再靠猜。
|
|
14
|
+
|
|
9
15
|
## v0.1.81(2026-10-04)
|
|
10
16
|
|
|
11
17
|
- **连载超时重试的「分层降级」修准了**:此前起草超时重试把经验库/圣经/知识库折成一整块再收缩,只能整体 4K 硬截——现在三块分开留底,重试时按各自身份降级(经验库 4K、圣经按二级标题保整段、模块库按模块边界保整模块),大纲/前情/本章要点永不动。重试提示词保住的是结构化上下文,不是一截碎尾巴。
|
package/README.md
CHANGED
|
@@ -33,10 +33,11 @@ Trae Agent、OpenClaw……),提供
|
|
|
33
33
|
---
|
|
34
34
|
|
|
35
35
|
<!-- relnotes:start -->
|
|
36
|
-
### 最新版更新内容(v0.1.
|
|
36
|
+
### 最新版更新内容(v0.1.82)
|
|
37
37
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
38
|
+
- 连载「多线剧情推演」开放到界面:任务表单/流程编辑器可设 1-3 路分支,写前推演择优再动笔;流程里配好的推演数/赛马数不再被静默冲掉
|
|
39
|
+
- 赛马复赛不再白烧:容量受限通道首轮全挂后,复赛按身份收缩提示词(大纲/前情永不动),首轮仍发全量
|
|
40
|
+
- 降级发生可对账:重试/复赛触发降级时,步骤说明写明降了哪几层
|
|
40
41
|
<!-- relnotes:end -->
|
|
41
42
|
|
|
42
43
|
|
package/app/core/flows.py
CHANGED
|
@@ -167,6 +167,17 @@ def _norm_serial(serial):
|
|
|
167
167
|
per = volumes.norm_per(serial.get("volume_chapters"))
|
|
168
168
|
if per:
|
|
169
169
|
out["volume_chapters"] = per
|
|
170
|
+
# 同章赛马/多线推演(1=不启用不落键):流程编辑器(app.js fl-variants)
|
|
171
|
+
# 会把 variants 随 serial 提交,漏带会在 upsert 时被静默丢弃——任务创建
|
|
172
|
+
# 从 flow.serial 继承(store.create_task)后永远读到 1,赛马形同虚设。
|
|
173
|
+
# 钳位口径与 store.create_task 一致(1-3)。
|
|
174
|
+
for key in ("variants", "branches"):
|
|
175
|
+
try:
|
|
176
|
+
n = max(1, min(3, int(serial.get(key) or 1)))
|
|
177
|
+
except Exception:
|
|
178
|
+
n = 1
|
|
179
|
+
if n > 1:
|
|
180
|
+
out[key] = n
|
|
170
181
|
return out
|
|
171
182
|
|
|
172
183
|
|
package/app/core/pipeline.py
CHANGED
|
@@ -2519,9 +2519,10 @@ def _shrink_context_block(sk_block, bible, budget=12000):
|
|
|
2519
2519
|
def _serial_shrunk_block(lessons, bible, kb_block, budget=12000):
|
|
2520
2520
|
"""连载起草重试的分层降级组装:经验库与圣经按各自身份过 _shrink_context_block
|
|
2521
2521
|
(经验库→4K、模块库按模块边界、圣经按二级标题边界),知识库块与大纲/前情
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2522
|
+
同待遇永不动。返回 (重组后的替换块, 降级说明)——调用方整块 replace,字节级
|
|
2523
|
+
对位;降级说明(哪几层生效了)进 step note,运行页可对账(预算内为空串)。"""
|
|
2524
|
+
sk2, bible2, note = _shrink_context_block(lessons, bible, budget=budget)
|
|
2525
|
+
return "\n\n".join(p for p in (sk2, bible2, kb_block) if p), note
|
|
2525
2526
|
|
|
2526
2527
|
|
|
2527
2528
|
def _critic_lens(critics, agent):
|
|
@@ -3596,6 +3597,7 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
|
|
|
3596
3597
|
last_attempt_reason = chapter_reason
|
|
3597
3598
|
prev_prompt = None # 上一次实际下发的提示词
|
|
3598
3599
|
prev_timed_out = False # 上一次是否「超时/停滞」收场
|
|
3600
|
+
shrink_note = "" # 本次重试的分层降级说明(进 step note 供对账)
|
|
3599
3601
|
for draft_attempt in range(3):
|
|
3600
3602
|
if draft_attempt:
|
|
3601
3603
|
# 30s / 60s 退避;ev.wait 睡等可被取消即刻唤醒
|
|
@@ -3609,8 +3611,9 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
|
|
|
3609
3611
|
# ——分层降级:经验库→4K、模块库按模块边界、圣经按二级标题
|
|
3610
3612
|
# 边界,保大纲/前情/本章要点(2026-09-17 七猫实测:全量
|
|
3611
3613
|
# 30KB 对讯飞必挂)
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
+
shrunk_block, shrink_note = _serial_shrunk_block(
|
|
3615
|
+
sk_lessons, bible, kb_block)
|
|
3616
|
+
use_prompt = prompt.replace(sk_block, shrunk_block)
|
|
3614
3617
|
# 超时重试必须有新变量才值得做(2026-09-22):提示词与上次逐字节
|
|
3615
3618
|
# 相同、上次又是超时/停滞收场时,重试只是把同一个超时再烧一遍
|
|
3616
3619
|
# (2400s × N)。此时直接跳出交替换将——换 CLI/模型才是新机会。
|
|
@@ -3622,7 +3625,9 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
|
|
|
3622
3625
|
step_wd, readonly=False, ev=ev, timeout=2400,
|
|
3623
3626
|
resume=resume_ctx["session"] if resume_ctx else None,
|
|
3624
3627
|
images=_task_images(task, workdir),
|
|
3625
|
-
note=("起草重试 %d/2
|
|
3628
|
+
note=("起草重试 %d/2(网关限流退避%s)"
|
|
3629
|
+
% (draft_attempt,
|
|
3630
|
+
(";降级:" + shrink_note) if shrink_note else "")) if draft_attempt else "")
|
|
3626
3631
|
prev_prompt = use_prompt
|
|
3627
3632
|
prev_timed_out = bool((res.get("raw") or {}).get("timed_out"))
|
|
3628
3633
|
if (res.get("raw") or {}).get("repeat_stop"):
|
|
@@ -3729,6 +3734,10 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
|
|
|
3729
3734
|
# 败稿删除;变体 0 = 本任作者(revise 会话沿用),其余取跨族优先的
|
|
3730
3735
|
# 其他真实智能体,不足时同作者开新会话凑数。
|
|
3731
3736
|
scored_variants = []
|
|
3737
|
+
# 复赛降级块(算一次):与非赛马起草重试同源(_serial_shrunk_block)
|
|
3738
|
+
# ——预算内与 sk_block 字节级一致(replace 等于原样),超预算才真降级
|
|
3739
|
+
race_shrunk_block, race_shrink_note = _serial_shrunk_block(
|
|
3740
|
+
sk_lessons, bible, kb_block)
|
|
3732
3741
|
for race_round in range(2):
|
|
3733
3742
|
# 全变体失败(网关突发限流)→ 60s 退避重赛一轮,别一章判死
|
|
3734
3743
|
if race_round:
|
|
@@ -3754,13 +3763,22 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
|
|
|
3754
3763
|
|
|
3755
3764
|
def _draft_one(kk, agent):
|
|
3756
3765
|
vfile = "chapter-%02d-v%d.md" % (i, kk)
|
|
3766
|
+
vp = _draft_prompt(vfile)
|
|
3767
|
+
if race_round and len(vp) > 12000 and sk_block and sk_block in vp:
|
|
3768
|
+
# 复赛分层降级(与非赛马起草重试同口径):容量受限通道上
|
|
3769
|
+
# 全量提示词必挂,复赛照发同一份全量只是把 N×2400s 再烧
|
|
3770
|
+
# 一遍——按身份收缩经验库/圣经(大纲/前情/知识库块不动)。
|
|
3771
|
+
vp = vp.replace(sk_block, race_shrunk_block)
|
|
3772
|
+
note = "赛马变体 %d/%d(%s)" % (kk + 1, len(pool), agent.get("id"))
|
|
3773
|
+
if race_round and race_shrink_note:
|
|
3774
|
+
note += ";复赛降级:%s" % race_shrink_note
|
|
3757
3775
|
r = _run_step(run_id, "draft-c%d-v%d" % (i, kk),
|
|
3758
3776
|
modelhub.bind_agent(agent, difficulty),
|
|
3759
|
-
|
|
3777
|
+
vp, step_wd, readonly=False, ev=ev,
|
|
3760
3778
|
timeout=2400,
|
|
3761
3779
|
# 赛马只在全新起草时启用(无续会话),每路都是新会话
|
|
3762
3780
|
images=_task_images(task, workdir),
|
|
3763
|
-
note=
|
|
3781
|
+
note=note)
|
|
3764
3782
|
results[kk] = (vfile, agent, r)
|
|
3765
3783
|
|
|
3766
3784
|
threads = []
|
package/app/core/store.py
CHANGED
|
@@ -1801,6 +1801,10 @@ def continue_task(task_id, chapters=None):
|
|
|
1801
1801
|
}
|
|
1802
1802
|
if serial.get("variants"): # 赛马配置随链条沿用
|
|
1803
1803
|
payload["serial"]["variants"] = serial["variants"]
|
|
1804
|
+
# 多线推演(branches)同口径随链条沿用:漏带则续写批次恒回 1,
|
|
1805
|
+
# 多线剧情推演在连载链上只剩首批生效
|
|
1806
|
+
if serial.get("branches"):
|
|
1807
|
+
payload["serial"]["branches"] = serial["branches"]
|
|
1804
1808
|
# 分卷配置随链条沿用:卷边界必须跨批次稳定,否则同一卷会被续写批次重切
|
|
1805
1809
|
if serial.get("volumes"):
|
|
1806
1810
|
payload["serial"]["volumes"] = serial["volumes"]
|
package/app/ui/app.js
CHANGED
|
@@ -766,7 +766,7 @@ function onTypeChange() {
|
|
|
766
766
|
const bibleCreate = $("bible-create-field");
|
|
767
767
|
const isSerialReview = isReview && !!(flow && flow.serial);
|
|
768
768
|
if (bibleCreate) bibleCreate.classList.toggle("hidden", !isSerialReview);
|
|
769
|
-
const clearSerialFields = () => ["f-chapters", "f-words-per-ch", "f-variants", "f-bible",
|
|
769
|
+
const clearSerialFields = () => ["f-chapters", "f-words-per-ch", "f-variants", "f-branches", "f-bible",
|
|
770
770
|
"f-vol-chapters", "f-vol-spec"].forEach((id) => {
|
|
771
771
|
const el = $(id);
|
|
772
772
|
if (el) el.value = "";
|
|
@@ -3187,6 +3187,9 @@ async function createTask() {
|
|
|
3187
3187
|
chapters: ch,
|
|
3188
3188
|
words_per_chapter: parseInt($("f-words-per-ch").value, 10) || 2500,
|
|
3189
3189
|
variants: Math.max(1, Math.min(3, parseInt($("f-variants").value, 10) || 1)),
|
|
3190
|
+
// 多线剧情推演:任务级 serial 整体替换流程默认,漏带会把流程里
|
|
3191
|
+
// 配好的 branches 冲掉(store.create_task 字段级不合并)
|
|
3192
|
+
branches: Math.max(1, Math.min(3, parseInt($("f-branches").value, 10) || 1)),
|
|
3190
3193
|
};
|
|
3191
3194
|
// 分卷:显式卷结构文本优先(后端解析成卷表),否则用每卷章数。
|
|
3192
3195
|
// 两个都留空 = 不分卷(后端收到 0/缺字段即不分卷)。
|
|
@@ -3951,6 +3954,7 @@ async function newFromTaskAsync(id) {
|
|
|
3951
3954
|
$("f-chapters").value = tk.serial ? tk.serial.chapters : "";
|
|
3952
3955
|
$("f-words-per-ch").value = tk.serial ? tk.serial.words_per_chapter : "";
|
|
3953
3956
|
$("f-variants").value = tk.serial && tk.serial.variants ? tk.serial.variants : "";
|
|
3957
|
+
$("f-branches").value = tk.serial && tk.serial.branches ? tk.serial.branches : "";
|
|
3954
3958
|
// 分卷:还原每卷章数;指定卷结构还原成可读文本(卷名 + 章数/章号范围)
|
|
3955
3959
|
$("f-vol-chapters").value = tk.serial && tk.serial.volume_chapters ? tk.serial.volume_chapters : "";
|
|
3956
3960
|
$("f-vol-spec").value = tk.serial && Array.isArray(tk.serial.volumes)
|
|
@@ -10887,6 +10891,7 @@ function flowForm(fid) {
|
|
|
10887
10891
|
'<div class="field"><label>' + t("连载章节数(留空 = 单稿件)") + '</label><input id="fl-chapters" type="number" min="2" max="20" value="' + (f && f.serial ? f.serial.chapters : "") + '" placeholder="' + t("例:8") + '"></div>' +
|
|
10888
10892
|
'<div class="field"><label>' + t("每章约字数") + '</label><input id="fl-words-per-ch" type="number" min="500" max="8000" step="100" value="' + (f && f.serial ? f.serial.words_per_chapter : "") + '" placeholder="' + t("例:2500") + '"></div>' +
|
|
10889
10893
|
'<div class="field"><label>' + t("同章赛马稿件数") + '</label><input id="fl-variants" type="number" min="1" max="3" step="1" value="' + (f && f.serial ? (f.serial.variants || 1) : 1) + '" placeholder="' + t("1 = 关闭") + '"></div>' +
|
|
10894
|
+
'<div class="field"><label>' + t("多线剧情推演数") + '</label><input id="fl-branches" type="number" min="1" max="3" step="1" value="' + (f && f.serial ? (f.serial.branches || 1) : 1) + '" placeholder="' + t("1 = 关闭") + '"></div>' +
|
|
10890
10895
|
'<div class="field"><label>' + t("分卷:每卷章数(留空 = 不分卷)") + '</label><input id="fl-vol-chapters" type="number" min="2" max="200" step="1" value="' + (f && f.serial && f.serial.volume_chapters ? f.serial.volume_chapters : "") + '" placeholder="' + t("例:20") + '"></div>' +
|
|
10891
10896
|
"</div>" +
|
|
10892
10897
|
'<div class="field"><label>' + t("起草提示词(可选,占位符 __FILE__ __GOAL__ __CONTEXT__ __SKILLS__)") + '</label><textarea id="fl-draft" rows="3" placeholder="' + t("留空 = 内置通用模板") + '">' + esc(f && f.draft_prompt ? f.draft_prompt : "") + "</textarea></div>" +
|
|
@@ -10932,6 +10937,7 @@ async function saveFlow() {
|
|
|
10932
10937
|
chapters: ch,
|
|
10933
10938
|
words_per_chapter: parseInt($("fl-words-per-ch").value, 10) || 2500,
|
|
10934
10939
|
variants: Math.max(1, Math.min(3, parseInt($("fl-variants").value, 10) || 1)),
|
|
10940
|
+
branches: Math.max(1, Math.min(3, parseInt($("fl-branches").value, 10) || 1)),
|
|
10935
10941
|
};
|
|
10936
10942
|
const vp = parseInt(($("fl-vol-chapters") || {}).value, 10);
|
|
10937
10943
|
if (vp >= 2) payload.serial.volume_chapters = vp; // 流程默认分卷(任务级可覆盖)
|
package/app/ui/i18n.js
CHANGED
|
@@ -1831,6 +1831,8 @@
|
|
|
1831
1831
|
"工作目录内的文件名": "File name inside the workdir",
|
|
1832
1832
|
"1 = 关闭": "1 = off",
|
|
1833
1833
|
"1 = 关闭(2-3 每章多稿择优,更贵)": "1 = off (2-3 drafts per chapter, best wins — pricier)",
|
|
1834
|
+
"多线剧情推演数": "Plot branch plans per chapter",
|
|
1835
|
+
"1 = 关闭(2-3 写前剧情分支推演择优)": "1 = off (2-3 branch plans, best picked before drafting)",
|
|
1834
1836
|
"小写字母开头,可留空": "start with a lowercase letter; optional",
|
|
1835
1837
|
"留空 = 2": "empty = 2",
|
|
1836
1838
|
"留空 = 7.0": "empty = 7.0",
|
package/app/ui/index.html
CHANGED
|
@@ -510,6 +510,7 @@
|
|
|
510
510
|
<div class="field"><label data-i18n="连载模式:章节数(空 = 单稿件一次成文)">连载模式:章节数(空 = 单稿件一次成文)</label><input id="f-chapters" type="number" min="2" max="20" placeholder="例:8(逐章起草+评审+修订)" data-i18n-ph="例:8(逐章起草+评审+修订)"></div>
|
|
511
511
|
<div class="field"><label data-i18n="每章约字数">每章约字数</label><input id="f-words-per-ch" type="number" min="500" max="8000" step="100" placeholder="例:2500" data-i18n-ph="例:2500"></div>
|
|
512
512
|
<div class="field"><label data-i18n="同章赛马稿件数">同章赛马稿件数</label><input id="f-variants" type="number" min="1" max="3" step="1" placeholder="1 = 关闭(2-3 每章多稿择优,更贵)" data-i18n-ph="1 = 关闭(2-3 每章多稿择优,更贵)"></div>
|
|
513
|
+
<div class="field"><label data-i18n="多线剧情推演数">多线剧情推演数</label><input id="f-branches" type="number" min="1" max="3" step="1" placeholder="1 = 关闭(2-3 写前剧情分支推演择优)" data-i18n-ph="1 = 关闭(2-3 写前剧情分支推演择优)"></div>
|
|
513
514
|
<div class="field"><label data-i18n="分卷:每卷章数(空 = 不分卷)">分卷:每卷章数(空 = 不分卷)</label><input id="f-vol-chapters" type="number" min="2" max="200" step="1" placeholder="例:20(卷边界按全书章号自动推导)" data-i18n-ph="例:20(卷边界按全书章号自动推导)"></div>
|
|
514
515
|
</div>
|
|
515
516
|
<div class="field" id="f-vol-spec-field"><label data-i18n="分卷:指定卷结构(可选,优先于每卷章数)">分卷:指定卷结构(可选,优先于每卷章数)</label><input id="f-vol-spec" placeholder="例:第一卷 少年初入江湖 20章;第二卷 风云再起 16章" data-i18n-ph="例:第一卷 少年初入江湖 20章;第二卷 风云再起 16章" data-i18n-title="每卷一行或分号分隔:卷名 + 章数(或第1-20章)。也可以在任务目标里直接这样写,会自动识别" title="每卷一行或分号分隔:卷名 + 章数(或第1-20章)。也可以在任务目标里直接这样写,会自动识别"></div>
|