From 1fade56b17b0640e747a4dd1e8bf29cd54b2c68a Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 10:40:28 +0000 Subject: [PATCH] feat(agentic): add content generate command Co-Authored-By: Virgil --- pkg/agentic/commands.go | 45 ++++++++++++++++++++++++++++++++++++ pkg/agentic/commands_test.go | 29 +++++++++++++++++++++++ pkg/agentic/prep_test.go | 12 ++++++++++ 3 files changed, 86 insertions(+) diff --git a/pkg/agentic/commands.go b/pkg/agentic/commands.go index ef1e68f..4b1ddc5 100644 --- a/pkg/agentic/commands.go +++ b/pkg/agentic/commands.go @@ -20,6 +20,7 @@ func (s *PrepSubsystem) registerCommands(ctx context.Context) { c.Command("run/task", core.Command{Description: "Run a single task end-to-end", Action: s.cmdRunTask}) c.Command("run/orchestrator", core.Command{Description: "Run the queue orchestrator (standalone, no MCP)", Action: s.cmdOrchestrator}) c.Command("prep", core.Command{Description: "Prepare a workspace: clone repo, build prompt", Action: s.cmdPrep}) + c.Command("generate", core.Command{Description: "Generate content from a prompt using the platform content pipeline", Action: s.cmdGenerate}) c.Command("status", core.Command{Description: "List agent workspace statuses", Action: s.cmdStatus}) c.Command("prompt", core.Command{Description: "Build and display an agent prompt for a repo", Action: s.cmdPrompt}) c.Command("extract", core.Command{Description: "Extract a workspace template to a directory", Action: s.cmdExtract}) @@ -150,6 +151,50 @@ func (s *PrepSubsystem) cmdPrep(options core.Options) core.Result { return core.Result{OK: true} } +func (s *PrepSubsystem) cmdGenerate(options core.Options) core.Result { + prompt := optionStringValue(options, "prompt", "_arg") + if prompt == "" { + core.Print(nil, "usage: core-agent generate --prompt=\"Draft a release note\" [--provider=claude] [--config='{\"max_tokens\":4000}']") + return core.Result{Value: core.E("agentic.cmdGenerate", "prompt is required", nil), OK: false} + } + + result := s.handleContentGenerate(s.commandContext(), core.NewOptions( + core.Option{Key: "prompt", Value: prompt}, + core.Option{Key: "provider", Value: options.String("provider")}, + core.Option{Key: "config", Value: options.String("config")}, + )) + if !result.OK { + err := commandResultError("agentic.cmdGenerate", result) + core.Print(nil, "error: %v", err) + return core.Result{Value: err, OK: false} + } + + output, ok := result.Value.(ContentGenerateOutput) + if !ok { + err := core.E("agentic.cmdGenerate", "invalid content generate output", nil) + core.Print(nil, "error: %v", err) + return core.Result{Value: err, OK: false} + } + + if output.Result.Provider != "" { + core.Print(nil, "provider: %s", output.Result.Provider) + } + if output.Result.Model != "" { + core.Print(nil, "model: %s", output.Result.Model) + } + if output.Result.Status != "" { + core.Print(nil, "status: %s", output.Result.Status) + } + if output.Result.Content != "" { + core.Print(nil, "content: %s", output.Result.Content) + } + if output.Result.InputTokens > 0 || output.Result.OutputTokens > 0 { + core.Print(nil, "tokens: %d in / %d out", output.Result.InputTokens, output.Result.OutputTokens) + } + + return core.Result{OK: true} +} + func (s *PrepSubsystem) cmdStatus(_ core.Options) core.Result { workspaceRoot := WorkspaceRoot() filesystem := s.Core().Fs() diff --git a/pkg/agentic/commands_test.go b/pkg/agentic/commands_test.go index 9c7f160..962807f 100644 --- a/pkg/agentic/commands_test.go +++ b/pkg/agentic/commands_test.go @@ -690,6 +690,35 @@ func TestCommands_CmdPrompt_Good_DefaultTask(t *testing.T) { assert.True(t, r.OK) } +func TestCommands_CmdGenerate_Bad_MissingPrompt(t *testing.T) { + s, _ := testPrepWithCore(t, nil) + r := s.cmdGenerate(core.NewOptions()) + assert.False(t, r.OK) +} + +func TestCommands_CmdGenerate_Good(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, "/v1/content/generate", r.URL.Path) + assert.Equal(t, http.MethodPost, r.Method) + _, _ = w.Write([]byte(`{"data":{"id":"gen_1","provider":"claude","model":"claude-3.7-sonnet","content":"Release notes draft","input_tokens":12,"output_tokens":48,"status":"completed"}}`)) + })) + defer server.Close() + + s := testPrepWithPlatformServer(t, server, "secret-token") + output := captureStdout(t, func() { + r := s.cmdGenerate(core.NewOptions( + core.Option{Key: "_arg", Value: "Draft a release note"}, + core.Option{Key: "provider", Value: "claude"}, + )) + assert.True(t, r.OK) + }) + + assert.Contains(t, output, "provider: claude") + assert.Contains(t, output, "model: claude-3.7-sonnet") + assert.Contains(t, output, "status: completed") + assert.Contains(t, output, "content: Release notes draft") +} + func TestCommands_CmdExtract_Good(t *testing.T) { s, _ := testPrepWithCore(t, nil) target := core.JoinPath(t.TempDir(), "extract-test") diff --git a/pkg/agentic/prep_test.go b/pkg/agentic/prep_test.go index 30dd11d..a2937d3 100644 --- a/pkg/agentic/prep_test.go +++ b/pkg/agentic/prep_test.go @@ -570,6 +570,18 @@ func TestPrep_OnStartup_Good_RegistersPlatformCommandAlias(t *testing.T) { assert.Contains(t, c.Commands(), "fleet/events") } +func TestPrep_OnStartup_Good_RegistersGenerateCommand(t *testing.T) { + t.Setenv("CORE_WORKSPACE", t.TempDir()) + t.Setenv("CORE_AGENT_DISPATCH", "") + + c := core.New(core.WithOption("name", "test")) + s := NewPrep() + s.ServiceRuntime = core.NewServiceRuntime(c, AgentOptions{}) + + require.True(t, s.OnStartup(context.Background()).OK) + assert.Contains(t, c.Commands(), "generate") +} + func TestPrep_OnStartup_Bad(t *testing.T) { // OnStartup with nil ServiceRuntime — panics because // registerCommands calls s.Core().Command().