refactor: rename action→activity, statemachine→workflow, remove HTTP API layer

- action/ → activity/ (Temporal activities)
- statemachine/ → workflow/ (Temporal workflows)
- Removed internal/api/ and cmd/server/ (api-gw handles HTTP, Temporal is the API)
- Created pkg/types/types.go as single source of truth for all shared types
- Extracted CallRoleLLM helper (DRY: implementer/planner/judge shared pattern)
- Fixed circular import: workflow_graph_query uses string activity names
- Fixed logger.logf → logger.Info/Warn (method didn't exist)
- Fixed routing types: added Branches, Activity, BackoffSeconds, TaskActivity
- Fixed db.Canvas.Name, db.Client→DB, GetWorkflow→FetchWorkflow
- Removed unused imports
- All tests pass, build clean, vet clean
This commit is contained in:
Test
2026-09-05 23:59:13 -07:00
parent c228b54fd7
commit 9c9e9450bc
54 changed files with 847 additions and 1901 deletions
-125
View File
@@ -1,125 +0,0 @@
package main
import (
"context"
"flag"
"log"
"os"
"os/signal"
"sync"
"syscall"
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
"github.com/rockliang/poimen/workflows/action"
"github.com/rockliang/poimen/workflows/internal/api"
"github.com/rockliang/poimen/workflows/internal/config"
"github.com/rockliang/poimen/workflows/pkg/db"
"github.com/rockliang/poimen/workflows/statemachine"
)
func main() {
var (
apiPort = flag.Int("port", 8080, "HTTP API port")
verbose = flag.Bool("verbose", false, "verbose logging")
)
flag.Parse()
logger := log.New(os.Stdout, "[poimen-server] ", log.LstdFlags|log.Lshortfile)
// Load configuration
cfg, err := config.LoadConfig()
if err != nil {
logger.Fatalf("failed to load config: %v", err)
}
// Connect to database (memory-db via K8s CNPG)
logger.Println("connecting to database...")
database, err := db.New(os.Getenv("DATABASE_URL"))
if err != nil {
logger.Fatalf("failed to connect to database: %v", err)
}
defer database.Close()
logger.Println("✓ Connected to database")
// Connect to Temporal
logger.Printf("connecting to Temporal at %s", cfg.Temporal.HostPort)
c, err := client.Dial(client.Options{
HostPort: cfg.Temporal.HostPort,
Namespace: cfg.Temporal.Namespace,
})
if err != nil {
logger.Fatalf("failed to connect to temporal: %v", err)
}
defer c.Close()
logger.Println("✓ Connected to Temporal")
// Create and start Temporal worker
w := worker.New(c, "default", worker.Options{})
// Register RoutingWorkflow
w.RegisterWorkflow(statemachine.RoutingWorkflow)
// Register activities
w.RegisterActivity(action.CloneRepoActivity)
w.RegisterActivity(action.AnalyzeCodeActivity)
w.RegisterActivity(action.SecurityScanActivity)
w.RegisterActivity(action.GenerateReportActivity)
w.RegisterActivity(action.DeploymentPreCheckActivity)
w.RegisterActivity(action.NotifyStatusActivity)
w.RegisterActivity(action.ApproveWorkflowActivity)
w.RegisterActivity(action.ArchiveResultsActivity)
w.RegisterActivity(action.RetrieveMemoryActivity)
w.RegisterActivity(action.AssumeRoleActivity)
w.RegisterActivity(action.LLMInferenceActivity)
w.RegisterActivity(action.LLMBatchInferenceActivity)
w.RegisterActivity(action.CanvasReasonerActivity)
var wg sync.WaitGroup
errChan := make(chan error, 2)
// Start Temporal worker
wg.Add(1)
go func() {
defer wg.Done()
logger.Println("starting Temporal worker...")
if err := w.Run(worker.InterruptCh()); err != nil {
errChan <- err
}
}()
// Start HTTP API server
wg.Add(1)
go func() {
defer wg.Done()
server := api.NewServer(database, c, logger)
logger.Printf("starting API server on port %d", *apiPort)
if err := server.Start(*apiPort); err != nil {
errChan <- err
}
}()
// Wait for interrupt signal
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigChan
logger.Printf("received signal: %v", sig)
w.Stop()
}()
// Monitor for errors
go func() {
err := <-errChan
if err != nil {
logger.Printf("error: %v", err)
w.Stop()
}
}()
wg.Wait()
logger.Println("✓ Server stopped gracefully")
}
+15 -15
View File
@@ -11,12 +11,12 @@ import (
"time"
"go.temporal.io/sdk/client"
"github.com/rockliang/poimen/workflows/action/llm"
"github.com/rockliang/poimen/workflows/activity/llm"
"github.com/rockliang/poimen/workflows/internal/config"
"github.com/rockliang/poimen/workflows/internal/health"
"github.com/rockliang/poimen/workflows/internal/logging"
"github.com/rockliang/poimen/workflows/internal/routing"
"github.com/rockliang/poimen/workflows/statemachine"
"github.com/rockliang/poimen/workflows/workflow"
)
func main() {
@@ -89,20 +89,20 @@ func main() {
// Build OrchestratorInput
input := statemachine.OrchestratorInput{
input := workflow.OrchestratorInput{
TargetRepoPath: *repoPath,
RemoteURL: *remoteURL,
Milestone: *milestone,
DryRun: *dryRun,
MaxCyclesBeforeCAN: 100,
PiProvider: *piProvider,
Config: statemachine.OrchestratorConfig{
Config: workflow.OrchestratorConfig{
SystemPrompt: "You are an expert software developer orchestrating multi-agent work.",
Skills: []statemachine.SkillRef{},
RolePrompts: map[string]statemachine.PromptSpec{
Skills: []workflow.SkillRef{},
RolePrompts: map[string]workflow.PromptSpec{
"planner": {
TemplateRef: "planner/default.tmpl",
Model: statemachine.ModelSpec{
Model: workflow.ModelSpec{
ModelID: *plannerModel,
Thinking: "adaptive",
Effort: "high",
@@ -110,7 +110,7 @@ func main() {
},
"judge": {
TemplateRef: "judge/default.tmpl",
Model: statemachine.ModelSpec{
Model: workflow.ModelSpec{
ModelID: *judgeModel,
Thinking: "adaptive",
Effort: "high",
@@ -118,12 +118,12 @@ func main() {
},
"implementer": {
TemplateRef: "implementer/default.tmpl",
Model: statemachine.ModelSpec{
Model: workflow.ModelSpec{
ModelID: *implementerModel,
},
},
},
Tuning: statemachine.NewActivityTuning(),
Tuning: workflow.NewActivityTuning(),
},
}
@@ -144,7 +144,7 @@ func main() {
run, err := c.ExecuteWorkflow(context.Background(), client.StartWorkflowOptions{
ID: workflowID,
TaskQueue: "poimen-taskqueue",
}, statemachine.OrchestratorWorkflow, input)
}, workflow.OrchestratorWorkflow, input)
if err != nil {
logging.Fatal("failed to start workflow", logging.Err(err))
}
@@ -164,7 +164,7 @@ func main() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
var result statemachine.OrchestratorOutput
var result workflow.OrchestratorOutput
if err := run.Get(ctx, &result); err != nil {
fmt.Printf("\nWorkflow initiated (execution in progress).\n")
fmt.Printf("Check the Web UI for real-time status updates.\n")
@@ -267,12 +267,12 @@ func runRoutingWorkflow(c client.Client, routeMsg, specFile string, isCron, dryR
}
workflowID := "routing-" + spec.Name + "-" + time.Now().Format("20060102-150405")
input := statemachine.RoutingWorkflowInput{Spec: spec}
input := workflow.RoutingWorkflowInput{Spec: spec}
run, err := c.ExecuteWorkflow(ctx, client.StartWorkflowOptions{
ID: workflowID,
TaskQueue: "poimen-taskqueue",
}, statemachine.RoutingWorkflow, input)
}, workflow.RoutingWorkflow, input)
if err != nil {
logging.Fatal("failed to start routing workflow", logging.Err(err))
}
@@ -285,7 +285,7 @@ func runRoutingWorkflow(c client.Client, routeMsg, specFile string, isCron, dryR
waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
var result statemachine.RoutingWorkflowOutput
var result workflow.RoutingWorkflowOutput
if err := run.Get(waitCtx, &result); err != nil {
fmt.Printf("\nWorkflow running (check Temporal UI for status)\n")
} else {
+37 -37
View File
@@ -11,11 +11,11 @@ import (
"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
"github.com/rockliang/poimen/workflows/action"
"github.com/rockliang/poimen/workflows/activity"
"github.com/rockliang/poimen/workflows/internal/config"
"github.com/rockliang/poimen/workflows/internal/health"
"github.com/rockliang/poimen/workflows/internal/logging"
"github.com/rockliang/poimen/workflows/statemachine"
"github.com/rockliang/poimen/workflows/workflow"
)
func main() {
@@ -48,56 +48,56 @@ func main() {
}
// Register all workflows
w.RegisterWorkflow(statemachine.OrchestratorWorkflow)
w.RegisterWorkflow(statemachine.TaskUnitWorkflow)
w.RegisterWorkflow(statemachine.TestWorkflow)
w.RegisterWorkflow(statemachine.RoutingWorkflow)
w.RegisterWorkflow(statemachine.WorkflowGraphQuery)
w.RegisterWorkflow(workflow.OrchestratorWorkflow)
w.RegisterWorkflow(workflow.TaskUnitWorkflow)
w.RegisterWorkflow(workflow.TestWorkflow)
w.RegisterWorkflow(workflow.RoutingWorkflow)
w.RegisterWorkflow(workflow.WorkflowGraphQuery)
// Register all activities
w.RegisterActivity(action.CloneRepoActivity)
w.RegisterActivity(action.GitWorktreeAddActivity)
w.RegisterActivity(action.GitCommitActivity)
w.RegisterActivity(action.GitPushActivity)
w.RegisterActivity(action.GitSquashMergeActivity)
w.RegisterActivity(action.GitDiffActivity)
w.RegisterActivity(action.PrepareSkillsActivity)
w.RegisterActivity(action.PlanningActivity)
w.RegisterActivity(action.ImplementerActivity)
w.RegisterActivity(action.JudgeActivity)
w.RegisterActivity(activity.CloneRepoActivity)
w.RegisterActivity(activity.GitWorktreeAddActivity)
w.RegisterActivity(activity.GitCommitActivity)
w.RegisterActivity(activity.GitPushActivity)
w.RegisterActivity(activity.GitSquashMergeActivity)
w.RegisterActivity(activity.GitDiffActivity)
w.RegisterActivity(activity.PrepareSkillsActivity)
w.RegisterActivity(activity.PlanningActivity)
w.RegisterActivity(activity.ImplementerActivity)
w.RegisterActivity(activity.JudgeActivity)
// Integration and lessons activities - register when fully tested
w.RegisterActivity(action.RunIntegrationTestActivity)
// w.RegisterActivity(action.UpdateLessonsActivity)
// w.RegisterActivity(action.ReadLessonsActivity)
w.RegisterActivity(activity.RunIntegrationTestActivity)
// w.RegisterActivity(activity.UpdateLessonsActivity)
// w.RegisterActivity(activity.ReadLessonsActivity)
// Routing workflow activities
w.RegisterActivity(action.LLMRouterActivity)
w.RegisterActivity(action.ValidateWorkflowSpecActivity)
w.RegisterActivity(action.ValidateCronWorkflowSpecActivity)
w.RegisterActivity(activity.LLMRouterActivity)
w.RegisterActivity(activity.ValidateWorkflowSpecActivity)
w.RegisterActivity(activity.ValidateCronWorkflowSpecActivity)
// Analysis activities
w.RegisterActivity(action.AnalyzeCodeActivity)
w.RegisterActivity(action.SecurityScanActivity)
w.RegisterActivity(action.GenerateReportActivity)
w.RegisterActivity(activity.AnalyzeCodeActivity)
w.RegisterActivity(activity.SecurityScanActivity)
w.RegisterActivity(activity.GenerateReportActivity)
// Notification and utility activities
w.RegisterActivity(action.NotifyStatusActivity)
w.RegisterActivity(action.ArchiveResultsActivity)
w.RegisterActivity(action.DeploymentPreCheckActivity)
w.RegisterActivity(action.ApproveWorkflowActivity)
w.RegisterActivity(activity.NotifyStatusActivity)
w.RegisterActivity(activity.ArchiveResultsActivity)
w.RegisterActivity(activity.DeploymentPreCheckActivity)
w.RegisterActivity(activity.ApproveWorkflowActivity)
// Authentication activities
w.RegisterActivity(action.AssumeRoleActivity)
w.RegisterActivity(activity.AssumeRoleActivity)
// Memory activities
w.RegisterActivity(action.RetrieveMemoryActivity)
w.RegisterActivity(activity.RetrieveMemoryActivity)
// GraphRAG activities
w.RegisterActivity(action.FetchCanvasRelationsActivity)
w.RegisterActivity(action.QueryGraphRAGActivity)
w.RegisterActivity(action.CanvasReasonerActivity)
w.RegisterActivity(action.IndexGraphRAGActivity)
w.RegisterActivity(action.CanvasCompatibilityActivity)
w.RegisterActivity(activity.FetchCanvasRelationsActivity)
w.RegisterActivity(activity.QueryGraphRAGActivity)
w.RegisterActivity(activity.CanvasReasonerActivity)
w.RegisterActivity(activity.IndexGraphRAGActivity)
w.RegisterActivity(activity.CanvasCompatibilityActivity)
// Initialize health checker
healthChecker := health.NewChecker(c)