ci / vet-and-test (pull_request) Successful in 47s
Why: Q3 WP2 retires the SpawnSubagent-compression execution path: all WorkflowDef execution now goes through the wfcompile compiled graph, and squad steps run on the agent-native kernel backend instead of the agent-system step backend. Evidence: runtime-level P4 parity tests (workflow_compiled_test.go): registered branch lookup/errors, planned branch confirmation gate + dynamic 8-step cap fail-closed before any HITL, model script switch default-off, missing-slot HITL collection with compile-time rendering, judge stream routed to the configured lightweight model (nil = fail-closed verifier-unavailable). squadadapter TestOrchestrateRunsOnKernelStub: four-phase skeleton runs end-to-end on the kernel stub (write_file materialization, seeded skills, exec allowlist). server TestSquadOrchestration reworked: kernel steps run in-process (no subagent child runs). Full backend suite green; wfcompile/squadadapter/runmgr green with -race (pre-existing llm_test fake race on main recorded as debt, CI does not gate -race). Impact: DELETED runtime/workflow.go + workflow_script.go (legacy step loop, critic, script host) and their tests; squadadapter stepBackend 'agent-system' + profileForRole deleted; BuildBackends exported and registers only agent-native; Orchestrate DefaultBackend -> agent-native; builtin roles declare agent-native with write_file added to allowlists and writer run_shell -> run_command (kernel tool name); runmgr default workflow runner -> CompiledWorkflowRunner; mock #workflow demo runs compiled (host-only steps). Model script branch keeps the single script-level confirmation (no extra plan confirmation), matching legacy. Refs: Q3 plan WP2 (2026-10-07-agent-stack-q2q3-plans.md); task card .task/feature-agent-stack-q3.md
100 lines
3.2 KiB
Go
100 lines
3.2 KiB
Go
package squadadapter
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
osexec "os/exec"
|
|
"strings"
|
|
"testing"
|
|
|
|
nativetools "agent-native/runtime/tools"
|
|
|
|
agentllm "agent-native/runtime/llm"
|
|
nativeadp "agent-squad/adapters/native"
|
|
"agent-system-backend/internal/skills"
|
|
core "agent-system-core"
|
|
)
|
|
|
|
type orchFakeRc struct {
|
|
subagentFakeRc
|
|
dir string
|
|
}
|
|
|
|
func (f *orchFakeRc) AskHITL(card core.HITLCard) (core.HITLResponse, error) {
|
|
if len(card.Choices) > 0 {
|
|
return core.HITLResponse{ChoiceID: card.Choices[0].ID}, nil
|
|
}
|
|
return core.HITLResponse{ChoiceID: "approve"}, nil
|
|
}
|
|
|
|
// TestOrchestrateRunsOnKernelStub Q3 WP2 行为面:agent-system 退役后,
|
|
// Orchestrate 的四阶段骨架经 agent-native 内核(桩 Stream + write_file 落盘
|
|
// 交付物 + 种子技能 + Exec 白名单)跑通并产出交付物工件。
|
|
func TestOrchestrateRunsOnKernelStub(t *testing.T) {
|
|
skillsRoot := t.TempDir()
|
|
if _, serr := skills.Seed(skillsRoot); serr != nil {
|
|
t.Fatal(serr)
|
|
}
|
|
saved := AgentNativeOptions
|
|
AgentNativeOptions = func(Ctx) (nativeadp.Config, bool) {
|
|
py, _ := osexec.LookPath("python3")
|
|
return nativeadp.Config{DefaultModel: "stub", SkillsRoots: []string{skillsRoot},
|
|
Exec: &nativetools.ExecConfig{Bash: "/bin/bash", Python: py}, Stream: stubStream("# 交付\n\n这是内核桩后端产出的步骤交付物正文,长度超过五十个字符以满足最小质检要求。")}, true
|
|
}
|
|
defer func() { AgentNativeOptions = saved }()
|
|
rc := &orchFakeRc{dir: t.TempDir()}
|
|
dataDir := t.TempDir()
|
|
summary, err := Orchestrate(rc, dataDir, "生成一份示例目标简报")
|
|
t.Logf("summary = %q", summary)
|
|
if err != nil {
|
|
t.Fatalf("err = %v", err)
|
|
}
|
|
if !strings.Contains(summary, "completed") || !strings.Contains(summary, "完成 4") {
|
|
t.Fatalf("summary = %q", summary)
|
|
}
|
|
}
|
|
|
|
|
|
func stubStream(text string) agentllm.StreamFunc {
|
|
return func(_ context.Context, _ string, msgs []agentllm.Message, _ []agentllm.ToolDecl, _ agentllm.StreamOptions) <-chan agentllm.Event {
|
|
ch := make(chan agentllm.Event, 8)
|
|
go func() {
|
|
defer close(ch)
|
|
finish := func() {
|
|
ch <- agentllm.Event{Kind: agentllm.KindTextDelta, Text: text}
|
|
ch <- agentllm.Event{Kind: agentllm.KindMessageEnd, Message: agentllm.Message{Role: agentllm.RoleAssistant, Content: text}}
|
|
}
|
|
prompt := ""
|
|
for _, m := range msgs {
|
|
if m.Role == agentllm.RoleTool {
|
|
finish()
|
|
return
|
|
}
|
|
if m.Role == agentllm.RoleUser {
|
|
prompt = m.Content
|
|
}
|
|
}
|
|
i := strings.Index(prompt, "期望产出:[")
|
|
if i < 0 {
|
|
finish()
|
|
return
|
|
}
|
|
j := strings.Index(prompt[i:], "]")
|
|
if j < 0 {
|
|
finish()
|
|
return
|
|
}
|
|
targets := strings.Fields(prompt[i+len("期望产出:[") : i+j])
|
|
var calls []agentllm.ToolCall
|
|
for k, tgt := range targets {
|
|
args := fmt.Sprintf(`{"path":%q,"content":%q}`, tgt, text)
|
|
id := fmt.Sprintf("call_stub_%d", k+1)
|
|
ch <- agentllm.Event{Kind: agentllm.KindToolCallDelta, ToolIndex: k, ToolID: id, ToolName: "write_file", ArgumentsDelta: args}
|
|
calls = append(calls, agentllm.ToolCall{ID: id, Name: "write_file", Arguments: args})
|
|
}
|
|
ch <- agentllm.Event{Kind: agentllm.KindMessageEnd, Message: agentllm.Message{Role: agentllm.RoleAssistant, ToolCalls: calls, StopReason: agentllm.StopToolCalls}}
|
|
}()
|
|
return ch
|
|
}
|
|
}
|