feat: AutoZero 通用 Agent 框架(从 AutoGo 五阶段拆分完成)

llm(三协议 Provider)/ session(JSONL 持久化)/ tools(Registry、围栏、
builtin、computer)/ cdp(browser)/ skills / mcp / agent(循环、两级压缩、
编排、审批门控)+ 底座 jsonl/textx/execx/diag/scratch/spill/imagecache。

产品装配代码(config 桥接、schedule 工具、memory/plan/retro/prompt)
留在 AutoGo,宿主接入方式见 MIGRATION.md。
This commit is contained in:
Sakurasan committed 2026-10-26 00:54:46 +08:00
commit d5dac5a6fc
140 files changed
+26497

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
package agent
import (
"context"
"testing"
"git.gopher.ink/mirrors2/AutoZero/llm"
"git.gopher.ink/mirrors2/AutoZero/session"
)
type turnRecorder struct{ turns []int }
func (r *turnRecorder) BeginTurn(n int) { r.turns = append(r.turns, n) }
// TestRunSyntheticSkipsPromptAccounting:后台通知落盘时带 synthetic 标记,
// 不计入提问数、不推进 rewind 回合号;随后的真实提问仍从 1 开始。
func TestRunSyntheticSkipsPromptAccounting(t *testing.T) {
prov := &scriptedProvider{fn: func(int, string, []llm.Message, []llm.ToolDef) (llm.Message, error) {
return llm.Message{Role: llm.RoleAssistant, Content: "ok"}, nil
}}
a, sess := newTestAgent(t)
a.Provider = prov
rec := &turnRecorder{}
a.TurnMarker = rec
if err := a.RunSynthetic(context.Background(), "[background job finished] bg-1"); err != nil {
t.Fatal(err)
}
last := sess.Messages[len(sess.Messages)-1]
if last.Role != llm.RoleAssistant {
t.Fatalf("last message = %s", last.Role)
}
var notice *llm.Message
for i := range sess.Messages {
if sess.Messages[i].Role == llm.RoleUser {
notice = &sess.Messages[i]
}
}
if notice == nil || !notice.Synthetic {
t.Fatalf("notification not marked synthetic: %+v", notice)
}
if got := session.CountPrompts(sess.Messages); got != 0 {
t.Fatalf("CountPrompts = %d, want 0", got)
}
// 没有真实提问时的边界仍是 1;通知本身不推进号。
if len(rec.turns) != 1 || rec.turns[0] != 1 {
t.Fatalf("turn markers after synthetic = %v, want [1]", rec.turns)
}
if err := a.Run(context.Background(), "real task"); err != nil {
t.Fatal(err)
}
if got := session.CountPrompts(sess.Messages); got != 1 {
t.Fatalf("CountPrompts after real prompt = %d, want 1", got)
}
// 第一个真实提问仍拿到 1——后台通知没有把 rewind 的号顶走。
if len(rec.turns) != 2 || rec.turns[1] != 1 {
t.Fatalf("turn markers = %v, want [1 1]", rec.turns)
}
}