refactor(instruction): remove project instruction handling and related tests
This commit is contained in:
@@ -20,12 +20,10 @@ type AssemblerInput struct {
|
|||||||
GovernanceInstruction string
|
GovernanceInstruction string
|
||||||
SkillInstruction string
|
SkillInstruction string
|
||||||
ToolAppendices []string
|
ToolAppendices []string
|
||||||
ProjectInstruction string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type AssemblySummary struct {
|
type AssemblySummary struct {
|
||||||
SectionTitles []string
|
SectionTitles []string
|
||||||
HasProjectRule bool
|
|
||||||
HasGovernanceRule bool
|
HasGovernanceRule bool
|
||||||
HasAgentRule bool
|
HasAgentRule bool
|
||||||
HasSkillRule bool
|
HasSkillRule bool
|
||||||
@@ -46,17 +44,8 @@ func (a *Assembler) Build(input AssemblerInput) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Assembler) Assemble(input AssemblerInput) AssemblyResult {
|
func (a *Assembler) Assemble(input AssemblerInput) AssemblyResult {
|
||||||
parts := make([]string, 0, 5)
|
parts := make([]string, 0, 4)
|
||||||
summary := AssemblySummary{SectionTitles: make([]string, 0, 5)}
|
summary := AssemblySummary{SectionTitles: make([]string, 0, 4)}
|
||||||
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, "项目级规则")
|
|
||||||
}
|
|
||||||
governanceInstruction := strings.TrimSpace(input.GovernanceInstruction)
|
governanceInstruction := strings.TrimSpace(input.GovernanceInstruction)
|
||||||
if governanceInstruction == "" && a != nil {
|
if governanceInstruction == "" && a != nil {
|
||||||
governanceInstruction = strings.TrimSpace(a.governanceInstruction)
|
governanceInstruction = strings.TrimSpace(a.governanceInstruction)
|
||||||
|
|||||||
@@ -7,15 +7,11 @@ import (
|
|||||||
|
|
||||||
func TestAssemblerRespectsProvidedSources(t *testing.T) {
|
func TestAssemblerRespectsProvidedSources(t *testing.T) {
|
||||||
result := NewAssembler().Assemble(AssemblerInput{
|
result := NewAssembler().Assemble(AssemblerInput{
|
||||||
ProjectInstruction: "project-rule",
|
|
||||||
GovernanceInstruction: "governance-rule",
|
GovernanceInstruction: "governance-rule",
|
||||||
AgentInstruction: "agent-rule",
|
AgentInstruction: "agent-rule",
|
||||||
SkillInstruction: "skill-rule",
|
SkillInstruction: "skill-rule",
|
||||||
ToolAppendices: []string{"tool-rule-1", "tool-rule-2"},
|
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") {
|
if !strings.Contains(result.Text, "系统治理规则:\ngovernance-rule") {
|
||||||
t.Fatalf("missing governance instruction: %s", result.Text)
|
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") {
|
if !strings.Contains(result.Text, "工具补充规则:\ntool-rule-1") {
|
||||||
t.Fatalf("missing tool appendix: %s", result.Text)
|
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)
|
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
|
package instruction
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
runtimetooling "cs-agent/internal/ai/runtime/tooling"
|
runtimetooling "cs-agent/internal/ai/runtime/tooling"
|
||||||
@@ -10,56 +8,6 @@ import (
|
|||||||
"cs-agent/internal/pkg/toolx"
|
"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{}
|
type ToolAppendixProvider struct{}
|
||||||
|
|
||||||
func NewToolAppendixProvider() *ToolAppendixProvider {
|
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 {
|
type Service struct {
|
||||||
assembler *Assembler
|
assembler *Assembler
|
||||||
projectInstructionProvider *ProjectInstructionProvider
|
|
||||||
governanceInstructionProvider *GovernanceInstructionProvider
|
governanceInstructionProvider *GovernanceInstructionProvider
|
||||||
skillInstructionProvider *SkillInstructionProvider
|
skillInstructionProvider *SkillInstructionProvider
|
||||||
toolAppendixProvider *ToolAppendixProvider
|
toolAppendixProvider *ToolAppendixProvider
|
||||||
@@ -17,7 +16,6 @@ type Service struct {
|
|||||||
|
|
||||||
func NewService(
|
func NewService(
|
||||||
assembler *Assembler,
|
assembler *Assembler,
|
||||||
projectProvider *ProjectInstructionProvider,
|
|
||||||
governanceProvider *GovernanceInstructionProvider,
|
governanceProvider *GovernanceInstructionProvider,
|
||||||
skillProvider *SkillInstructionProvider,
|
skillProvider *SkillInstructionProvider,
|
||||||
toolProvider *ToolAppendixProvider,
|
toolProvider *ToolAppendixProvider,
|
||||||
@@ -25,9 +23,6 @@ func NewService(
|
|||||||
if assembler == nil {
|
if assembler == nil {
|
||||||
assembler = NewAssembler()
|
assembler = NewAssembler()
|
||||||
}
|
}
|
||||||
if projectProvider == nil {
|
|
||||||
projectProvider = NewProjectInstructionProvider()
|
|
||||||
}
|
|
||||||
if governanceProvider == nil {
|
if governanceProvider == nil {
|
||||||
governanceProvider = NewGovernanceInstructionProvider()
|
governanceProvider = NewGovernanceInstructionProvider()
|
||||||
}
|
}
|
||||||
@@ -39,7 +34,6 @@ func NewService(
|
|||||||
}
|
}
|
||||||
return &Service{
|
return &Service{
|
||||||
assembler: assembler,
|
assembler: assembler,
|
||||||
projectInstructionProvider: projectProvider,
|
|
||||||
governanceInstructionProvider: governanceProvider,
|
governanceInstructionProvider: governanceProvider,
|
||||||
skillInstructionProvider: skillProvider,
|
skillInstructionProvider: skillProvider,
|
||||||
toolAppendixProvider: toolProvider,
|
toolAppendixProvider: toolProvider,
|
||||||
@@ -52,13 +46,9 @@ func (s *Service) Build(
|
|||||||
toolDefinitions []runtimetooling.MCPToolDefinition,
|
toolDefinitions []runtimetooling.MCPToolDefinition,
|
||||||
extraToolCodes map[string]string,
|
extraToolCodes map[string]string,
|
||||||
) AssemblyResult {
|
) AssemblyResult {
|
||||||
projectInstruction := ""
|
|
||||||
governanceInstruction := ""
|
governanceInstruction := ""
|
||||||
skillInstruction := ""
|
skillInstruction := ""
|
||||||
toolAppendices := make([]string, 0)
|
toolAppendices := make([]string, 0)
|
||||||
if s != nil && s.projectInstructionProvider != nil {
|
|
||||||
projectInstruction = s.projectInstructionProvider.Resolve()
|
|
||||||
}
|
|
||||||
if s != nil && s.governanceInstructionProvider != nil {
|
if s != nil && s.governanceInstructionProvider != nil {
|
||||||
governanceInstruction = s.governanceInstructionProvider.Resolve()
|
governanceInstruction = s.governanceInstructionProvider.Resolve()
|
||||||
}
|
}
|
||||||
@@ -77,6 +67,5 @@ func (s *Service) Build(
|
|||||||
GovernanceInstruction: governanceInstruction,
|
GovernanceInstruction: governanceInstruction,
|
||||||
SkillInstruction: skillInstruction,
|
SkillInstruction: skillInstruction,
|
||||||
ToolAppendices: toolAppendices,
|
ToolAppendices: toolAppendices,
|
||||||
ProjectInstruction: projectInstruction,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ func (c *RuntimeTraceCollector) SetInstructionSummary(summary InstructionTraceSu
|
|||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
c.Data.Instruction.SectionTitles = append([]string(nil), summary.SectionTitles...)
|
c.Data.Instruction.SectionTitles = append([]string(nil), summary.SectionTitles...)
|
||||||
c.Data.Instruction.HasProjectRule = summary.HasProjectRule
|
|
||||||
c.Data.Instruction.HasGovernanceRule = summary.HasGovernanceRule
|
c.Data.Instruction.HasGovernanceRule = summary.HasGovernanceRule
|
||||||
c.Data.Instruction.HasAgentRule = summary.HasAgentRule
|
c.Data.Instruction.HasAgentRule = summary.HasAgentRule
|
||||||
c.Data.Instruction.HasSkillRule = summary.HasSkillRule
|
c.Data.Instruction.HasSkillRule = summary.HasSkillRule
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ type RetrieverPolicyTraceItem struct {
|
|||||||
|
|
||||||
type InstructionTraceSummary struct {
|
type InstructionTraceSummary struct {
|
||||||
SectionTitles []string
|
SectionTitles []string
|
||||||
HasProjectRule bool
|
|
||||||
HasGovernanceRule bool
|
HasGovernanceRule bool
|
||||||
HasAgentRule bool
|
HasAgentRule bool
|
||||||
HasSkillRule bool
|
HasSkillRule bool
|
||||||
@@ -93,7 +92,6 @@ type RuntimeTraceData struct {
|
|||||||
} `json:"model"`
|
} `json:"model"`
|
||||||
Instruction struct {
|
Instruction struct {
|
||||||
SectionTitles []string `json:"sectionTitles,omitempty"`
|
SectionTitles []string `json:"sectionTitles,omitempty"`
|
||||||
HasProjectRule bool `json:"hasProjectRule,omitempty"`
|
|
||||||
HasGovernanceRule bool `json:"hasGovernanceRule,omitempty"`
|
HasGovernanceRule bool `json:"hasGovernanceRule,omitempty"`
|
||||||
HasAgentRule bool `json:"hasAgentRule,omitempty"`
|
HasAgentRule bool `json:"hasAgentRule,omitempty"`
|
||||||
HasSkillRule bool `json:"hasSkillRule,omitempty"`
|
HasSkillRule bool `json:"hasSkillRule,omitempty"`
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func NewAgentFactory() *AgentFactory {
|
|||||||
return &AgentFactory{
|
return &AgentFactory{
|
||||||
chatModelFactory: NewChatModelFactory(),
|
chatModelFactory: NewChatModelFactory(),
|
||||||
toolFactory: NewToolFactory(),
|
toolFactory: NewToolFactory(),
|
||||||
instructionService: runtimeinstruction.NewService(nil, nil, nil, nil, nil),
|
instructionService: runtimeinstruction.NewService(nil, nil, nil, nil),
|
||||||
handlerService: NewAgentHandlerService(nil),
|
handlerService: NewAgentHandlerService(nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ func TestAgentHandlerServiceBuildWithCollectorOnly(t *testing.T) {
|
|||||||
handlers, err := service.Build(context.Background(), BuildAgentHandlersInput{
|
handlers, err := service.Build(context.Background(), BuildAgentHandlersInput{
|
||||||
Collector: collector,
|
Collector: collector,
|
||||||
InstructionSummary: einocallbacks.InstructionTraceSummary{
|
InstructionSummary: einocallbacks.InstructionTraceSummary{
|
||||||
SectionTitles: []string{"项目级规则", "系统治理规则"},
|
SectionTitles: []string{"系统治理规则"},
|
||||||
HasProjectRule: true,
|
|
||||||
HasGovernanceRule: true,
|
HasGovernanceRule: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -25,10 +24,10 @@ func TestAgentHandlerServiceBuildWithCollectorOnly(t *testing.T) {
|
|||||||
if len(handlers) != 1 {
|
if len(handlers) != 1 {
|
||||||
t.Fatalf("expected 1 handler, got %d", len(handlers))
|
t.Fatalf("expected 1 handler, got %d", len(handlers))
|
||||||
}
|
}
|
||||||
if !collector.Data.Instruction.HasProjectRule || !collector.Data.Instruction.HasGovernanceRule {
|
if !collector.Data.Instruction.HasGovernanceRule {
|
||||||
t.Fatalf("instruction summary was not written to collector: %#v", collector.Data.Instruction)
|
t.Fatalf("instruction summary was not written to collector: %#v", collector.Data.Instruction)
|
||||||
}
|
}
|
||||||
if len(collector.Data.Instruction.SectionTitles) != 2 {
|
if len(collector.Data.Instruction.SectionTitles) != 1 {
|
||||||
t.Fatalf("unexpected section titles: %#v", collector.Data.Instruction.SectionTitles)
|
t.Fatalf("unexpected section titles: %#v", collector.Data.Instruction.SectionTitles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
func buildInstructionTraceSummary(summary runtimeinstruction.AssemblySummary) einocallbacks.InstructionTraceSummary {
|
func buildInstructionTraceSummary(summary runtimeinstruction.AssemblySummary) einocallbacks.InstructionTraceSummary {
|
||||||
return einocallbacks.InstructionTraceSummary{
|
return einocallbacks.InstructionTraceSummary{
|
||||||
SectionTitles: append([]string(nil), summary.SectionTitles...),
|
SectionTitles: append([]string(nil), summary.SectionTitles...),
|
||||||
HasProjectRule: summary.HasProjectRule,
|
|
||||||
HasGovernanceRule: summary.HasGovernanceRule,
|
HasGovernanceRule: summary.HasGovernanceRule,
|
||||||
HasAgentRule: summary.HasAgentRule,
|
HasAgentRule: summary.HasAgentRule,
|
||||||
HasSkillRule: summary.HasSkillRule,
|
HasSkillRule: summary.HasSkillRule,
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestBuildInstructionTraceSummary(t *testing.T) {
|
func TestBuildInstructionTraceSummary(t *testing.T) {
|
||||||
got := buildInstructionTraceSummary(runtimeinstruction.AssemblySummary{
|
got := buildInstructionTraceSummary(runtimeinstruction.AssemblySummary{
|
||||||
SectionTitles: []string{"项目级规则", "当前技能上下文"},
|
SectionTitles: []string{"系统治理规则", "当前技能上下文"},
|
||||||
HasProjectRule: true,
|
|
||||||
HasGovernanceRule: true,
|
HasGovernanceRule: true,
|
||||||
HasAgentRule: true,
|
HasAgentRule: true,
|
||||||
HasSkillRule: true,
|
HasSkillRule: true,
|
||||||
@@ -19,7 +18,7 @@ func TestBuildInstructionTraceSummary(t *testing.T) {
|
|||||||
if len(got.SectionTitles) != 2 {
|
if len(got.SectionTitles) != 2 {
|
||||||
t.Fatalf("unexpected section titles: %#v", got.SectionTitles)
|
t.Fatalf("unexpected section titles: %#v", got.SectionTitles)
|
||||||
}
|
}
|
||||||
if !got.HasProjectRule || !got.HasGovernanceRule || !got.HasAgentRule || !got.HasSkillRule {
|
if !got.HasGovernanceRule || !got.HasAgentRule || !got.HasSkillRule {
|
||||||
t.Fatalf("unexpected summary flags: %#v", got)
|
t.Fatalf("unexpected summary flags: %#v", got)
|
||||||
}
|
}
|
||||||
if got.HasToolRule {
|
if got.HasToolRule {
|
||||||
|
|||||||
Reference in New Issue
Block a user