From dc7c89fdae3b768321f54b3389b6d181b47692b0 Mon Sep 17 00:00:00 2001 From: Snider Date: Wed, 18 Mar 2026 14:09:17 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20remove=20pkg/prompts=20=E2=80=94=20?= =?UTF-8?q?consolidated=20into=20pkg/lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Virgil --- pkg/agentic/prep.go | 13 ++-- pkg/lib/lib.go | 8 ++ pkg/prompts/prompts.go | 19 ----- pkg/prompts/prompts_test.go | 141 ------------------------------------ 4 files changed, 14 insertions(+), 167 deletions(-) delete mode 100644 pkg/prompts/prompts.go delete mode 100644 pkg/prompts/prompts_test.go diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index 0b8b0d6..48695ad 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -18,7 +18,6 @@ import ( "time" "forge.lthn.ai/core/agent/pkg/lib" - "forge.lthn.ai/core/agent/pkg/prompts" coreio "forge.lthn.ai/core/go-io" coreerr "forge.lthn.ai/core/go-log" "github.com/modelcontextprotocol/go-sdk/mcp" @@ -209,12 +208,12 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques wsTmpl = "review" } - promptContent, _ := prompts.Prompt(input.Template) + promptContent, _ := lib.Prompt(input.Template) personaContent := "" if input.Persona != "" { - personaContent, _ = prompts.Persona(input.Persona) + personaContent, _ = lib.Persona(input.Persona) } - flowContent, _ := prompts.Flow(detectLanguage(repoPath)) + flowContent, _ := lib.Flow(detectLanguage(repoPath)) wsData := &lib.WorkspaceData{ Repo: input.Repo, @@ -278,10 +277,10 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques // --- Prompt templates --- func (s *PrepSubsystem) writePromptTemplate(template, wsDir string) { - prompt, err := prompts.Template(template) + prompt, err := lib.Template(template) if err != nil { // Fallback to default template - prompt, _ = prompts.Template("default") + prompt, _ = lib.Template("default") if prompt == "" { prompt = "Read TODO.md and complete the task. Work in src/.\n" } @@ -296,7 +295,7 @@ func (s *PrepSubsystem) writePromptTemplate(template, wsDir string) { // and writes PLAN.md into the workspace src/ directory. func (s *PrepSubsystem) writePlanFromTemplate(templateSlug string, variables map[string]string, task string, wsDir string) { // Load template from embedded prompts package - data, err := prompts.Template(templateSlug) + data, err := lib.Template(templateSlug) if err != nil { return // Template not found, skip silently } diff --git a/pkg/lib/lib.go b/pkg/lib/lib.go index 387d1a2..dc12398 100644 --- a/pkg/lib/lib.go +++ b/pkg/lib/lib.go @@ -48,6 +48,14 @@ var workspaceFS embed.FS // --- Prompts --- +// Template tries Prompt then Task (backwards compat). +func Template(slug string) (string, error) { + if content, err := Prompt(slug); err == nil { + return content, nil + } + return Task(slug) +} + func Prompt(slug string) (string, error) { data, err := promptFS.ReadFile("prompt/" + slug + ".md") if err != nil { diff --git a/pkg/prompts/prompts.go b/pkg/prompts/prompts.go deleted file mode 100644 index ff77e44..0000000 --- a/pkg/prompts/prompts.go +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: EUPL-1.2 - -// Package prompts re-exports the lib package for backwards compatibility. -// New code should import pkg/lib directly. -package prompts - -import "forge.lthn.ai/core/agent/pkg/lib" - -func Prompt(slug string) (string, error) { return lib.Prompt(slug) } -func Task(slug string) (string, error) { return lib.Task(slug) } -func TaskBundle(slug string) (string, map[string]string, error) { return lib.TaskBundle(slug) } -func Flow(slug string) (string, error) { return lib.Flow(slug) } -func Persona(path string) (string, error) { return lib.Persona(path) } -func Template(slug string) (string, error) { return lib.Prompt(slug) } -func ListPrompts() []string { return lib.ListPrompts() } -func ListTasks() []string { return lib.ListTasks() } -func ListFlows() []string { return lib.ListFlows() } -func ListPersonas() []string { return lib.ListPersonas() } -func ListTemplates() []string { return append(lib.ListPrompts(), lib.ListTasks()...) } diff --git a/pkg/prompts/prompts_test.go b/pkg/prompts/prompts_test.go deleted file mode 100644 index cecbf4f..0000000 --- a/pkg/prompts/prompts_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// SPDX-License-Identifier: EUPL-1.2 - -package prompts - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestPrompt_Good(t *testing.T) { - content, err := Prompt("coding") - require.NoError(t, err) - assert.Contains(t, content, "SANDBOX") - assert.Contains(t, content, "Closeout Sequence") -} - -func TestPrompt_Bad_NotFound(t *testing.T) { - _, err := Prompt("nonexistent") - assert.Error(t, err) -} - -func TestTask_Good(t *testing.T) { - content, err := Task("bug-fix") - require.NoError(t, err) - assert.Contains(t, content, "name:") -} - -func TestTask_Good_Nested(t *testing.T) { - content, err := Task("code/review") - require.NoError(t, err) - assert.Contains(t, content, "Code Review") -} - -func TestTaskBundle_Good(t *testing.T) { - main, bundle, err := TaskBundle("code/review") - require.NoError(t, err) - assert.Contains(t, main, "Code Review") - assert.NotNil(t, bundle) - assert.Contains(t, bundle, "conventions.md") - assert.Contains(t, bundle, "severity.md") - assert.Contains(t, bundle["conventions.md"], "coreerr.E") -} - -func TestTaskBundle_Good_NoBundleDir(t *testing.T) { - main, bundle, err := TaskBundle("bug-fix") - require.NoError(t, err) - assert.Contains(t, main, "name:") - assert.Nil(t, bundle) -} - -func TestTask_Bad_NotFound(t *testing.T) { - _, err := Task("nonexistent") - assert.Error(t, err) -} - -func TestTemplate_Good_BackwardsCompat(t *testing.T) { - content, err := Template("coding") - require.NoError(t, err) - assert.Contains(t, content, "SANDBOX") - - content, err = Template("bug-fix") - require.NoError(t, err) - assert.Contains(t, content, "name:") -} - -func TestFlow_Good(t *testing.T) { - content, err := Flow("go") - require.NoError(t, err) - assert.Contains(t, content, "go build") -} - -func TestFlow_Good_Docker(t *testing.T) { - content, err := Flow("docker") - require.NoError(t, err) - assert.Contains(t, content, "docker build") -} - -func TestPersona_Good(t *testing.T) { - content, err := Persona("secops/developer") - require.NoError(t, err) - assert.Contains(t, content, "name:") -} - -func TestPersona_Good_SMM(t *testing.T) { - content, err := Persona("smm/security-developer") - require.NoError(t, err) - assert.Contains(t, content, "OAuth") -} - -func TestPersona_Bad_NotFound(t *testing.T) { - _, err := Persona("nonexistent/persona") - assert.Error(t, err) -} - -func TestListPrompts_Good(t *testing.T) { - list := ListPrompts() - assert.Contains(t, list, "coding") - assert.Contains(t, list, "verify") - assert.True(t, len(list) >= 5) -} - -func TestListTasks_Good(t *testing.T) { - list := ListTasks() - assert.Contains(t, list, "bug-fix") - // Nested tasks - hasCodeReview := false - for _, t := range list { - if t == "code/review" { - hasCodeReview = true - } - } - assert.True(t, hasCodeReview, "code/review not found in tasks") -} - -func TestListFlows_Good(t *testing.T) { - list := ListFlows() - assert.Contains(t, list, "go") - assert.Contains(t, list, "php") - assert.Contains(t, list, "docker") - assert.True(t, len(list) >= 9) -} - -func TestListPersonas_Good(t *testing.T) { - personas := ListPersonas() - assert.True(t, len(personas) >= 90) -} - -func TestListPersonas_Good_NoPrefixDuplication(t *testing.T) { - for _, p := range ListPersonas() { - parts := strings.Split(p, "/") - if len(parts) == 2 { - domain := parts[0] - file := parts[1] - assert.False(t, strings.HasPrefix(file, domain+"-"), - "persona %q has redundant domain prefix in filename", p) - } - } -}