From 452c4a27c78f5d912e86d651e2e3a510edad8dce Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 21:57:55 +0000 Subject: [PATCH] feat(agentic): expose prompt snapshot over MCP Co-Authored-By: Virgil --- pkg/agentic/prep.go | 2 ++ pkg/agentic/prep_test.go | 1 + pkg/agentic/prompt_version.go | 20 +++++++++++++++++ pkg/agentic/prompt_version_test.go | 36 ++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) diff --git a/pkg/agentic/prep.go b/pkg/agentic/prep.go index 5ee1aed..11ee344 100644 --- a/pkg/agentic/prep.go +++ b/pkg/agentic/prep.go @@ -92,6 +92,7 @@ func (s *PrepSubsystem) OnStartup(ctx context.Context) core.Result { case "agentic.status", "agentic.scan", "agentic.watch", "agentic.issue.get", "agentic.issue.list", "agentic.issue.assign", "agentic.pr.get", "agentic.pr.list", "agentic.prompt", "agentic.task", "agentic.flow", "agentic.persona", + "agentic.prompt.version", "agentic.sync.status", "agentic.fleet.nodes", "agentic.fleet.stats", "agentic.fleet.events", "agentic.credits.balance", "agentic.credits.history", "agentic.subscription.detect", "agentic.subscription.budget", @@ -385,6 +386,7 @@ func (s *PrepSubsystem) RegisterTools(server *mcp.Server) { s.registerStateTools(server) s.registerPhaseTools(server) s.registerTaskTools(server) + s.registerPromptTools(server) s.registerTemplateTools(server) s.registerIssueTools(server) s.registerMessageTools(server) diff --git a/pkg/agentic/prep_test.go b/pkg/agentic/prep_test.go index c0b5213..31ca135 100644 --- a/pkg/agentic/prep_test.go +++ b/pkg/agentic/prep_test.go @@ -654,6 +654,7 @@ func TestPrep_RegisterTools_Good_RegistersCompletionTool(t *testing.T) { } assert.Contains(t, toolNames, "agentic_complete") + assert.Contains(t, toolNames, "agentic_prompt_version") assert.Contains(t, toolNames, "session_complete") assert.Contains(t, toolNames, "agentic_message_send") assert.Contains(t, toolNames, "agentic_message_inbox") diff --git a/pkg/agentic/prompt_version.go b/pkg/agentic/prompt_version.go index 39b39b3..fcf7a5e 100644 --- a/pkg/agentic/prompt_version.go +++ b/pkg/agentic/prompt_version.go @@ -16,6 +16,11 @@ type PromptVersionOutput struct { Snapshot PromptVersionSnapshot `json:"snapshot"` } +// input := agentic.PromptVersionInput{Workspace: "/srv/.core/workspace/core/go-io/task-42"} +type PromptVersionInput struct { + Workspace string `json:"workspace"` +} + // result := c.Action("agentic.prompt.version").Run(ctx, core.NewOptions( // // core.Option{Key: "workspace", Value: "/srv/.core/workspace/core/go-io/task-42"}, @@ -47,3 +52,18 @@ func (s *PrepSubsystem) promptVersion(_ context.Context, _ *mcp.CallToolRequest, Snapshot: snapshot, }, nil } + +func (s *PrepSubsystem) registerPromptTools(server *mcp.Server) { + mcp.AddTool(server, &mcp.Tool{ + Name: "agentic_prompt_version", + Description: "Read the current prompt snapshot for a workspace.", + }, s.promptVersionTool) +} + +func (s *PrepSubsystem) promptVersionTool(ctx context.Context, _ *mcp.CallToolRequest, input PromptVersionInput) (*mcp.CallToolResult, PromptVersionOutput, error) { + if core.Trim(input.Workspace) == "" { + return nil, PromptVersionOutput{}, core.E("promptVersion", "workspace is required", nil) + } + + return s.promptVersion(ctx, nil, input.Workspace) +} diff --git a/pkg/agentic/prompt_version_test.go b/pkg/agentic/prompt_version_test.go index 5dad545..10c9161 100644 --- a/pkg/agentic/prompt_version_test.go +++ b/pkg/agentic/prompt_version_test.go @@ -3,6 +3,7 @@ package agentic import ( + "context" "testing" core "dappco.re/go/core" @@ -41,3 +42,38 @@ func TestPromptVersion_ReadPromptSnapshot_Ugly_InvalidJson(t *testing.T) { require.Error(t, err) assert.Contains(t, err.Error(), "failed to parse prompt snapshot") } + +func TestPromptVersion_PromptVersionTool_Good(t *testing.T) { + workspaceDir := t.TempDir() + prompt := "TASK: Fix tests\n\nRead CODEX.md and commit when done." + + require.True(t, writePromptSnapshot(workspaceDir, prompt).OK) + + _, output, err := (&PrepSubsystem{}).promptVersionTool(context.Background(), nil, PromptVersionInput{ + Workspace: workspaceDir, + }) + require.NoError(t, err) + + assert.True(t, output.Success) + assert.Equal(t, workspaceDir, output.Workspace) + assert.Equal(t, promptSnapshotHash(prompt), output.Snapshot.Hash) +} + +func TestPromptVersion_PromptVersionTool_Bad_MissingWorkspace(t *testing.T) { + _, _, err := (&PrepSubsystem{}).promptVersionTool(context.Background(), nil, PromptVersionInput{}) + require.Error(t, err) + assert.Contains(t, err.Error(), "workspace is required") +} + +func TestPromptVersion_PromptVersionTool_Ugly_InvalidJson(t *testing.T) { + workspaceDir := t.TempDir() + metaDir := WorkspaceMetaDir(workspaceDir) + require.True(t, fs.EnsureDir(metaDir).OK) + require.True(t, fs.Write(core.JoinPath(metaDir, "prompt-version.json"), "{not-json").OK) + + _, _, err := (&PrepSubsystem{}).promptVersionTool(context.Background(), nil, PromptVersionInput{ + Workspace: workspaceDir, + }) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse prompt snapshot") +}