feat(backthink,browser): 自排工具面 C1-3 + 浏览器两处偏离收口(X2+X3 同文件一并落)

X2 C1-3(自排工具面与提示词):
- request_think(thinktool.go,照 transcode/tool.go 范式)+ reason 必填/urgency 闭集 + 双守门
  (安全闸 + owner 判定:群聊/陌生人一律拒)
- **成对**进两张唤醒态允许集(quiet + awake;CAPACITY_TOOL_SETS 是整体替换)
- 提示词抽共用段落 + 自排前缀优先(不枚举工具清单);面板加 self_wake 标签与筛选轴
- 4 个变异自检(拿掉 owner 判定/只加一张表/放宽 urgency/前端标签恒等)

X3 收口(与 X2 共用 wire_services.go ⇒ 一并落):
- 删掉第三份 SSRF 实现(guard.go),改由 io.ValidateRequestURL 唯一判定 + 薄门面(保两个错误身份)
- 浏览器会话挂进 a.close(真机:真 Chrome 被关、无残留、生产未扰动)
- a.wireBrowser() 归位到 wire_runtime.go,删掉 ioToolOptions 的临时挂点
- 5 个变异自检

顺带补提交 C1-2 漏掉的 internal/config/runtimeconfig/backthink_test.go(ed50053 漏 add)。
This commit is contained in:
AskaEth committed 2026-10-06 21:16:23 +08:00
1 parent 2bf3b536dd
commit 2d211c2d16
20 files changed
+1568 -176

No files matched your search

+12 -6
View File
@@ -7,14 +7,18 @@ import (
)
// allTools is a representative registration-order tool list for tests; it covers
// the basic/io/terminal plugins actually shipped by the repo, plus the two tools
// added to the built-in state sets by X1 (transcode / capability_list).
// the basic/io/terminal plugins actually shipped by the repo, plus the tools added
// to the built-in state sets by X1 (transcode / capability_list) and C1-3
// (request_think, design/12 §N C.3).
//
// ⚠️ 它必须与真实注册面同步:允许集是「档位集 ∩ AllToolNames」,名字不在这份列表里
// 就等于「没注册」,TestDecide_AllowedSets 于是会红 —— 那正是我们要的探针。
func allTools() []string {
return []string{
"terminal", "file", "knowledge", "text",
"web-search", "web-fetch", "http",
"calculator", "datetime", "random", "json", "markdown",
transcodeToolName, capabilityListToolName,
transcodeToolName, capabilityListToolName, selfWakeToolName,
}
}
@@ -177,9 +181,11 @@ func TestDecide_PersonaMinConfidence_ForcesQuiet(t *testing.T) {
func TestDecide_AllowedSets(t *testing.T) {
d := New(activeConfig())
// 内置档位集里的「后加能力」也必须在允许集内(X1 / 裁决 15):登记了能力
// 却不在集合里 = CAPACITY_ENABLED=true 时它调不动。
extra := []string{transcodeToolName, capabilityListToolName}
// 内置档位集里的「后加能力」也必须在允许集内(X1 / 裁决 15 + C1-3):登记了能力
// 却不在集合里 = CAPACITY_ENABLED=true 时它调不动。request_think 由 C1-3 追加,
// 它**必须同时在静息与唤醒两张表里**(她思考时通常落在静息态);本用例的两条断言
// 就是「只加了一张表」的探针。
extra := []string{transcodeToolName, capabilityListToolName, selfWakeToolName}
quiet := d.Decide(context.Background(), in("你好")).AllowedTools
wantQuiet := append([]string{"terminal", "file", "knowledge", "text"}, extra...)
+10 -2
View File
@@ -22,13 +22,21 @@ import (
const (
transcodeToolName = "transcode"
capabilityListToolName = "capability_list"
// selfWakeToolName 是「自排一次思考」工具的名字(internal/services/backthink 的
// ThinkToolName,design/12 §N C.3)。它必须**同时**进下面两张内置允许集:
// 她思考时通常落在静息态(陪伴 / 夜里),只进唤醒态等于「注册了却看不见」。
//
// ⚠️ 主人若用既有的 `CAPACITY_TOOL_SETS` 覆盖档位集,这两张内置表会被**整体替换**
// (`wire_capacity.go` 的 parseCapacityToolSets),那份 JSON 里没写 request_think
// 就照样看不见 —— 该键是「替换」不是「追加」,这条口径与 X1 的同类缺口同源。
selfWakeToolName = "request_think"
)
// defaultQuietTools is the companion-safe face (design §1): terminal + file edit
// + memory/emotion companion. It is a function building the slice fresh so no
// package-level global slice is introduced (project rule §10).
func defaultQuietTools() []string {
return []string{"terminal", "file", "knowledge", "text", transcodeToolName, capabilityListToolName}
return []string{"terminal", "file", "knowledge", "text", transcodeToolName, capabilityListToolName, selfWakeToolName}
}
// defaultAwakeTools extends the quiet face with web/network retrieval (design
@@ -37,7 +45,7 @@ func defaultAwakeTools() []string {
return []string{
"terminal", "file", "knowledge", "text",
"web-search", "web-fetch", "http",
transcodeToolName, capabilityListToolName,
transcodeToolName, capabilityListToolName, selfWakeToolName,
}
}