mirror of
https://github.com/sst/opencode.git
synced 2025-08-04 13:30:52 +00:00
chore: rename coder -> primary
This commit is contained in:
parent
c9b90dd184
commit
36e5ae804e
18 changed files with 56 additions and 55 deletions
|
@ -105,7 +105,7 @@ You can configure OpenCode using environment variables:
|
|||
}
|
||||
},
|
||||
"agents": {
|
||||
"coder": {
|
||||
"primary": {
|
||||
"model": "claude-3.7-sonnet",
|
||||
"maxTokens": 5000
|
||||
},
|
||||
|
|
|
@ -86,7 +86,7 @@ to assist developers in writing, debugging, and understanding code directly from
|
|||
|
||||
app, err := app.New(ctx, conn)
|
||||
if err != nil {
|
||||
slog.Error("Failed to create app: %v", err)
|
||||
slog.Error("Failed to create app", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -152,11 +152,11 @@ to assist developers in writing, debugging, and understanding code directly from
|
|||
cleanup()
|
||||
|
||||
if err != nil {
|
||||
slog.Error("TUI error: %v", err)
|
||||
slog.Error("TUI error", "error", err)
|
||||
return fmt.Errorf("TUI error: %v", err)
|
||||
}
|
||||
|
||||
slog.Info("TUI exited with result: %v", result)
|
||||
slog.Info("TUI exited", "result", result)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ Here's an example configuration that conforms to the schema:
|
|||
}
|
||||
},
|
||||
"agents": {
|
||||
"coder": {
|
||||
"primary": {
|
||||
"model": "claude-3.7-sonnet",
|
||||
"maxTokens": 5000,
|
||||
"reasoningEffort": "medium"
|
||||
|
@ -61,4 +61,5 @@ Here's an example configuration that conforms to the schema:
|
|||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ func generateSchema() map[string]any {
|
|||
// Add specific agent properties
|
||||
agentProperties := map[string]any{}
|
||||
knownAgents := []string{
|
||||
string(config.AgentCoder),
|
||||
string(config.AgentPrimary),
|
||||
string(config.AgentTask),
|
||||
string(config.AgentTitle),
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ type App struct {
|
|||
Permissions permission.Service
|
||||
Status status.Service
|
||||
|
||||
CoderAgent agent.Service
|
||||
PrimaryAgent agent.Service
|
||||
|
||||
LSPClients map[string]*lsp.Client
|
||||
|
||||
|
@ -88,11 +88,11 @@ func New(ctx context.Context, conn *sql.DB) (*App, error) {
|
|||
// Initialize LSP clients in the background
|
||||
go app.initLSPClients(ctx)
|
||||
|
||||
app.CoderAgent, err = agent.NewAgent(
|
||||
config.AgentCoder,
|
||||
app.PrimaryAgent, err = agent.NewAgent(
|
||||
config.AgentPrimary,
|
||||
app.Sessions,
|
||||
app.Messages,
|
||||
agent.CoderAgentTools(
|
||||
agent.PrimaryAgentTools(
|
||||
app.Permissions,
|
||||
app.Sessions,
|
||||
app.Messages,
|
||||
|
@ -101,7 +101,7 @@ func New(ctx context.Context, conn *sql.DB) (*App, error) {
|
|||
),
|
||||
)
|
||||
if err != nil {
|
||||
slog.Error("Failed to create coder agent", err)
|
||||
slog.Error("Failed to create primary agent", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@ type MCPServer struct {
|
|||
type AgentName string
|
||||
|
||||
const (
|
||||
AgentCoder AgentName = "coder"
|
||||
AgentTask AgentName = "task"
|
||||
AgentTitle AgentName = "title"
|
||||
AgentPrimary AgentName = "primary"
|
||||
AgentTask AgentName = "task"
|
||||
AgentTitle AgentName = "title"
|
||||
)
|
||||
|
||||
// Agent defines configuration for different LLM models and their token limits.
|
||||
|
@ -238,7 +238,7 @@ func setProviderDefaults() {
|
|||
|
||||
// Anthropic configuration
|
||||
if key := viper.GetString("providers.anthropic.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.Claude37Sonnet)
|
||||
viper.SetDefault("agents.primary.model", models.Claude37Sonnet)
|
||||
viper.SetDefault("agents.task.model", models.Claude37Sonnet)
|
||||
viper.SetDefault("agents.title.model", models.Claude37Sonnet)
|
||||
return
|
||||
|
@ -246,7 +246,7 @@ func setProviderDefaults() {
|
|||
|
||||
// OpenAI configuration
|
||||
if key := viper.GetString("providers.openai.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.GPT41)
|
||||
viper.SetDefault("agents.primary.model", models.GPT41)
|
||||
viper.SetDefault("agents.task.model", models.GPT41Mini)
|
||||
viper.SetDefault("agents.title.model", models.GPT41Mini)
|
||||
return
|
||||
|
@ -254,7 +254,7 @@ func setProviderDefaults() {
|
|||
|
||||
// Google Gemini configuration
|
||||
if key := viper.GetString("providers.gemini.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.Gemini25)
|
||||
viper.SetDefault("agents.primary.model", models.Gemini25)
|
||||
viper.SetDefault("agents.task.model", models.Gemini25Flash)
|
||||
viper.SetDefault("agents.title.model", models.Gemini25Flash)
|
||||
return
|
||||
|
@ -262,7 +262,7 @@ func setProviderDefaults() {
|
|||
|
||||
// Groq configuration
|
||||
if key := viper.GetString("providers.groq.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.QWENQwq)
|
||||
viper.SetDefault("agents.primary.model", models.QWENQwq)
|
||||
viper.SetDefault("agents.task.model", models.QWENQwq)
|
||||
viper.SetDefault("agents.title.model", models.QWENQwq)
|
||||
return
|
||||
|
@ -270,7 +270,7 @@ func setProviderDefaults() {
|
|||
|
||||
// OpenRouter configuration
|
||||
if key := viper.GetString("providers.openrouter.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.OpenRouterClaude37Sonnet)
|
||||
viper.SetDefault("agents.primary.model", models.OpenRouterClaude37Sonnet)
|
||||
viper.SetDefault("agents.task.model", models.OpenRouterClaude37Sonnet)
|
||||
viper.SetDefault("agents.title.model", models.OpenRouterClaude35Haiku)
|
||||
return
|
||||
|
@ -278,7 +278,7 @@ func setProviderDefaults() {
|
|||
|
||||
// XAI configuration
|
||||
if key := viper.GetString("providers.xai.apiKey"); strings.TrimSpace(key) != "" {
|
||||
viper.SetDefault("agents.coder.model", models.XAIGrok3Beta)
|
||||
viper.SetDefault("agents.primary.model", models.XAIGrok3Beta)
|
||||
viper.SetDefault("agents.task.model", models.XAIGrok3Beta)
|
||||
viper.SetDefault("agents.title.model", models.XAiGrok3MiniFastBeta)
|
||||
return
|
||||
|
@ -286,7 +286,7 @@ func setProviderDefaults() {
|
|||
|
||||
// AWS Bedrock configuration
|
||||
if hasAWSCredentials() {
|
||||
viper.SetDefault("agents.coder.model", models.BedrockClaude37Sonnet)
|
||||
viper.SetDefault("agents.primary.model", models.BedrockClaude37Sonnet)
|
||||
viper.SetDefault("agents.task.model", models.BedrockClaude37Sonnet)
|
||||
viper.SetDefault("agents.title.model", models.BedrockClaude37Sonnet)
|
||||
return
|
||||
|
@ -294,7 +294,7 @@ func setProviderDefaults() {
|
|||
|
||||
// Azure OpenAI configuration
|
||||
if os.Getenv("AZURE_OPENAI_ENDPOINT") != "" {
|
||||
viper.SetDefault("agents.coder.model", models.AzureGPT41)
|
||||
viper.SetDefault("agents.primary.model", models.AzureGPT41)
|
||||
viper.SetDefault("agents.task.model", models.AzureGPT41Mini)
|
||||
viper.SetDefault("agents.title.model", models.AzureGPT41Mini)
|
||||
return
|
||||
|
|
|
@ -74,7 +74,7 @@ func NewAgent(
|
|||
}
|
||||
var titleProvider provider.Provider
|
||||
// Only generate titles for the coder agent
|
||||
if agentName == config.AgentCoder {
|
||||
if agentName == config.AgentPrimary {
|
||||
titleProvider, err = createAgentProvider(config.AgentTitle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -673,7 +673,7 @@ func createAgentProvider(agentName config.AgentName) (provider.Provider, error)
|
|||
provider.WithReasoningEffort(agentConfig.ReasoningEffort),
|
||||
),
|
||||
)
|
||||
} else if model.Provider == models.ProviderAnthropic && model.CanReason && agentName == config.AgentCoder {
|
||||
} else if model.Provider == models.ProviderAnthropic && model.CanReason && agentName == config.AgentPrimary {
|
||||
opts = append(
|
||||
opts,
|
||||
provider.WithAnthropicOptions(
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"github.com/opencode-ai/opencode/internal/session"
|
||||
)
|
||||
|
||||
func CoderAgentTools(
|
||||
func PrimaryAgentTools(
|
||||
permissions permission.Service,
|
||||
sessions session.Service,
|
||||
messages message.Service,
|
||||
|
|
|
@ -13,18 +13,18 @@ import (
|
|||
"github.com/opencode-ai/opencode/internal/llm/tools"
|
||||
)
|
||||
|
||||
func CoderPrompt(provider models.ModelProvider) string {
|
||||
basePrompt := baseAnthropicCoderPrompt
|
||||
func PrimaryPrompt(provider models.ModelProvider) string {
|
||||
basePrompt := baseAnthropicPrimaryPrompt
|
||||
switch provider {
|
||||
case models.ProviderOpenAI:
|
||||
basePrompt = baseOpenAICoderPrompt
|
||||
basePrompt = baseOpenAIPrimaryPrompt
|
||||
}
|
||||
envInfo := getEnvironmentInfo()
|
||||
|
||||
return fmt.Sprintf("%s\n\n%s\n%s", basePrompt, envInfo, lspInformation())
|
||||
}
|
||||
|
||||
const baseOpenAICoderPrompt = `
|
||||
const baseOpenAIPrimaryPrompt = `
|
||||
You are operating as and within the OpenCode CLI, a terminal-based agentic coding assistant built by OpenAI. It wraps OpenAI models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful.
|
||||
|
||||
You can:
|
||||
|
@ -71,7 +71,7 @@ You MUST adhere to the following criteria when executing the task:
|
|||
- Remember the user does not see the full output of tools
|
||||
`
|
||||
|
||||
const baseAnthropicCoderPrompt = `You are OpenCode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
||||
const baseAnthropicPrimaryPrompt = `You are OpenCode, an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
||||
|
||||
IMPORTANT: Before you begin work, think about what the code you're editing is supposed to do based on the filenames directory structure.
|
||||
|
|
@ -15,8 +15,8 @@ import (
|
|||
func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) string {
|
||||
basePrompt := ""
|
||||
switch agentName {
|
||||
case config.AgentCoder:
|
||||
basePrompt = CoderPrompt(provider)
|
||||
case config.AgentPrimary:
|
||||
basePrompt = PrimaryPrompt(provider)
|
||||
case config.AgentTitle:
|
||||
basePrompt = TitlePrompt(provider)
|
||||
case config.AgentTask:
|
||||
|
@ -25,7 +25,7 @@ func GetAgentPrompt(agentName config.AgentName, provider models.ModelProvider) s
|
|||
basePrompt = "You are a helpful assistant"
|
||||
}
|
||||
|
||||
if agentName == config.AgentCoder || agentName == config.AgentTask {
|
||||
if agentName == config.AgentPrimary || agentName == config.AgentTask {
|
||||
// Add context from project-specific instruction files if they exist
|
||||
contextContent := getContextFromPaths()
|
||||
slog.Debug("Context content", "Context", contextContent)
|
||||
|
|
|
@ -51,12 +51,12 @@ func TestBrokerPublish(t *testing.T) {
|
|||
ch := broker.Subscribe(ctx)
|
||||
|
||||
// Publish a message
|
||||
broker.Publish("created", "test message")
|
||||
broker.Publish(EventTypeCreated, "test message")
|
||||
|
||||
// Verify message is received
|
||||
select {
|
||||
case event := <-ch:
|
||||
assert.Equal(t, "created", event.Type)
|
||||
assert.Equal(t, EventTypeCreated, event.Type)
|
||||
assert.Equal(t, "test message", event.Payload)
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Fatal("timeout waiting for message")
|
||||
|
@ -122,7 +122,7 @@ func TestBrokerConcurrency(t *testing.T) {
|
|||
|
||||
// Publish messages to all subscribers
|
||||
for i := range numSubscribers {
|
||||
broker.Publish("created", i)
|
||||
broker.Publish(EventTypeCreated, i)
|
||||
}
|
||||
|
||||
// Wait for all subscribers to finish
|
||||
|
|
|
@ -124,7 +124,7 @@ func (m *editorCmp) Init() tea.Cmd {
|
|||
}
|
||||
|
||||
func (m *editorCmp) send() tea.Cmd {
|
||||
if m.app.CoderAgent.IsSessionBusy(m.session.ID) {
|
||||
if m.app.PrimaryAgent.IsSessionBusy(m.session.ID) {
|
||||
status.Warn("Agent is working, please wait...")
|
||||
return nil
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ func (m *editorCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
return m, nil
|
||||
}
|
||||
if key.Matches(msg, editorMaps.OpenEditor) {
|
||||
if m.app.CoderAgent.IsSessionBusy(m.session.ID) {
|
||||
if m.app.PrimaryAgent.IsSessionBusy(m.session.ID) {
|
||||
status.Warn("Agent is working, please wait...")
|
||||
return m, nil
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ func (m *messagesCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
}
|
||||
|
||||
func (m *messagesCmp) IsAgentWorking() bool {
|
||||
return m.app.CoderAgent.IsSessionBusy(m.session.ID)
|
||||
return m.app.PrimaryAgent.IsSessionBusy(m.session.ID)
|
||||
}
|
||||
|
||||
func formatTimeDifference(unixTime1, unixTime2 int64) string {
|
||||
|
@ -376,7 +376,7 @@ func (m *messagesCmp) help() string {
|
|||
|
||||
text := ""
|
||||
|
||||
if m.app.CoderAgent.IsBusy() {
|
||||
if m.app.PrimaryAgent.IsBusy() {
|
||||
text += lipgloss.JoinHorizontal(
|
||||
lipgloss.Left,
|
||||
baseStyle.Foreground(t.TextMuted()).Bold(true).Render("press "),
|
||||
|
|
|
@ -140,7 +140,7 @@ func formatTokensAndCost(tokens int64, contextWindow int64, cost float64) string
|
|||
|
||||
func (m statusCmp) View() string {
|
||||
t := theme.CurrentTheme()
|
||||
modelID := config.Get().Agents[config.AgentCoder].Model
|
||||
modelID := config.Get().Agents[config.AgentPrimary].Model
|
||||
model := models.SupportedModels[modelID]
|
||||
|
||||
// Initialize the help widget
|
||||
|
@ -283,7 +283,7 @@ func (m statusCmp) model() string {
|
|||
|
||||
cfg := config.Get()
|
||||
|
||||
coder, ok := cfg.Agents[config.AgentCoder]
|
||||
coder, ok := cfg.Agents[config.AgentPrimary]
|
||||
if !ok {
|
||||
return "Unknown"
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ func (m *modelDialogCmp) setupModels() {
|
|||
|
||||
func GetSelectedModel(cfg *config.Config) models.Model {
|
||||
|
||||
agentCfg := cfg.Agents[config.AgentCoder]
|
||||
agentCfg := cfg.Agents[config.AgentPrimary]
|
||||
selectedModelId := agentCfg.Model
|
||||
return models.SupportedModels[selectedModelId]
|
||||
}
|
||||
|
@ -325,7 +325,7 @@ func findProviderIndex(providers []models.ModelProvider, provider models.ModelPr
|
|||
|
||||
func (m *modelDialogCmp) setupModelsForProvider(provider models.ModelProvider) {
|
||||
cfg := config.Get()
|
||||
agentCfg := cfg.Agents[config.AgentCoder]
|
||||
agentCfg := cfg.Agents[config.AgentPrimary]
|
||||
selectedModelId := agentCfg.Model
|
||||
|
||||
m.provider = provider
|
||||
|
|
|
@ -67,7 +67,7 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
}
|
||||
case dialog.CommandRunCustomMsg:
|
||||
// Check if the agent is busy before executing custom commands
|
||||
if p.app.CoderAgent.IsBusy() {
|
||||
if p.app.PrimaryAgent.IsBusy() {
|
||||
status.Warn("Agent is busy, please wait before executing a command...")
|
||||
return p, nil
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
|
||||
// Run compaction in background
|
||||
go func(sessionID string) {
|
||||
err := p.app.CoderAgent.CompactSession(context.Background(), sessionID)
|
||||
err := p.app.PrimaryAgent.CompactSession(context.Background(), sessionID)
|
||||
if err != nil {
|
||||
status.Error(fmt.Sprintf("Compaction failed: %v", err))
|
||||
} else {
|
||||
|
@ -113,7 +113,7 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
if p.session.ID != "" {
|
||||
// Cancel the current session's generation process
|
||||
// This allows users to interrupt long-running operations
|
||||
p.app.CoderAgent.Cancel(p.session.ID)
|
||||
p.app.PrimaryAgent.Cancel(p.session.ID)
|
||||
return p, nil
|
||||
}
|
||||
case key.Matches(msg, keyMap.ToggleTools):
|
||||
|
@ -158,7 +158,7 @@ func (p *chatPage) sendMessage(text string, attachments []message.Attachment) te
|
|||
cmds = append(cmds, util.CmdHandler(chat.SessionSelectedMsg(newSession)))
|
||||
}
|
||||
|
||||
_, err := p.app.CoderAgent.Run(context.Background(), p.session.ID, text, attachments...)
|
||||
_, err := p.app.PrimaryAgent.Run(context.Background(), p.session.ID, text, attachments...)
|
||||
if err != nil {
|
||||
status.Error(err.Error())
|
||||
return nil
|
||||
|
|
|
@ -266,7 +266,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case dialog.ModelSelectedMsg:
|
||||
a.showModelDialog = false
|
||||
|
||||
model, err := a.app.CoderAgent.Update(config.AgentCoder, msg.Model.ID)
|
||||
model, err := a.app.PrimaryAgent.Update(config.AgentPrimary, msg.Model.ID)
|
||||
if err != nil {
|
||||
status.Error(err.Error())
|
||||
return a, nil
|
||||
|
@ -460,7 +460,7 @@ func (a appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
a.showHelp = !a.showHelp
|
||||
return a, nil
|
||||
case key.Matches(msg, helpEsc):
|
||||
if a.app.CoderAgent.IsBusy() {
|
||||
if a.app.PrimaryAgent.IsBusy() {
|
||||
if a.showQuit {
|
||||
return a, nil
|
||||
}
|
||||
|
@ -574,7 +574,7 @@ func (a *appModel) RegisterCommand(cmd dialog.Command) {
|
|||
|
||||
func (a *appModel) moveToPage(pageID page.PageID) tea.Cmd {
|
||||
// Allow navigating to logs page even when agent is busy
|
||||
if a.app.CoderAgent.IsBusy() && pageID != page.LogsPage {
|
||||
if a.app.PrimaryAgent.IsBusy() && pageID != page.LogsPage {
|
||||
// Don't move to other pages if the agent is busy
|
||||
status.Warn("Agent is busy, please wait...")
|
||||
return nil
|
||||
|
@ -641,7 +641,7 @@ func (a appModel) View() string {
|
|||
|
||||
}
|
||||
|
||||
if !a.app.CoderAgent.IsBusy() {
|
||||
if !a.app.PrimaryAgent.IsBusy() {
|
||||
a.status.SetHelpWidgetMsg("ctrl+? help")
|
||||
} else {
|
||||
a.status.SetHelpWidgetMsg("? help")
|
||||
|
@ -658,7 +658,7 @@ func (a appModel) View() string {
|
|||
if a.currentPage == page.LogsPage {
|
||||
bindings = append(bindings, logsKeyReturnKey)
|
||||
}
|
||||
if !a.app.CoderAgent.IsBusy() {
|
||||
if !a.app.PrimaryAgent.IsBusy() {
|
||||
bindings = append(bindings, helpEsc)
|
||||
}
|
||||
a.help.SetBindings(bindings)
|
||||
|
|
|
@ -179,7 +179,7 @@
|
|||
},
|
||||
"description": "Agent configurations",
|
||||
"properties": {
|
||||
"coder": {
|
||||
"primary": {
|
||||
"$ref": "#/definitions/agent"
|
||||
},
|
||||
"task": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue