feat(portal): /portal/daemon/extract 接受 daemon 自帶提示詞——卡片格式契約回歸單一真相源(Arcrun#134)

免金鑰預設路(Workers AI)一直用雲端自己那份舊格式 prompt(一句話定義/要點/
關鍵實體/關聯),而 daemon 端 2026-08-15 已改成「LLM 只回 JSON 判斷、wikishape.go
機械組卡」(InkStoneCo#44 ④)⇒ 走預設路的用戶拿到次級卡。兩份 prompt 靠註解
叮嚀「兩邊要一起改」同步,這張票就是叮嚀失效的證據。

修法=契約搬回唯一一處:daemon 送 {page_name, text, prompt},雲端在 prompt 模式
只當執行器(用實例自己的 env.AI 跑生成、max_tokens 對齊 gemma 路的 8192),
原文以 {success, output} 回傳,淨化與解析全在 daemon。雲端不再認得卡的形狀。

相容兩個方向都有路:舊 daemon(無 prompt)走 legacy 路,行為與回應完全不變;
新 daemon 撞舊雲端(回 card 無 output)由 daemon fallback 到 legacy 卡處理。

測試:portal-admin +2(prompt 單獨成立=501 探針非 400;legacy 齊欄行為凍結),
全套 447 passed,14 failed 與基準(main)逐一相同=非本改動引入。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
uncle6me-web
2026-08-15 21:21:48 +08:00
parent 969acff325
commit 9fa88065ab
2 changed files with 58 additions and 13 deletions
@@ -748,4 +748,22 @@ describe('POST /portal/daemon/extractt181Workers AI 萃卡,免金鑰)'
expect(raw).not.toContain('gemini_api_key');
expect(raw).not.toContain('credential');
});
// 🔴 Arcrun#134:新 daemon 自帶提示詞(卡片格式契約的唯一真相源在 daemon 端
// collector/——提示詞+JSON 解析+wikishape 組卡同住一處,才不會像 t181 那樣
// 兩份 prompt 靠註解叮嚀同步而漂移)。雲端在 prompt 模式下只是執行器。
//
// 測試環境刻意沒有 [ai] binding ⇒ 走到 AI 分支必回 501。這裡拿 501 當「驗證已通過、
// 已進入 AI 分支」的探針:若有人把 prompt 模式改回要求 page_name/text,這則會看到 400。
it('帶 prompt 時不再要求 page_name/text#134:契約住 daemon 端)', async () => {
const res = await json('POST', '/portal/daemon/extract', { prompt: '任意契約內容' }, KEY);
expect(res.status).toBe(501); // 不是 400 ⇒ prompt 單獨成立
});
// 相容守衛:舊 daemon(無 prompt 欄位)行為凍結——缺欄仍 400(上面那則),
// 齊欄則同樣走到 AI 分支(501 探針)。若這則變 400,代表 legacy 驗證被動到了。
it('legacy(無 prompt)齊欄仍走原路(相容不回退)', async () => {
const res = await json('POST', '/portal/daemon/extract', { page_name: 'x', text: 'y' }, KEY);
expect(res.status).toBe(501);
});
});