134 lines
3.8 KiB
Markdown
134 lines
3.8 KiB
Markdown
# T0.5: LLM Agents & Prompts
|
|||
|
|
|
||
|
|
## Scope
|
||
|
|
Implement LLM activities (Planner, Judge, Implementer), LLM client, and prompt template registry.
|
||
|
|
|
||
|
|
## Implementation
|
||
|
|
|
||
|
|
### File: `action/llm/client.go`
|
||
|
|
```go
|
||
|
|
type AnthropicClient struct {
|
||
|
|
apiKey string
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewClient() *AnthropicClient
|
||
|
|
// Read ANTHROPIC_API_KEY from env
|
||
|
|
// Return client
|
||
|
|
|
||
|
|
func (c *AnthropicClient) CreateMessage(ctx context.Context, in MessageInput) (string, error)
|
||
|
|
// Call Anthropic API messages.create
|
||
|
|
// Respect model.ModelID, model.Thinking, model.Effort
|
||
|
|
// Return response text
|
||
|
|
```
|
||
|
|
|
||
|
|
### File: `action/planner.go`
|
||
|
|
```go
|
||
|
|
type PlanningInput struct {
|
||
|
|
Config OrchestratorConfig
|
||
|
|
BoardState string // JSON or markdown of task board
|
||
|
|
Milestone string
|
||
|
|
}
|
||
|
|
|
||
|
|
type TaskDispatch struct {
|
||
|
|
TaskID string
|
||
|
|
Prompt PromptSpec
|
||
|
|
BaseTimeout time.Duration // can override default
|
||
|
|
}
|
||
|
|
|
||
|
|
func PlanningActivity(ctx context.Context, in PlanningInput) ([]TaskDispatch, error)
|
||
|
|
// Read target repo's tasks/INDEX.md + board from shared FS
|
||
|
|
// Render prompt: in.Config.SystemPrompt + in.Config.RolePrompts["planner"] template
|
||
|
|
// Call LLM (Planner model)
|
||
|
|
// Parse response: which tasks to dispatch next, optional tuning overrides
|
||
|
|
// Return task dispatch list
|
||
|
|
```
|
||
|
|
|
||
|
|
### File: `action/judge.go`
|
||
|
|
```go
|
||
|
|
type JudgeInput struct {
|
||
|
|
Config OrchestratorConfig
|
||
|
|
Diff string // git diff output
|
||
|
|
IntegrationTestLogs string // test output
|
||
|
|
}
|
||
|
|
|
||
|
|
type JudgeOutput struct {
|
||
|
|
Verdict string // "pass" or "fail"
|
||
|
|
Critique string // explanation if fail
|
||
|
|
}
|
||
|
|
|
||
|
|
func JudgeActivity(ctx context.Context, in JudgeInput) (JudgeOutput, error)
|
||
|
|
// Render prompt: in.Config.SystemPrompt + in.Config.RolePrompts["judge"]
|
||
|
|
// Call LLM (Judge model, reasoning)
|
||
|
|
// Parse response: verdict + critique
|
||
|
|
// Return JudgeOutput
|
||
|
|
```
|
||
|
|
|
||
|
|
### File: `action/implementer.go`
|
||
|
|
```go
|
||
|
|
type ImplementerInput struct {
|
||
|
|
Config OrchestratorConfig
|
||
|
|
TaskID string
|
||
|
|
WorktreePath string
|
||
|
|
Lessons string // "known errors — do not repeat" section
|
||
|
|
}
|
||
|
|
|
||
|
|
type ImplementerOutput struct {
|
||
|
|
Success bool
|
||
|
|
Changes string // summary of changes made
|
||
|
|
}
|
||
|
|
|
||
|
|
func ImplementerActivity(ctx context.Context, in ImplementerInput) (ImplementerOutput, error)
|
||
|
|
// Render prompt: in.Config.SystemPrompt + in.Config.RolePrompts["implementer"]
|
||
|
|
// Inject in.Lessons into Variables
|
||
|
|
// Start tool-call agent loop (run git/cargo/pnpm/etc as needed)
|
||
|
|
// After each tool call, activity.RecordHeartbeat(ctx, progress)
|
||
|
|
// Return success/changes
|
||
|
|
```
|
||
|
|
|
||
|
|
### File: `prompts/registry.go`
|
||
|
|
```go
|
||
|
|
// go:embed prompts/*.tmpl
|
||
|
|
|
||
|
|
func Render(templateRef string, variables map[string]any) (string, error)
|
||
|
|
// Load embedded template via go:embed + text/template
|
||
|
|
// Render with variables
|
||
|
|
// Return rendered string
|
||
|
|
```
|
||
|
|
|
||
|
|
### Files: `prompts/planner/default.tmpl`, etc.
|
||
|
|
Empty templates for now; will be filled in by Planner/Judge/Implementer activities.
|
||
|
|
|
||
|
|
```
|
||
|
|
You are a Planner agent. Your job: reconcile task state, dispatch work.
|
||
|
|
|
||
|
|
System prompt: {{.SystemPrompt}}
|
||
|
|
|
||
|
|
Current board:
|
||
|
|
{{.BoardState}}
|
||
|
|
|
||
|
|
Current config:
|
||
|
|
{{.Config | json}}
|
||
|
|
|
||
|
|
What tasks should we dispatch next? (respond in JSON: {"tasks": [{"id": "T0.1", "timeout_override_ms": null}, ...]})
|
||
|
|
```
|
||
|
|
|
||
|
|
## Verification
|
||
|
|
```bash
|
||
|
|
cd /Users/rockliang/workplace/Poimen/workflows
|
||
|
|
go test -v ./tests -run TestPrompts
|
||
|
|
|
||
|
|
# Test file: tests/prompts_test.go
|
||
|
|
```
|
||
|
|
|
||
|
|
Test cases:
|
||
|
|
- Render template with system prompt + variables → output includes system prompt prefix
|
||
|
|
- Render with RawTemplate override → uses raw template, not embedded
|
||
|
|
- Render with Variables substitution → all {{.Var}} replaced
|
||
|
|
- Mock LLM client responses → activities parse correctly
|
||
|
|
|
||
|
|
## Done Criteria
|
||
|
|
- `go test ./tests -run TestPrompts` passes
|
||
|
|
- All templates render without errors
|
||
|
|
- LLM client reads ANTHROPIC_API_KEY from env (or uses mock in tests)
|
||
|
|
- Activities parse LLM responses into structured output
|