Files
AskaEth 2d211c2d16 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)。
2026-10-06 21:16:23 +08:00

111 lines
4.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package runtimeconfig
import (
"errors"
"os"
"path/filepath"
"testing"
)
// 本文件守 design/12 §N C.5 的**只读加载件**:落点是
// `$DATA_DIR/config/backthink.json`(零新 env 键),文件缺失 = 还没配过(零值 + nil,
// 不是错误),存在但解不开 = 返回错(调用方记 WARN 并回落默认,绝不静默变成「无上限」)。
// TestDefaultBackthinkPath 钉住落点:`<dataDir>/config/backthink.json`。
// 它同时守住「新家族从一开始就只写 config/」(design/13 §2.1 第 5 条)——
// 路径里少一段 config 就是静默换家。
func TestDefaultBackthinkPath(t *testing.T) {
t.Parallel()
got := DefaultBackthinkPath(filepath.Join("root", "data"))
want := filepath.Join("root", "data", "config", "backthink.json")
if got != want {
t.Fatalf("DefaultBackthinkPath = %q, want %q", got, want)
}
}
// TestLoadBackgroundTuning_MissingFileIsNotAnError 钉住「没配过」不是错误:
// 返回零值 + nil,由服务侧 normalize 回落代码默认(4 轮/小时)。
func TestLoadBackgroundTuning_MissingFileIsNotAnError(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "config", "backthink.json")
got, err := LoadBackgroundTuning(path)
if err != nil {
t.Fatalf("缺失文件应返回 nil error,得到 %v", err)
}
if got.SelfWakePerWindow != 0 || got.SelfWakeWindowSec != 0 {
t.Fatalf("缺失文件应返回零值,得到 %+v", got)
}
// 它**不建目录**:读路径不许留下副作用(新家族没有老位置,也没什么要建的)。
if _, statErr := os.Stat(filepath.Dir(path)); !os.IsNotExist(statErr) {
t.Fatalf("读路径建了目录或留下了别的痕迹:stat err = %v", statErr)
}
}
// TestLoadBackgroundTuning_EmptyFileIsNotConfigured 钉住「全空白 = 还没配过」,
// 与 plugins.json / web-search.json 的既有口径逐字一致。
func TestLoadBackgroundTuning_EmptyFileIsNotConfigured(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "backthink.json")
if err := os.WriteFile(path, []byte(" \n\t\n"), 0o600); err != nil {
t.Fatalf("写测试文件: %v", err)
}
got, err := LoadBackgroundTuning(path)
if err != nil {
t.Fatalf("空白文件应返回 nil error,得到 %v", err)
}
if got != (BackgroundTuning{}) {
t.Fatalf("空白文件应返回零值,得到 %+v", got)
}
}
// TestLoadBackgroundTuning_ReadsSpecShape 钉住规格里给的形状逐字可读
// (design/12 §N C.5 的 JSON 例子),且原样交出**未**回落默认的原始数字
// —— 回落是服务侧 normalize 的事,这里不做第二套默认值。
func TestLoadBackgroundTuning_ReadsSpecShape(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "backthink.json")
body := `{ "selfWakePerWindow": 2, "selfWakeWindowSec": 1800 }`
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
t.Fatalf("写测试文件: %v", err)
}
got, err := LoadBackgroundTuning(path)
if err != nil {
t.Fatalf("LoadBackgroundTuning: %v", err)
}
if got.SelfWakePerWindow != 2 || got.SelfWakeWindowSec != 1800 {
t.Fatalf("tuning = %+v, want {2 1800}", got)
}
}
// TestLoadBackgroundTuning_ZeroStaysZero 钉住「配成 0」原样交出去(不在这里改写成默认):
// 服务侧的 normalize 才是「≤0 回落默认」的唯一执行点,本层若也回落,就等于有了
// 两套默认值真源。
func TestLoadBackgroundTuning_ZeroStaysZero(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "backthink.json")
if err := os.WriteFile(path, []byte(`{ "selfWakePerWindow": 0, "selfWakeWindowSec": -1 }`), 0o600); err != nil {
t.Fatalf("写测试文件: %v", err)
}
got, err := LoadBackgroundTuning(path)
if err != nil {
t.Fatalf("LoadBackgroundTuning: %v", err)
}
if got.SelfWakePerWindow != 0 || got.SelfWakeWindowSec != -1 {
t.Fatalf("tuning = %+v, want 原样(0 与 -1 都不在本地改写)", got)
}
}
// TestLoadBackgroundTuning_BrokenFileReturnsError 钉住坏文件**必须**报错:
// 调用方据此记 WARN 并回落默认。若这里静默返回零值,一个写坏的文件就会安静地
// 变成「用默认值」,与「如实告知」的红线相反。
func TestLoadBackgroundTuning_BrokenFileReturnsError(t *testing.T) {
t.Parallel()
path := filepath.Join(t.TempDir(), "backthink.json")
if err := os.WriteFile(path, []byte(`{ "selfWakePerWindow": `), 0o600); err != nil {
t.Fatalf("写测试文件: %v", err)
}
if _, err := LoadBackgroundTuning(path); !errors.Is(err, ErrInvalidBackthink) {
t.Fatalf("err = %v, want ErrInvalidBackthink", err)
}
}