refactor(instruction): remove project instruction handling and related tests

This commit is contained in:
mlogclub
2026-04-18 10:54:36 +08:00
parent 19848d031b
commit 9a677a6265
12 changed files with 9 additions and 157 deletions
+2 -13
View File
@@ -20,12 +20,10 @@ type AssemblerInput struct {
GovernanceInstruction string
SkillInstruction string
ToolAppendices []string
ProjectInstruction string
}
type AssemblySummary struct {
SectionTitles []string
HasProjectRule bool
HasGovernanceRule bool
HasAgentRule bool
HasSkillRule bool
@@ -46,17 +44,8 @@ func (a *Assembler) Build(input AssemblerInput) string {
}
func (a *Assembler) Assemble(input AssemblerInput) AssemblyResult {
parts := make([]string, 0, 5)
summary := AssemblySummary{SectionTitles: make([]string, 0, 5)}
projectInstruction := strings.TrimSpace(input.ProjectInstruction)
if projectInstruction == "" {
projectInstruction = strings.TrimSpace(DefaultProjectInstruction)
}
if projectInstruction != "" {
parts = append(parts, buildInstructionSection("项目级规则", projectInstruction))
summary.HasProjectRule = true
summary.SectionTitles = append(summary.SectionTitles, "项目级规则")
}
parts := make([]string, 0, 4)
summary := AssemblySummary{SectionTitles: make([]string, 0, 4)}
governanceInstruction := strings.TrimSpace(input.GovernanceInstruction)
if governanceInstruction == "" && a != nil {
governanceInstruction = strings.TrimSpace(a.governanceInstruction)
@@ -7,15 +7,11 @@ import (
func TestAssemblerRespectsProvidedSources(t *testing.T) {
result := NewAssembler().Assemble(AssemblerInput{
ProjectInstruction: "project-rule",
GovernanceInstruction: "governance-rule",
AgentInstruction: "agent-rule",
SkillInstruction: "skill-rule",
ToolAppendices: []string{"tool-rule-1", "tool-rule-2"},
})
if !strings.Contains(result.Text, "项目级规则:\nproject-rule") {
t.Fatalf("missing project instruction: %s", result.Text)
}
if !strings.Contains(result.Text, "系统治理规则:\ngovernance-rule") {
t.Fatalf("missing governance instruction: %s", result.Text)
}
@@ -25,7 +21,7 @@ func TestAssemblerRespectsProvidedSources(t *testing.T) {
if !strings.Contains(result.Text, "工具补充规则:\ntool-rule-1") {
t.Fatalf("missing tool appendix: %s", result.Text)
}
if !result.Summary.HasProjectRule || !result.Summary.HasGovernanceRule || !result.Summary.HasAgentRule || !result.Summary.HasSkillRule || !result.Summary.HasToolRule {
if !result.Summary.HasGovernanceRule || !result.Summary.HasAgentRule || !result.Summary.HasSkillRule || !result.Summary.HasToolRule {
t.Fatalf("unexpected summary: %#v", result.Summary)
}
}
@@ -1,16 +0,0 @@
package instruction
// DefaultProjectInstruction 为当前项目统一注入的全局项目规则。
//
// 默认回退到内置常量;运行时优先由 ProjectInstructionProvider 读取仓库中的 AGENTS.md。
// TODO 这里是做什么的?为什么不直接读取AIAgent的?
const DefaultProjectInstruction = `# AGENTS.md
本文件定义本项目内 AI Agent 的强制开发规则。除非用户明确要求偏离,否则必须遵循。
## 1. 基本原则
- 适用范围:仓库根目录及所有子目录
- 优先级:用户明确指令 > 本文件 > 默认实现习惯
- 若与用户要求冲突:先执行用户要求,并在变更说明中标注偏离点
`
@@ -1,8 +1,6 @@
package instruction
import (
"os"
"path/filepath"
"strings"
runtimetooling "cs-agent/internal/ai/runtime/tooling"
@@ -10,56 +8,6 @@ import (
"cs-agent/internal/pkg/toolx"
)
type ProjectInstructionProvider struct {
fileName string
}
func NewProjectInstructionProvider() *ProjectInstructionProvider {
return &ProjectInstructionProvider{fileName: "AGENTS.md"}
}
func (p *ProjectInstructionProvider) Resolve() string {
if text := p.loadFromFile(); text != "" {
return text
}
return strings.TrimSpace(DefaultProjectInstruction)
}
func (p *ProjectInstructionProvider) loadFromFile() string {
path := p.resolvePath()
if path == "" {
return ""
}
data, err := os.ReadFile(path)
if err != nil {
return ""
}
return strings.TrimSpace(string(data))
}
func (p *ProjectInstructionProvider) resolvePath() string {
fileName := "AGENTS.md"
if p != nil && strings.TrimSpace(p.fileName) != "" {
fileName = strings.TrimSpace(p.fileName)
}
wd, err := os.Getwd()
if err != nil {
return ""
}
dir := wd
for {
candidate := filepath.Join(dir, fileName)
if stat, statErr := os.Stat(candidate); statErr == nil && !stat.IsDir() {
return candidate
}
parent := filepath.Dir(dir)
if parent == dir {
return ""
}
dir = parent
}
}
type ToolAppendixProvider struct{}
func NewToolAppendixProvider() *ToolAppendixProvider {
@@ -1,48 +0,0 @@
package instruction
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestProjectInstructionProviderResolveFromAgentsFile(t *testing.T) {
tmpDir := t.TempDir()
nestedDir := filepath.Join(tmpDir, "nested", "child")
if err := os.MkdirAll(nestedDir, 0o755); err != nil {
t.Fatalf("mkdir failed: %v", err)
}
content := "# AGENTS.md\n\nfrom temp file"
if err := os.WriteFile(filepath.Join(tmpDir, "AGENTS.md"), []byte(content), 0o644); err != nil {
t.Fatalf("write file failed: %v", err)
}
wd, err := os.Getwd()
if err != nil {
t.Fatalf("getwd failed: %v", err)
}
defer func() { _ = os.Chdir(wd) }()
if err := os.Chdir(nestedDir); err != nil {
t.Fatalf("chdir failed: %v", err)
}
got := NewProjectInstructionProvider().Resolve()
if !strings.Contains(got, "from temp file") {
t.Fatalf("expected provider to load AGENTS.md from file, got: %s", got)
}
}
func TestProjectInstructionProviderFallbacksToDefault(t *testing.T) {
tmpDir := t.TempDir()
wd, err := os.Getwd()
if err != nil {
t.Fatalf("getwd failed: %v", err)
}
defer func() { _ = os.Chdir(wd) }()
if err := os.Chdir(tmpDir); err != nil {
t.Fatalf("chdir failed: %v", err)
}
got := NewProjectInstructionProvider().Resolve()
if !strings.Contains(got, "本文件定义本项目内 AI Agent 的强制开发规则") {
t.Fatalf("expected fallback project instruction, got: %s", got)
}
}
@@ -9,7 +9,6 @@ import (
type Service struct {
assembler *Assembler
projectInstructionProvider *ProjectInstructionProvider
governanceInstructionProvider *GovernanceInstructionProvider
skillInstructionProvider *SkillInstructionProvider
toolAppendixProvider *ToolAppendixProvider
@@ -17,7 +16,6 @@ type Service struct {
func NewService(
assembler *Assembler,
projectProvider *ProjectInstructionProvider,
governanceProvider *GovernanceInstructionProvider,
skillProvider *SkillInstructionProvider,
toolProvider *ToolAppendixProvider,
@@ -25,9 +23,6 @@ func NewService(
if assembler == nil {
assembler = NewAssembler()
}
if projectProvider == nil {
projectProvider = NewProjectInstructionProvider()
}
if governanceProvider == nil {
governanceProvider = NewGovernanceInstructionProvider()
}
@@ -39,7 +34,6 @@ func NewService(
}
return &Service{
assembler: assembler,
projectInstructionProvider: projectProvider,
governanceInstructionProvider: governanceProvider,
skillInstructionProvider: skillProvider,
toolAppendixProvider: toolProvider,
@@ -52,13 +46,9 @@ func (s *Service) Build(
toolDefinitions []runtimetooling.MCPToolDefinition,
extraToolCodes map[string]string,
) AssemblyResult {
projectInstruction := ""
governanceInstruction := ""
skillInstruction := ""
toolAppendices := make([]string, 0)
if s != nil && s.projectInstructionProvider != nil {
projectInstruction = s.projectInstructionProvider.Resolve()
}
if s != nil && s.governanceInstructionProvider != nil {
governanceInstruction = s.governanceInstructionProvider.Resolve()
}
@@ -77,6 +67,5 @@ func (s *Service) Build(
GovernanceInstruction: governanceInstruction,
SkillInstruction: skillInstruction,
ToolAppendices: toolAppendices,
ProjectInstruction: projectInstruction,
})
}