mirror of
https://github.com/patriceckhart/zot.git
synced 2026-06-26 21:36:31 +02:00
Support AGENTS.md context files
This commit is contained in:
parent
25cb7d5003
commit
9f0629bcaf
2 changed files with 127 additions and 0 deletions
|
|
@ -278,6 +278,9 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
|
|||
summaries := toolSummaries(reg, args)
|
||||
|
||||
append_ := append([]string(nil), args.AppendSystemPrompt...)
|
||||
if agentsAddendum := readAgentsContext(args.CWD, ZotHome()); agentsAddendum != "" {
|
||||
append_ = append(append_, agentsAddendum)
|
||||
}
|
||||
if skillAddendum != "" {
|
||||
append_ = append(append_, skillAddendum)
|
||||
}
|
||||
|
|
@ -340,6 +343,83 @@ func readUserSystemPrompt(zotHome string) string {
|
|||
return strings.TrimSpace(string(raw))
|
||||
}
|
||||
|
||||
// readAgentsContext loads optional AGENTS.md instruction files. No
|
||||
// default file is created or required: zot only includes files that
|
||||
// already exist. Global instructions ($ZOT_HOME/AGENTS.md) come first,
|
||||
// followed by project instructions from the top-most parent down to cwd.
|
||||
func readAgentsContext(cwd, zotHome string) string {
|
||||
type contextFile struct {
|
||||
path string
|
||||
content string
|
||||
}
|
||||
var files []contextFile
|
||||
seen := map[string]bool{}
|
||||
add := func(path string) {
|
||||
if path == "" {
|
||||
return
|
||||
}
|
||||
abs, err := filepath.Abs(path)
|
||||
if err == nil {
|
||||
path = abs
|
||||
}
|
||||
if seen[path] {
|
||||
return
|
||||
}
|
||||
raw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content := strings.TrimSpace(string(raw))
|
||||
if content == "" {
|
||||
return
|
||||
}
|
||||
seen[path] = true
|
||||
files = append(files, contextFile{path: path, content: content})
|
||||
}
|
||||
addFirstFromDir := func(dir string) {
|
||||
if dir == "" {
|
||||
return
|
||||
}
|
||||
for _, name := range []string{"AGENTS.md", "AGENTS.MD"} {
|
||||
path := filepath.Join(dir, name)
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
add(path)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addFirstFromDir(zotHome)
|
||||
|
||||
if cwd != "" {
|
||||
abs, err := filepath.Abs(cwd)
|
||||
if err == nil {
|
||||
cwd = abs
|
||||
}
|
||||
var dirs []string
|
||||
for dir := filepath.Clean(cwd); ; dir = filepath.Dir(dir) {
|
||||
dirs = append(dirs, dir)
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
break
|
||||
}
|
||||
}
|
||||
for i := len(dirs) - 1; i >= 0; i-- {
|
||||
addFirstFromDir(dirs[i])
|
||||
}
|
||||
}
|
||||
|
||||
if len(files) == 0 {
|
||||
return ""
|
||||
}
|
||||
var sb strings.Builder
|
||||
sb.WriteString("Project context instructions loaded from AGENTS.md files. Follow them when working in this repository. Later files are more specific and may override earlier ones.\n")
|
||||
for _, f := range files {
|
||||
fmt.Fprintf(&sb, "\n## %s\n\n%s\n", f.path, f.content)
|
||||
}
|
||||
return strings.TrimSpace(sb.String())
|
||||
}
|
||||
|
||||
// descMapFromSummaries indexes the human-readable descriptions for
|
||||
// the renderToolsSection rebuild path.
|
||||
func descMapFromSummaries(summaries []ToolSummary) map[string]string {
|
||||
|
|
|
|||
47
internal/agent/build_test.go
Normal file
47
internal/agent/build_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadAgentsContextLoadsGlobalAndAncestors(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
zotHome := filepath.Join(root, "zot-home")
|
||||
project := filepath.Join(root, "repo")
|
||||
nested := filepath.Join(project, "packages", "app")
|
||||
if err := os.MkdirAll(zotHome, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(nested, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(zotHome, "AGENTS.md"), []byte("global rule"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(project, "AGENTS.md"), []byte("repo rule"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(nested, "AGENTS.md"), []byte("app rule"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := readAgentsContext(nested, zotHome)
|
||||
for _, want := range []string{"global rule", "repo rule", "app rule"} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Fatalf("readAgentsContext missing %q in:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
if strings.Index(got, "global rule") > strings.Index(got, "repo rule") || strings.Index(got, "repo rule") > strings.Index(got, "app rule") {
|
||||
t.Fatalf("AGENTS.md files loaded in wrong order:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadAgentsContextMissingFilesIsEmpty(t *testing.T) {
|
||||
got := readAgentsContext(t.TempDir(), t.TempDir())
|
||||
if got != "" {
|
||||
t.Fatalf("expected no context, got %q", got)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue