Files
Agent-System-Backend/internal/runtime/workspace_tools_test.go
T
weichen 77da63edac
ci / vet-and-test (pull_request) Successful in 41s
Open the kernel workspace tools and the markdown-source build pipeline
Why: User rulings 1 and 3. The direct conversation path exposed only
run_shell/run_python, so any file edit meant rewriting and re-running whole
generation scripts (diagnosis: 24 calls with 9 failures in one turn, 6KB
scripts regenerated 8 times). The kernel already ships line-numbered reads,
exact edit/multi_edit with read-before-write, grep and glob; they were wired
only into the squad path. Deliverables had no editable source: docx output
came from one-shot python scripts, so "make section 3 more detailed" rebuilt
everything.

Now: WorkspaceToolsCheckpointed (sandbox = conversation workspace, checkpoint
hooks wired) is registered into the direct run and its decls join the tool
surface (plan mode keeps the read-only subset). Word deliverables get a
markdown-source pipeline - python3 -m housestyle.build renders .md
deterministically via docx_kit and runs lint + outline on every build
(write-time diagnostics, exit 1 on error so the model fixes the source and
rebuilds). run_python kits remain for xlsx/pptx/images (ruling 3).
base-tools/base-deliverables prompts and the house-style SKILL document the
new loop.

Evidence: SELF - TestDirectRunExposesKernelWorkspaceTools (read->edit->grep
against the real sandbox FS), TestDirectRunWithoutSandboxHidesKernelTools,
three new BuildTests in recipes (renders+lint passes, heading-skip errors
exit 1, CLI entry); go vet + go test ./... pass; live before/after on the
golden task set recorded on the phase03 task card per the policy clause.

Impact: Direct conversations can now read and edit workspace files
surgically; docx deliverables become edit-source + rebuild instead of
regenerate. No contract or storage changes.
2026-10-09 18:01:06 +00:00

72 lines
2.2 KiB
Go
Raw 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 runtime
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
agentllm "agent-native/runtime/llm"
core "agent-system-core"
)
// 裁定 1:会话沙箱配置时,内核工作区工具(read/edit/multi_edit/grep/glob/list)
// 进入直连工具面;计划模式只留只读子集。
func TestDirectRunExposesKernelWorkspaceTools(t *testing.T) {
sandbox := t.TempDir()
if err := os.WriteFile(filepath.Join(sandbox, "note.txt"), []byte("alpha\nbeta\n"), 0o644); err != nil {
t.Fatal(err)
}
rc := &fakeRunCtx{
ctx: context.Background(), sandbox: sandbox,
prof: core.AgentProfile{Model: core.ModelRoute{Chat: "test-model"}},
}
// 第一步 read_file(行号分页),第二步 edit_file(须先读过),第三步 grep。
turns := padTurns(
textDeltaTurn("", toolCall("read_file", `{"path":"note.txt"}`)),
textDeltaTurn("", toolCall("edit_file", `{"path":"note.txt","old":"alpha","new":"gamma"}`)),
textDeltaTurn("", toolCall("grep", `{"pattern":"gamma"}`)),
textDeltaTurn("改完了。"),
)
r := &LLMRunner{Stream: scriptStream(turns, nil)}
if err := r.Execute(rc); err != nil {
t.Fatalf("Execute: %v", err)
}
raw, err := os.ReadFile(filepath.Join(sandbox, "note.txt"))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(raw), "gamma") || strings.Contains(string(raw), "alpha") {
t.Fatalf("edit_file did not apply: %q", string(raw))
}
found := 0
for _, p := range rc.assistant {
if p.ToolResult != nil && p.ToolResult.Summary != "" {
found++
}
}
if found < 3 {
t.Fatalf("workspace tool results missing from assistant parts: %+v", rc.assistant)
}
}
// 无沙箱(未配置工作区)时内核工具不注册,模型看不到。
func TestDirectRunWithoutSandboxHidesKernelTools(t *testing.T) {
rc := &fakeRunCtx{
ctx: context.Background(),
prof: core.AgentProfile{Model: core.ModelRoute{Chat: "test-model"}},
}
r := &LLMRunner{Stream: scriptStream(textTurns("你好。"), nil)}
if err := r.Execute(rc); err != nil {
t.Fatalf("Execute: %v", err)
}
for _, p := range rc.assistant {
if p.ToolCall != nil && p.ToolCall.Name == "read_file" {
t.Fatalf("read_file must not be visible without a sandbox")
}
}
}
var _ = agentllm.RoleUser