Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions go-opencode/cmd/opencode/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"strings"

"github.com/opencode-ai/opencode/internal/agent"
"github.com/opencode-ai/opencode/internal/config"
"github.com/opencode-ai/opencode/internal/mcp"
"github.com/opencode-ai/opencode/internal/permission"
Expand Down Expand Up @@ -99,6 +100,10 @@ func runInteractive(cmd *cobra.Command, args []string) error {
// Initialize tool registry
toolReg := tool.DefaultRegistry(workDir, store)

// Initialize agent registry and task tool
agentReg := agent.NewRegistry()
toolReg.RegisterTaskTool(agentReg)

// Initialize MCP client and servers from config
var mcpClient *mcp.Client
if appConfig.MCP != nil && len(appConfig.MCP) > 0 {
Expand Down Expand Up @@ -192,6 +197,19 @@ func runInteractive(cmd *cobra.Command, args []string) error {
}
}

// Create and configure SubagentExecutor for task tool
subagentExecutor := tool.NewSubagentExecutor(tool.SubagentExecutorConfig{
Storage: store,
ProviderRegistry: providerReg,
ToolRegistry: toolReg,
PermissionChecker: permChecker,
AgentRegistry: agentReg,
WorkDir: workDir,
DefaultProviderID: defaultProviderID,
DefaultModelID: defaultModelID,
})
toolReg.SetTaskExecutor(subagentExecutor)

// Create processor
processor := session.NewProcessor(providerReg, toolReg, store, permChecker, defaultProviderID, defaultModelID)

Expand Down
36 changes: 36 additions & 0 deletions go-opencode/cmd/opencode/commands/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"

"github.com/opencode-ai/opencode/internal/agent"
"github.com/opencode-ai/opencode/internal/config"
"github.com/opencode-ai/opencode/internal/logging"
"github.com/opencode-ai/opencode/internal/mcp"
Expand Down Expand Up @@ -85,6 +87,40 @@ func runServe(cmd *cobra.Command, args []string) error {
// Initialize tool registry
toolReg := tool.DefaultRegistry(workDir, store)

// Initialize agent registry
agentReg := agent.NewRegistry()
logging.Info().
Int("agentCount", agentReg.Count()).
Strs("agents", agentReg.Names()).
Msg("Agent registry initialized")

// Register task tool with agent registry
toolReg.RegisterTaskTool(agentReg)

// Parse default provider and model from config
var defaultProviderID, defaultModelID string
if appConfig != nil && appConfig.Model != "" {
parts := strings.SplitN(appConfig.Model, "/", 2)
if len(parts) == 2 {
defaultProviderID = parts[0]
defaultModelID = parts[1]
}
}

// Create and configure SubagentExecutor for task tool
subagentExecutor := tool.NewSubagentExecutor(tool.SubagentExecutorConfig{
Storage: store,
ProviderRegistry: providerReg,
ToolRegistry: toolReg,
PermissionChecker: nil, // No permission checker for subagents
AgentRegistry: agentReg,
WorkDir: workDir,
DefaultProviderID: defaultProviderID,
DefaultModelID: defaultModelID,
})
toolReg.SetTaskExecutor(subagentExecutor)
logging.Info().Msg("Subagent executor configured for task tool")

// Configure server
serverConfig := server.DefaultConfig()
serverConfig.Port = servePort
Expand Down
122 changes: 83 additions & 39 deletions go-opencode/internal/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,26 @@ func matchWildcard(pattern, s string) bool {
return pattern == s
}

// ExploreAgentPrompt is the system prompt for the explore agent.
const ExploreAgentPrompt = `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.

Your strengths:
- Rapidly finding files using glob patterns
- Searching code and text with powerful regex patterns
- Reading and analyzing file contents

Guidelines:
- Use Glob for broad file pattern matching
- Use Grep for searching file contents with regex
- Use Read when you know the specific file path you need to read
- Use Bash for file operations like copying, moving, or listing directory contents
- Adapt your search approach based on the thoroughness level specified by the caller
- Return file paths as absolute paths in your final response
- For clear communication, avoid using emojis
- Do not create any files, or run bash commands that modify the user's system state in any way

Complete the user's search request efficiently and report your findings clearly.`

// BuiltInAgents returns the default agent configurations.
func BuiltInAgents() map[string]*Agent {
return map[string]*Agent{
Expand Down Expand Up @@ -230,70 +250,94 @@ func BuiltInAgents() map[string]*Agent {
Permission: AgentPermission{
Edit: permission.ActionDeny,
Bash: map[string]permission.PermissionAction{
"grep*": permission.ActionAllow,
"find*": permission.ActionAllow,
"ls*": permission.ActionAllow,
"cat*": permission.ActionAllow,
"git status": permission.ActionAllow,
"git diff*": permission.ActionAllow,
"git log*": permission.ActionAllow,
"*": permission.ActionDeny,
"cut*": permission.ActionAllow,
"diff*": permission.ActionAllow,
"du*": permission.ActionAllow,
"file *": permission.ActionAllow,
"find * -delete*": permission.ActionAsk,
"find * -exec*": permission.ActionAsk,
"find * -fprint*": permission.ActionAsk,
"find * -fls*": permission.ActionAsk,
"find * -fprintf*": permission.ActionAsk,
"find * -ok*": permission.ActionAsk,
"find *": permission.ActionAllow,
"git diff*": permission.ActionAllow,
"git log*": permission.ActionAllow,
"git show*": permission.ActionAllow,
"git status*": permission.ActionAllow,
"git branch": permission.ActionAllow,
"git branch -v": permission.ActionAllow,
"grep*": permission.ActionAllow,
"head*": permission.ActionAllow,
"less*": permission.ActionAllow,
"ls*": permission.ActionAllow,
"more*": permission.ActionAllow,
"pwd*": permission.ActionAllow,
"rg*": permission.ActionAllow,
"sort --output=*": permission.ActionAsk,
"sort -o *": permission.ActionAsk,
"sort*": permission.ActionAllow,
"stat*": permission.ActionAllow,
"tail*": permission.ActionAllow,
"tree -o *": permission.ActionAsk,
"tree*": permission.ActionAllow,
"uniq*": permission.ActionAllow,
"wc*": permission.ActionAllow,
"whereis*": permission.ActionAllow,
"which*": permission.ActionAllow,
"*": permission.ActionAsk,
},
WebFetch: permission.ActionAllow,
ExternalDir: permission.ActionDeny,
DoomLoop: permission.ActionDeny,
},
Tools: map[string]bool{
"read": true,
"glob": true,
"grep": true,
"ls": true,
"bash": true,
"edit": false,
"write": false,
"*": true,
"edit": false,
"write": false,
"todoread": false,
"todowrite": false,
},
},
"general": {
Name: "general",
Description: "General-purpose subagent for searches and exploration",
Description: "General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel.",
Mode: ModeSubagent,
BuiltIn: true,
Permission: AgentPermission{
Edit: permission.ActionDeny,
Bash: map[string]permission.PermissionAction{"*": permission.ActionDeny},
Edit: permission.ActionAllow,
Bash: map[string]permission.PermissionAction{"*": permission.ActionAllow},
WebFetch: permission.ActionAllow,
ExternalDir: permission.ActionDeny,
DoomLoop: permission.ActionDeny,
ExternalDir: permission.ActionAsk,
DoomLoop: permission.ActionAsk,
},
Tools: map[string]bool{
"read": true,
"glob": true,
"grep": true,
"webfetch": true,
"bash": false,
"edit": false,
"write": false,
"*": true,
"todoread": false,
"todowrite": false,
"task": false, // Prevent recursive task calls
},
},
"explore": {
Name: "explore",
Description: "Fast agent specialized for codebase exploration",
Description: `Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.`,
Mode: ModeSubagent,
BuiltIn: true,
Prompt: ExploreAgentPrompt,
Permission: AgentPermission{
Edit: permission.ActionDeny,
Bash: map[string]permission.PermissionAction{"*": permission.ActionDeny},
WebFetch: permission.ActionDeny,
ExternalDir: permission.ActionDeny,
DoomLoop: permission.ActionDeny,
Edit: permission.ActionAllow,
Bash: map[string]permission.PermissionAction{"*": permission.ActionAllow},
WebFetch: permission.ActionAllow,
ExternalDir: permission.ActionAsk,
DoomLoop: permission.ActionAsk,
},
Tools: map[string]bool{
"read": true,
"glob": true,
"grep": true,
"ls": true,
"bash": false,
"edit": false,
"*": true,
"todoread": false,
"todowrite": false,
"edit": false,
"write": false,
"task": false, // Prevent recursive task calls
},
},
}
Expand Down
Loading
Loading