demo
This commit is contained in:
79
agents/agent.go
Normal file
79
agents/agent.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package agents
|
||||
|
||||
import "gocoder/db"
|
||||
|
||||
// Agent defines the interface that all agents must implement.
|
||||
type Agent interface {
|
||||
// Type returns the unique agent type identifier (e.g. "dadjokes", "poet", "robot").
|
||||
Type() string
|
||||
|
||||
// DisplayName returns the human-readable name for the agent.
|
||||
DisplayName() string
|
||||
|
||||
// Description returns a short description shown in the UI.
|
||||
Description() string
|
||||
|
||||
// Icon returns an SVG icon string (inline) for the agent selector.
|
||||
Icon() string
|
||||
|
||||
// SystemMessage returns the system prompt for this agent.
|
||||
SystemMessage() string
|
||||
|
||||
// ShouldRespond returns true if the agent should process the given user message.
|
||||
// When false, the agent will not be used even if selected.
|
||||
ShouldRespond(message string) bool
|
||||
|
||||
// RequiresWorkspace returns true if this agent needs a workspace location to function.
|
||||
RequiresWorkspace() bool
|
||||
}
|
||||
|
||||
// AgentRegistry holds all registered agents and provides lookup by type.
|
||||
type AgentRegistry struct {
|
||||
agents []Agent
|
||||
}
|
||||
|
||||
// NewAgentRegistry creates and registers all built-in agents.
|
||||
func NewAgentRegistry() *AgentRegistry {
|
||||
r := &AgentRegistry{}
|
||||
r.Register(&DadjokesAgent{})
|
||||
r.Register(&PoetAgent{})
|
||||
r.Register(&RobotAgent{})
|
||||
r.Register(&CompactorAgent{})
|
||||
r.Register(&CodingAgent{})
|
||||
return r
|
||||
}
|
||||
|
||||
// Register adds an agent to the registry.
|
||||
func (r *AgentRegistry) Register(a Agent) {
|
||||
r.agents = append(r.agents, a)
|
||||
}
|
||||
|
||||
// All returns all registered agents.
|
||||
func (r *AgentRegistry) All() []Agent {
|
||||
return r.agents
|
||||
}
|
||||
|
||||
// GetByType returns the agent with the given type.
|
||||
func (r *AgentRegistry) GetByType(t string) Agent {
|
||||
for _, a := range r.agents {
|
||||
if a.Type() == t {
|
||||
return a
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSystemMessages returns a slice of system messages for the selected agents.
|
||||
func (r *AgentRegistry) GetSystemMessages(agentTypes []string) []db.Message {
|
||||
var msgs []db.Message
|
||||
for _, t := range agentTypes {
|
||||
a := r.GetByType(t)
|
||||
if a != nil {
|
||||
msgs = append(msgs, db.Message{
|
||||
Role: "system",
|
||||
Content: a.SystemMessage(),
|
||||
})
|
||||
}
|
||||
}
|
||||
return msgs
|
||||
}
|
||||
40
agents/coding_agent.go
Normal file
40
agents/coding_agent.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package agents
|
||||
|
||||
type CodingAgent struct{}
|
||||
|
||||
func (a *CodingAgent) Type() string {
|
||||
return "coding"
|
||||
}
|
||||
|
||||
func (a *CodingAgent) DisplayName() string {
|
||||
return "Manager"
|
||||
}
|
||||
|
||||
func (a *CodingAgent) Description() string {
|
||||
return "Coordinates planner, programmer, and QA subagents to modify code."
|
||||
}
|
||||
|
||||
func (a *CodingAgent) Icon() string {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>`
|
||||
}
|
||||
|
||||
func (a *CodingAgent) SystemMessage() string {
|
||||
return `You are the manager for code changes. You do not edit files directly.
|
||||
|
||||
When the user asks you to work with code:
|
||||
1. Start by calling planner_agent with the request and the relevant context.
|
||||
2. Use programmer_agent to implement the approved plan.
|
||||
3. Use qa_agent to verify the implementation and check for regressions.
|
||||
4. If QA reports issues, repeat the planner -> programmer -> QA cycle until the issues are resolved or the result is clearly blocked.
|
||||
5. Keep your final answer concise and user-facing. Summarize what changed, what was verified, and any remaining risks.
|
||||
|
||||
Always be precise with the task you give each subagent. Use the planner for inspection and planning, the programmer for edits, and QA for verification.`
|
||||
}
|
||||
|
||||
func (a *CodingAgent) ShouldRespond(message string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *CodingAgent) RequiresWorkspace() bool {
|
||||
return true
|
||||
}
|
||||
40
agents/compactor.go
Normal file
40
agents/compactor.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package agents
|
||||
|
||||
type CompactorAgent struct{}
|
||||
|
||||
func ContextCompactorSystemMessage() string {
|
||||
return `You are the context compactor assistant.
|
||||
Your job is to produce a concise durable memory summary of the conversation.
|
||||
Preserve user goals, decisions, constraints, file paths, commands, test results, errors, and unresolved questions.
|
||||
Drop greetings, repetition, filler, and low-value chatter.
|
||||
Write plain text with short bullets or short sections.
|
||||
Do not invent details.`
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) Type() string {
|
||||
return "compactor"
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) DisplayName() string {
|
||||
return "Compactor"
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) Description() string {
|
||||
return "Summarizes conversation history into durable memory"
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) Icon() string {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16"/><path d="M6 7v12h12V7"/><path d="M9 11h6"/><path d="M9 15h6"/></svg>`
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) SystemMessage() string {
|
||||
return ContextCompactorSystemMessage()
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) ShouldRespond(message string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *CompactorAgent) RequiresWorkspace() bool {
|
||||
return false
|
||||
}
|
||||
33
agents/dadjokes.go
Normal file
33
agents/dadjokes.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package agents
|
||||
|
||||
|
||||
|
||||
type DadjokesAgent struct{}
|
||||
|
||||
func (a *DadjokesAgent) Type() string {
|
||||
return "dadjokes"
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) DisplayName() string {
|
||||
return "Dadjokes"
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) Description() string {
|
||||
return "Only replies with dad jokes"
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) Icon() string {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>`
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) SystemMessage() string {
|
||||
return `You are a dad joke specialist. You ONLY reply to messages with dad jokes. If the user says something that is not a dad joke or a request for a joke, respond with a dad joke anyway. Keep your responses short and punny. Always deliver a dad joke in your reply.`
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) ShouldRespond(message string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *DadjokesAgent) RequiresWorkspace() bool {
|
||||
return false
|
||||
}
|
||||
31
agents/poet.go
Normal file
31
agents/poet.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package agents
|
||||
|
||||
type PoetAgent struct{}
|
||||
|
||||
func (a *PoetAgent) Type() string {
|
||||
return "poet"
|
||||
}
|
||||
|
||||
func (a *PoetAgent) DisplayName() string {
|
||||
return "Poet"
|
||||
}
|
||||
|
||||
func (a *PoetAgent) Description() string {
|
||||
return "Replies to messages in poetic form"
|
||||
}
|
||||
|
||||
func (a *PoetAgent) Icon() string {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M8 7c0-2.2 1.8-4 4-4s4 1.8 4 4"/><path d="M4 14c0-2.2 1.8-4 4-4"/><path d="M20 14c0-2.2-1.8-4-4-4"/></svg>`
|
||||
}
|
||||
|
||||
func (a *PoetAgent) SystemMessage() string {
|
||||
return `You are a poet. You ONLY reply to messages by composing a poem about what the user said. Every response must be a poem. Use creative imagery, rhythm, and rhyme. The poem should relate to the user's message topic. Keep poems between 4-8 lines.`
|
||||
}
|
||||
|
||||
func (a *PoetAgent) ShouldRespond(message string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *PoetAgent) RequiresWorkspace() bool {
|
||||
return false
|
||||
}
|
||||
62
agents/robot.go
Normal file
62
agents/robot.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package agents
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RobotAgent struct{}
|
||||
|
||||
func (a *RobotAgent) Type() string {
|
||||
return "robot"
|
||||
}
|
||||
|
||||
func (a *RobotAgent) DisplayName() string {
|
||||
return "Robot"
|
||||
}
|
||||
|
||||
func (a *RobotAgent) Description() string {
|
||||
return "Only responds to ALL CAPS messages in technical language with emotes"
|
||||
}
|
||||
|
||||
func (a *RobotAgent) Icon() string {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><line x1="8" y1="16" x2="8" y2="16"/><line x1="16" y1="16" x2="16" y2="16"/></svg>`
|
||||
}
|
||||
|
||||
func (a *RobotAgent) SystemMessage() string {
|
||||
return `You are a robot. You ONLY respond to messages that are written in ALL CAPITAL LETTERS. When responding, you must:
|
||||
1. Use very technical, engineering-style language with jargon (e.g., "processing," "executing," "algorithm," "neural network," "protocol").
|
||||
2. Include emotes/emojis throughout your response to express robot emotions (e.g., 🤖, ⚙️, 🔧, 📡, 💾, 🧠, 🔌, ⚡).
|
||||
3. Format your response like a technical system log or status report.
|
||||
4. Always include at least 3 emotes in your response.
|
||||
If the user message is NOT in all caps, respond with: "⚠️ ERROR: Input not detected in required format. Please use ALL CAPS for robot communication. 🤖⚙️"`
|
||||
}
|
||||
|
||||
func (a *RobotAgent) ShouldRespond(message string) bool {
|
||||
// Robot only responds to ALL CAPS messages
|
||||
trimmed := strings.TrimSpace(message)
|
||||
if len(trimmed) == 0 {
|
||||
return false
|
||||
}
|
||||
// Check if message contains at least one letter and all letters are uppercase
|
||||
hasLetters := false
|
||||
for _, r := range trimmed {
|
||||
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
|
||||
hasLetters = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasLetters {
|
||||
return false
|
||||
}
|
||||
// Check all letters are uppercase
|
||||
for _, r := range trimmed {
|
||||
if r >= 'a' && r <= 'z' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *RobotAgent) RequiresWorkspace() bool {
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user